From df902c5c429a3f2b06553b69eb9796011c77026d Mon Sep 17 00:00:00 2001 From: stemgene Date: Thu, 21 Nov 2024 15:18:17 -0500 Subject: [PATCH 01/26] Refactor Home.calculate Co-authored-by: Ethan Strominger --- python/src/rules_engine/engine.py | 26 ++++++++++++++----- python/tests/test_rules_engine/test_engine.py | 8 ++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 3ad2514..1c1b1e8 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -97,13 +97,12 @@ def get_outputs_normalized( fuel_type=summary_input.fuel_type, ) - home = Home( + home = Home.calculate( summary_input=summary_input, billing_periods=intermediate_billing_periods, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) - home.calculate() average_indoor_temperature = get_average_indoor_temperature( thermostat_set_point=summary_input.thermostat_set_point, @@ -399,7 +398,7 @@ class Home: standard deviation of the UA values across them. """ - def __init__( + def _init( self, summary_input: SummaryInput, billing_periods: list[ProcessedBill], @@ -413,6 +412,7 @@ def __init__( self.dhw_input = dhw_input self._initialize_billing_periods(billing_periods) + def _initialize_billing_periods(self, billing_periods: list[ProcessedBill]) -> None: self.bills_winter = [] self.bills_summer = [] @@ -621,8 +621,13 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: if len(directions_to_check) == 2: directions_to_check.pop(-1) + @classmethod def calculate( - self, + cls, + summary_input: SummaryInput, + billing_periods: list[ProcessedBill], + dhw_input: Optional[DhwInput], + initial_balance_point: float = 60, initial_balance_point_sensitivity: float = 0.5, stdev_pct_max: float = 0.10, max_stdev_pct_diff: float = 0.01, @@ -633,14 +638,23 @@ def calculate( and UA coefficient for the home, removing UA outliers based on a normalized standard deviation threshold. """ - self._calculate_avg_non_heating_usage() - self._calculate_balance_point_and_ua( + home_instance = object.__new__(cls) + home_instance._init( + summary_input = summary_input, + billing_periods = billing_periods, + dhw_input = dhw_input, + initial_balance_point = initial_balance_point, + ) + home_instance._calculate_avg_non_heating_usage() + home_instance._calculate_balance_point_and_ua( initial_balance_point_sensitivity, stdev_pct_max, max_stdev_pct_diff, next_balance_point_sensitivity, ) + return home_instance + def initialize_ua(self, billing_period: ProcessedBill) -> None: """ Average heating usage, partial UA, initial UA. requires that diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index ca63f74..0d751a1 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -313,15 +313,13 @@ def test_get_average_indoor_temperature(): def test_bp_ua_estimates(sample_summary_inputs, sample_billing_periods): - home = engine.Home( + home = engine.Home.calculate( sample_summary_inputs, sample_billing_periods, dhw_input=None, initial_balance_point=58, ) - home.calculate() - ua_1, ua_2, ua_3 = [bill.ua for bill in home.bills_winter] assert home.balance_point == 60.5 @@ -333,15 +331,13 @@ def test_bp_ua_estimates(sample_summary_inputs, sample_billing_periods): def test_bp_ua_with_outlier(sample_summary_inputs, sample_billing_periods_with_outlier): - home = engine.Home( + home = engine.Home.calculate( sample_summary_inputs, sample_billing_periods_with_outlier, dhw_input=None, initial_balance_point=58, ) - home.calculate() - # expect that ua_1 is considered an outlier and not used in bills_winter ua_2, ua_3, ua_4 = [bill.ua for bill in home.bills_winter] From 8422c687f79f04225bfe2a6b3de21251a8d15422 Mon Sep 17 00:00:00 2001 From: stemgene Date: Mon, 25 Nov 2024 15:19:57 -0500 Subject: [PATCH 02/26] Refactor "SummaryInput" to "HeatLoadInput", "summary_input" to "heat_load_input" Co-authored-by: Ethan Strominger --- heat-stack/app/routes/_heat+/single.tsx | 14 +++---- heat-stack/app/utils/pyodide.test.ts | 12 +++--- heat-stack/app/utils/pyodide.util.js | 10 ++--- python/src/rules_engine/engine.py | 40 +++++++++---------- python/src/rules_engine/pydantic_models.py | 2 +- python/src/rules_engine/refactor.md | 2 +- python/tests/test_rules_engine/test_engine.py | 8 ++-- python/tests/test_rules_engine/test_utils.py | 4 +- 8 files changed, 46 insertions(+), 46 deletions(-) diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index 4b3a4c4..b21d53e 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -227,7 +227,7 @@ export async function action({ request, params }: ActionFunctionArgs) { from rules_engine import parser from rules_engine.pydantic_models import ( FuelType, - SummaryInput, + HeatLoadInput, TemperatureInput ) from rules_engine import engine @@ -302,7 +302,7 @@ export async function action({ request, params }: ActionFunctionArgs) { from rules_engine import parser from rules_engine.pydantic_models import ( FuelType, - SummaryInput, + HeatLoadInput, TemperatureInput ) from rules_engine import engine, helpers @@ -313,7 +313,7 @@ export async function action({ request, params }: ActionFunctionArgs) { # two new geocode parameters may be needed for design temp: # watch out for helpers.get_design_temp( addressMatches[0].geographies.counties[0]['STATE'] , addressMatches[0].geographies.counties[0]['COUNTY'] county_id) # in addition to latitude and longitude from GeocodeUtil.ts object . - # pack the get_design_temp output into summary_input + # pack the get_design_temp output into heat_load_input """ summaryInputFromJs = summaryInputJs.as_object_map().values()._mapping @@ -323,7 +323,7 @@ export async function action({ request, params }: ActionFunctionArgs) { naturalGasInputRecords = parser.parse_gas_bill(csvDataJs, parser.NaturalGasCompany.NATIONAL_GRID) design_temp_looked_up = helpers.get_design_temp(state_id, county_id) - summaryInput = SummaryInput( **summaryInputFromJs, design_temperature=design_temp_looked_up) + summaryInput = HeatLoadInput( **summaryInputFromJs, design_temperature=design_temp_looked_up) temperatureInput = TemperatureInput(**temperatureInputFromJs) @@ -344,14 +344,14 @@ export async function action({ request, params }: ActionFunctionArgs) { from rules_engine import parser from rules_engine.pydantic_models import ( FuelType, - SummaryInput, + HeatLoadInput, TemperatureInput, NormalizedBillingPeriodRecordBase ) from rules_engine import engine, helpers # def get_outputs_normalized( - # summary_input: SummaryInput, + # heat_load_input: HeatLoadInput, # dhw_input: Optional[DhwInput], # temperature_input: TemperatureInput, # billing_periods: list[NormalizedBillingPeriodRecordBase], @@ -367,7 +367,7 @@ export async function action({ request, params }: ActionFunctionArgs) { design_temp_looked_up = helpers.get_design_temp(state_id, county_id) # expect 1 for middlesex county: print("design temp check ",design_temp_looked_up, state_id, county_id) - summaryInput = SummaryInput( **summaryInputFromJs, design_temperature=design_temp_looked_up) + summaryInput = HeatLoadInput( **summaryInputFromJs, design_temperature=design_temp_looked_up) temperatureInput = TemperatureInput(**temperatureInputFromJs) diff --git a/heat-stack/app/utils/pyodide.test.ts b/heat-stack/app/utils/pyodide.test.ts index 04c9e18..0ce82ae 100644 --- a/heat-stack/app/utils/pyodide.test.ts +++ b/heat-stack/app/utils/pyodide.test.ts @@ -142,7 +142,7 @@ test('pyodide solves climate change', async () => { // https://github.com/codeforboston/home-energy-analysis-tool/blob/main/python/src/rules_engine/parser.py#L60 /* 2) get_outputs_natural_gas( - summary_input: SummaryInput, + heat_load_input: HeatLoadInput, temperature_input: TemperatureInput, natural_gas_billing_input: NaturalGasBillingInput, ) -> RulesEngineResult @@ -153,7 +153,7 @@ test('pyodide solves climate change', async () => { /** * TODO: * - Match up our types with rules engine types at https://github.com/codeforboston/home-energy-analysis-tool/blob/main/python/src/rules_engine/pydantic_models.py#L57 - * - Use those to create summary_input (in the same file) + * - Use those to create heat_load_input (in the same file) * - Use those to create temperature_input (in the same file) * - Use those to create natural_gas_billing_input (in the same file) */ @@ -223,7 +223,7 @@ test('pyodide solves climate change', async () => { from rules_engine import parser from rules_engine.pydantic_models import ( FuelType, - SummaryInput, + HeatLoadInput, TemperatureInput ) from rules_engine import engine @@ -236,7 +236,7 @@ test('pyodide solves climate change', async () => { naturalGasInputRecords = parser.parse_gas_bill(csvDataJs, parser.NaturalGasCompany.NATIONAL_GRID) - summaryInput = SummaryInput(**summaryInputFromJs) + summaryInput = HeatLoadInput(**summaryInputFromJs) temperatureInput = TemperatureInput(**temperatureInputFromJs) outputs = engine.get_outputs_natural_gas(summaryInput,temperatureInput, naturalGasInputRecords) @@ -352,7 +352,7 @@ test('pyodide solves climate change', async () => { // // https://github.com/codeforboston/home-energy-analysis-tool/blob/main/python/src/rules_engine/parser.py#L60 // /* 2) get_outputs_natural_gas( -// summary_input: SummaryInput, +// heat_load_input: HeatLoadInput, // temperature_input: TemperatureInput, // natural_gas_billing_input: NaturalGasBillingInput, // ) -> RulesEngineResult @@ -363,7 +363,7 @@ test('pyodide solves climate change', async () => { // /** // * TODO: // * - Match up our types with rules engine types at https://github.com/codeforboston/home-energy-analysis-tool/blob/main/python/src/rules_engine/pydantic_models.py#L57 -// * - Use those to create summary_input (in the same file) +// * - Use those to create heat_load_input (in the same file) // * - Use those to create temperature_input (in the same file) // * - Use those to create natural_gas_billing_input (in the same file) // */ diff --git a/heat-stack/app/utils/pyodide.util.js b/heat-stack/app/utils/pyodide.util.js index c43b1ed..3684dc0 100644 --- a/heat-stack/app/utils/pyodide.util.js +++ b/heat-stack/app/utils/pyodide.util.js @@ -48,7 +48,7 @@ class PyodideUtil { console.log("Makin SI name:"+ si.name); let f = this.pyodideModule.runPython(` def f(s): - return SummaryInput(**s) + return HeatLoadInput(**s) f `); let fr = f(si); @@ -58,10 +58,10 @@ class PyodideUtil { getSIO() { let r = this.pyodideModule.runPython(` - from rules_engine.pydantic_models import SummaryInput + from rules_engine.pydantic_models import HeatLoadInput from pyodide.ffi import to_js import js - SummaryInput`); + HeatLoadInput`); return r; } @@ -83,7 +83,7 @@ class PyodideUtil { NaturalGasBillingInput, NormalizedBillingPeriodRecordInput, OilPropaneBillingInput, - SummaryInput, + HeatLoadInput, SummaryOutput, TemperatureInput, ) @@ -105,7 +105,7 @@ class PyodideUtil { t = t.to_py(default_converter=default_converter) - summa_inpoot = SummaryInput(**svm) + summa_inpoot = HeatLoadInput(**svm) tempinz = TemperatureInput(**t) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 1c1b1e8..bafb198 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -21,14 +21,14 @@ NormalizedBillingPeriodRecordBase, OilPropaneBillingInput, RulesEngineResult, - SummaryInput, + HeatLoadInput, SummaryOutput, TemperatureInput, ) def get_outputs_oil_propane( - summary_input: SummaryInput, + heat_load_input: HeatLoadInput, dhw_input: Optional[DhwInput], temperature_input: TemperatureInput, oil_propane_billing_input: OilPropaneBillingInput, @@ -52,12 +52,12 @@ def get_outputs_oil_propane( last_date = input_val.period_end_date return get_outputs_normalized( - summary_input, dhw_input, temperature_input, billing_periods + heat_load_input, dhw_input, temperature_input, billing_periods ) def get_outputs_natural_gas( - summary_input: SummaryInput, + heat_load_input: HeatLoadInput, temperature_input: TemperatureInput, natural_gas_billing_input: NaturalGasBillingInput, ) -> RulesEngineResult: @@ -77,12 +77,12 @@ def get_outputs_natural_gas( ) return get_outputs_normalized( - summary_input, None, temperature_input, billing_periods + heat_load_input, None, temperature_input, billing_periods ) def get_outputs_normalized( - summary_input: SummaryInput, + heat_load_input: HeatLoadInput, dhw_input: Optional[DhwInput], temperature_input: TemperatureInput, billing_periods: list[NormalizedBillingPeriodRecordBase], @@ -94,31 +94,31 @@ def get_outputs_normalized( intermediate_billing_periods = convert_to_intermediate_billing_periods( temperature_input=temperature_input, billing_periods=billing_periods, - fuel_type=summary_input.fuel_type, + fuel_type=heat_load_input.fuel_type, ) home = Home.calculate( - summary_input=summary_input, + heat_load_input=heat_load_input, billing_periods=intermediate_billing_periods, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) average_indoor_temperature = get_average_indoor_temperature( - thermostat_set_point=summary_input.thermostat_set_point, - setback_temperature=summary_input.setback_temperature, - setback_hours_per_day=summary_input.setback_hours_per_day, + thermostat_set_point=heat_load_input.thermostat_set_point, + setback_temperature=heat_load_input.setback_temperature, + setback_hours_per_day=heat_load_input.setback_hours_per_day, ) average_heat_load = get_average_heat_load( design_set_point=Constants.DESIGN_SET_POINT, avg_indoor_temp=average_indoor_temperature, balance_point=home.balance_point, - design_temp=summary_input.design_temperature, + design_temp=heat_load_input.design_temperature, ua=home.avg_ua, ) maximum_heat_load = get_maximum_heat_load( design_set_point=Constants.DESIGN_SET_POINT, - design_temp=summary_input.design_temperature, + design_temp=heat_load_input.design_temperature, ua=home.avg_ua, ) @@ -127,7 +127,7 @@ def get_outputs_normalized( other_fuel_usage=home.avg_non_heating_usage, average_indoor_temperature=average_indoor_temperature, difference_between_ti_and_tbp=average_indoor_temperature - home.balance_point, - design_temperature=summary_input.design_temperature, + design_temperature=heat_load_input.design_temperature, whole_home_heat_loss_rate=home.avg_ua, standard_deviation_of_heat_loss_rate=home.stdev_pct, average_heat_load=average_heat_load, @@ -400,14 +400,14 @@ class Home: def _init( self, - summary_input: SummaryInput, + heat_load_input: HeatLoadInput, billing_periods: list[ProcessedBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, ): - self.fuel_type = summary_input.fuel_type - self.heat_sys_efficiency = summary_input.heating_system_efficiency - self.thermostat_set_point = summary_input.thermostat_set_point + self.fuel_type = heat_load_input.fuel_type + self.heat_sys_efficiency = heat_load_input.heating_system_efficiency + self.thermostat_set_point = heat_load_input.thermostat_set_point self.balance_point = initial_balance_point self.dhw_input = dhw_input self._initialize_billing_periods(billing_periods) @@ -624,7 +624,7 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: @classmethod def calculate( cls, - summary_input: SummaryInput, + heat_load_input: HeatLoadInput, billing_periods: list[ProcessedBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, @@ -640,7 +640,7 @@ def calculate( """ home_instance = object.__new__(cls) home_instance._init( - summary_input = summary_input, + heat_load_input = heat_load_input, billing_periods = billing_periods, dhw_input = dhw_input, initial_balance_point = initial_balance_point, diff --git a/python/src/rules_engine/pydantic_models.py b/python/src/rules_engine/pydantic_models.py index fce4208..b94aeeb 100644 --- a/python/src/rules_engine/pydantic_models.py +++ b/python/src/rules_engine/pydantic_models.py @@ -56,7 +56,7 @@ def validate_fuel_type(value: Any) -> FuelType: ) -class SummaryInput(BaseModel): +class HeatLoadInput(BaseModel): """From Summary Tab""" # design_temperature_override: float diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index a103f0e..35eef85 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -31,7 +31,7 @@ gets rid of the need for the class. ) return get_outputs_normalized( - summary_input, None, temperature_input, billing_periods + heat_load_input, None, temperature_input, billing_periods ) def get_outputs_normalized diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 0d751a1..2f0f98b 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -12,7 +12,7 @@ FuelType, NaturalGasBillingInput, NormalizedBillingPeriodRecordBase, - SummaryInput, + HeatLoadInput, SummaryOutput, TemperatureInput, ) @@ -113,7 +113,7 @@ def sample_billing_periods_with_outlier() -> list[engine.ProcessedBill]: @pytest.fixture() -def sample_summary_inputs() -> SummaryInput: +def sample_summary_inputs() -> HeatLoadInput: heat_sys_efficiency = 0.88 living_area = 1000 @@ -122,7 +122,7 @@ def sample_summary_inputs() -> SummaryInput: setback_hours_per_day = 8 fuel_type = FuelType.GAS design_temperature = 60 - summary_input = SummaryInput( + heat_load_input = HeatLoadInput( living_area=living_area, fuel_type=fuel_type, heating_system_efficiency=heat_sys_efficiency, @@ -131,7 +131,7 @@ def sample_summary_inputs() -> SummaryInput: setback_hours_per_day=setback_hours_per_day, design_temperature=design_temperature, ) - return summary_input + return heat_load_input @pytest.fixture() diff --git a/python/tests/test_rules_engine/test_utils.py b/python/tests/test_rules_engine/test_utils.py index 32a6c81..3f50a7f 100644 --- a/python/tests/test_rules_engine/test_utils.py +++ b/python/tests/test_rules_engine/test_utils.py @@ -9,13 +9,13 @@ NaturalGasBillingRecordInput, OilPropaneBillingInput, OilPropaneBillingRecordInput, - SummaryInput, + HeatLoadInput, SummaryOutput, TemperatureInput, ) -class Summary(SummaryInput, SummaryOutput): +class Summary(HeatLoadInput, SummaryOutput): """ Holds summary.json information alongside a string referring to a local weather station. From 3249f4dc40dcfbf783a9e84556526571653b160c Mon Sep 17 00:00:00 2001 From: stemgene Date: Mon, 25 Nov 2024 16:20:21 -0500 Subject: [PATCH 03/26] (Issue #264) Refactor: Rename "SummaryOnput" to "HeatLoadOuput", "summary_output" to "heat_load_output" Co-authored-by: Ethan Strominger --- .../heat/CaseSummaryComponents/AnalysisHeader.tsx | 4 ++-- heat-stack/app/routes/_heat+/single.tsx | 4 ++-- heat-stack/app/utils/pyodide.test.ts | 2 +- heat-stack/app/utils/pyodide.util.js | 2 +- heat-stack/types/index.ts | 4 ++-- python/src/rules_engine/engine.py | 6 +++--- python/src/rules_engine/pydantic_models.py | 4 ++-- python/tests/test_rules_engine/test_engine.py | 8 ++++---- python/tests/test_rules_engine/test_natural_gas.py | 14 +++++++------- python/tests/test_rules_engine/test_utils.py | 6 +++--- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx index 2ea3122..049ecc9 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx @@ -33,8 +33,8 @@ export function AnalysisHeader({ usage_data }: { usage_data: UsageDataSchema}) { // 3312125.0171753373 // ]]) - // Extract the summary_output from usage_data - const summaryOutputs = usage_data?.summary_output; + // Extract the heat_load_output from usage_data + const summaryOutputs = usage_data?.heat_load_output; const totalRecords = usage_data?.billing_records?.length || "-" diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index b21d53e..a24a1ad 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -496,10 +496,10 @@ export default function Inputs() { /** * Where temp1 is a temporary variable with the main Map of Maps (or undefined if page not yet submitted). * - * temp1.get('summary_output'): Map(9) { estimated_balance_point → 61.5, other_fuel_usage → 0.2857142857142857, average_indoor_temperature → 67, difference_between_ti_and_tbp → 5.5, design_temperature → 1, whole_home_heat_loss_rate → 48001.81184312083, standard_deviation_of_heat_loss_rate → 0.08066745182677547, average_heat_load → 3048115.0520381727, maximum_heat_load → 3312125.0171753373 } + * temp1.get('heat_load_output'): Map(9) { estimated_balance_point → 61.5, other_fuel_usage → 0.2857142857142857, average_indoor_temperature → 67, difference_between_ti_and_tbp → 5.5, design_temperature → 1, whole_home_heat_loss_rate → 48001.81184312083, standard_deviation_of_heat_loss_rate → 0.08066745182677547, average_heat_load → 3048115.0520381727, maximum_heat_load → 3312125.0171753373 } */ /* @ts-ignore */ - // console.log("Summary Output", lastResult !== undefined ? JSON.parse(lastResult.data, reviver)?.get('summary_output'): undefined) + // console.log("Summary Output", lastResult !== undefined ? JSON.parse(lastResult.data, reviver)?.get('heat_load_output'): undefined) /** * Where temp1 is a temporary variable with the main Map of Maps (or undefined if page not yet submitted). diff --git a/heat-stack/app/utils/pyodide.test.ts b/heat-stack/app/utils/pyodide.test.ts index 0ce82ae..315d793 100644 --- a/heat-stack/app/utils/pyodide.test.ts +++ b/heat-stack/app/utils/pyodide.test.ts @@ -275,7 +275,7 @@ test('pyodide solves climate change', async () => { console.log(result.toJs().get('balance_point_graph')) /* prettify-ignore */ - const expectedRecordsToGoInTheTable = '{"dataType":"Map","value":[["summary_output",{"dataType":"Map","value":[["estimated_balance_point",59.5],["other_fuel_usage",8.666666666666666],["average_indoor_temperature",68],["difference_between_ti_and_tbp",8.5],["design_temperature",9.5],["whole_home_heat_loss_rate",47972.03453453454],["standard_deviation_of_heat_loss_rate",0.07742772585617895],["average_heat_load",2494545.795795796],["maximum_heat_load",2902308.0893393396]]}],["balance_point_graph",{"dataType":"Map","value":[["records",[{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",41034.85407876231],["change_in_heat_loss_rate",0],["percent_change_in_heat_loss_rate",0],["standard_deviation",0.3967358807600794]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",38592.303240740745],["change_in_heat_loss_rate",-2442.550838021569],["percent_change_in_heat_loss_rate",-6.32911392405064],["standard_deviation",0.39673588076007943]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",43807.47935435436],["change_in_heat_loss_rate",2772.625275592043],["percent_change_in_heat_loss_rate",6.329113924050622],["standard_deviation",0.3967358807600795]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",42226.71012849585],["change_in_heat_loss_rate",-2672.576590411132],["percent_change_in_heat_loss_rate",-6.329113924050639],["standard_deviation",0.30164495413734566]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",47933.022308022315],["change_in_heat_loss_rate",3033.7355891153347],["percent_change_in_heat_loss_rate",6.3291139240506284],["standard_deviation",0.3016449541373457]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",46671.62698412699],["change_in_heat_loss_rate",-2953.9004420333513],["percent_change_in_heat_loss_rate",-6.329113924050628],["standard_deviation",0.15298851745396608]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",52978.60360360361],["change_in_heat_loss_rate",3353.0761774432685],["percent_change_in_heat_loss_rate",6.329113924050636],["standard_deviation",0.1529885174539661]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",44137.56613756614],["change_in_heat_loss_rate",-2793.516844149759],["percent_change_in_heat_loss_rate",-6.329113924050642],["standard_deviation",0.10782787516463575]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",53732.689210950084],["change_in_heat_loss_rate",3630.587108847976],["percent_change_in_heat_loss_rate",6.756756756756753],["standard_deviation",0.10782787516463577]]},{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",44935.829817158934],["change_in_heat_loss_rate",-3036.2047173756073],["percent_change_in_heat_loss_rate",-6.756756756756764],["standard_deviation",0.07742772585617896]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",51448.26892109501],["change_in_heat_loss_rate",3476.2343865604707],["percent_change_in_heat_loss_rate",6.756756756756752],["standard_deviation",0.07742772585617896]]}]]]}],["billing_records",[{"dataType":"Map","value":[["period_start_date","2020-10-02"],["period_end_date","2020-11-04"],["usage",29],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2020-11-05"],["period_end_date","2020-12-03"],["usage",36],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2020-12-04"],["period_end_date","2021-01-07"],["usage",97],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-01-08"],["period_end_date","2021-02-05"],["usage",105],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-02-06"],["period_end_date","2021-03-05"],["usage",98],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-03-06"],["period_end_date","2021-04-06"],["usage",66],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-04-07"],["period_end_date","2021-05-05"],["usage",22],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-05-06"],["period_end_date","2021-06-07"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-06-08"],["period_end_date","2021-07-06"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-07-07"],["period_end_date","2021-08-04"],["usage",10],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-08-05"],["period_end_date","2021-09-08"],["usage",11],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-09-09"],["period_end_date","2021-10-05"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-10-06"],["period_end_date","2021-11-03"],["usage",13],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-11-04"],["period_end_date","2021-12-06"],["usage",41],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2021-12-07"],["period_end_date","2022-01-05"],["usage",86],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-01-06"],["period_end_date","2022-02-03"],["usage",132],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-02-04"],["period_end_date","2022-03-07"],["usage",116],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-03-08"],["period_end_date","2022-04-04"],["usage",49],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-04-05"],["period_end_date","2022-05-05"],["usage",39],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-05-06"],["period_end_date","2022-06-06"],["usage",20],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-06-07"],["period_end_date","2022-07-05"],["usage",9],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-07-06"],["period_end_date","2022-08-03"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-08-04"],["period_end_date","2022-09-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-09-04"],["period_end_date","2022-10-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-10-04"],["period_end_date","2022-11-03"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]}]]]}' + const expectedRecordsToGoInTheTable = '{"dataType":"Map","value":[["heat_load_output",{"dataType":"Map","value":[["estimated_balance_point",59.5],["other_fuel_usage",8.666666666666666],["average_indoor_temperature",68],["difference_between_ti_and_tbp",8.5],["design_temperature",9.5],["whole_home_heat_loss_rate",47972.03453453454],["standard_deviation_of_heat_loss_rate",0.07742772585617895],["average_heat_load",2494545.795795796],["maximum_heat_load",2902308.0893393396]]}],["balance_point_graph",{"dataType":"Map","value":[["records",[{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",41034.85407876231],["change_in_heat_loss_rate",0],["percent_change_in_heat_loss_rate",0],["standard_deviation",0.3967358807600794]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",38592.303240740745],["change_in_heat_loss_rate",-2442.550838021569],["percent_change_in_heat_loss_rate",-6.32911392405064],["standard_deviation",0.39673588076007943]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",43807.47935435436],["change_in_heat_loss_rate",2772.625275592043],["percent_change_in_heat_loss_rate",6.329113924050622],["standard_deviation",0.3967358807600795]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",42226.71012849585],["change_in_heat_loss_rate",-2672.576590411132],["percent_change_in_heat_loss_rate",-6.329113924050639],["standard_deviation",0.30164495413734566]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",47933.022308022315],["change_in_heat_loss_rate",3033.7355891153347],["percent_change_in_heat_loss_rate",6.3291139240506284],["standard_deviation",0.3016449541373457]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",46671.62698412699],["change_in_heat_loss_rate",-2953.9004420333513],["percent_change_in_heat_loss_rate",-6.329113924050628],["standard_deviation",0.15298851745396608]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",52978.60360360361],["change_in_heat_loss_rate",3353.0761774432685],["percent_change_in_heat_loss_rate",6.329113924050636],["standard_deviation",0.1529885174539661]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",44137.56613756614],["change_in_heat_loss_rate",-2793.516844149759],["percent_change_in_heat_loss_rate",-6.329113924050642],["standard_deviation",0.10782787516463575]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",53732.689210950084],["change_in_heat_loss_rate",3630.587108847976],["percent_change_in_heat_loss_rate",6.756756756756753],["standard_deviation",0.10782787516463577]]},{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",44935.829817158934],["change_in_heat_loss_rate",-3036.2047173756073],["percent_change_in_heat_loss_rate",-6.756756756756764],["standard_deviation",0.07742772585617896]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",51448.26892109501],["change_in_heat_loss_rate",3476.2343865604707],["percent_change_in_heat_loss_rate",6.756756756756752],["standard_deviation",0.07742772585617896]]}]]]}],["billing_records",[{"dataType":"Map","value":[["period_start_date","2020-10-02"],["period_end_date","2020-11-04"],["usage",29],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2020-11-05"],["period_end_date","2020-12-03"],["usage",36],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2020-12-04"],["period_end_date","2021-01-07"],["usage",97],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-01-08"],["period_end_date","2021-02-05"],["usage",105],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-02-06"],["period_end_date","2021-03-05"],["usage",98],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-03-06"],["period_end_date","2021-04-06"],["usage",66],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-04-07"],["period_end_date","2021-05-05"],["usage",22],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-05-06"],["period_end_date","2021-06-07"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-06-08"],["period_end_date","2021-07-06"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-07-07"],["period_end_date","2021-08-04"],["usage",10],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-08-05"],["period_end_date","2021-09-08"],["usage",11],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-09-09"],["period_end_date","2021-10-05"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-10-06"],["period_end_date","2021-11-03"],["usage",13],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-11-04"],["period_end_date","2021-12-06"],["usage",41],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2021-12-07"],["period_end_date","2022-01-05"],["usage",86],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-01-06"],["period_end_date","2022-02-03"],["usage",132],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-02-04"],["period_end_date","2022-03-07"],["usage",116],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-03-08"],["period_end_date","2022-04-04"],["usage",49],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-04-05"],["period_end_date","2022-05-05"],["usage",39],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-05-06"],["period_end_date","2022-06-06"],["usage",20],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-06-07"],["period_end_date","2022-07-05"],["usage",9],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-07-06"],["period_end_date","2022-08-03"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-08-04"],["period_end_date","2022-09-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-09-04"],["period_end_date","2022-10-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-10-04"],["period_end_date","2022-11-03"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]}]]]}' // how you do "dir()"" in python // console.log(Object.getOwnPropertyNames(result.toJs())); diff --git a/heat-stack/app/utils/pyodide.util.js b/heat-stack/app/utils/pyodide.util.js index 3684dc0..dea0cbf 100644 --- a/heat-stack/app/utils/pyodide.util.js +++ b/heat-stack/app/utils/pyodide.util.js @@ -84,7 +84,7 @@ class PyodideUtil { NormalizedBillingPeriodRecordInput, OilPropaneBillingInput, HeatLoadInput, - SummaryOutput, + HeatLoadOutput, TemperatureInput, ) diff --git a/heat-stack/types/index.ts b/heat-stack/types/index.ts index b934a47..cd39945 100644 --- a/heat-stack/types/index.ts +++ b/heat-stack/types/index.ts @@ -63,7 +63,7 @@ export const balancePointGraphSchema = z.object({ records: z.array(balancePointGraphRecordSchema), }) -// Define the schema for the 'summary_output' key +// Define the schema for the 'heat_load_output' key export const summaryOutputSchema = z.object({ // rulesEngineVersion: z.string(), // TODO estimated_balance_point: z.number(), @@ -126,7 +126,7 @@ export const allBillingRecordsSchema = z.array(oneBillingRecordSchema); // Define the schema for the 'usage_data' key export const usageDataSchema = z.object({ - summary_output: summaryOutputSchema, + heat_load_output: summaryOutputSchema, balance_point_graph: balancePointGraphSchema, billing_records: allBillingRecordsSchema, }) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index bafb198..2bbeca8 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -22,7 +22,7 @@ OilPropaneBillingInput, RulesEngineResult, HeatLoadInput, - SummaryOutput, + HeatLoadOutput, TemperatureInput, ) @@ -122,7 +122,7 @@ def get_outputs_normalized( ua=home.avg_ua, ) - summary_output = SummaryOutput( + heat_load_output = HeatLoadOutput( estimated_balance_point=home.balance_point, other_fuel_usage=home.avg_non_heating_usage, average_indoor_temperature=average_indoor_temperature, @@ -151,7 +151,7 @@ def get_outputs_normalized( billing_records.append(billing_record) result = RulesEngineResult( - summary_output=summary_output, + heat_load_output=heat_load_output, balance_point_graph=balance_point_graph, billing_records=billing_records, ) diff --git a/python/src/rules_engine/pydantic_models.py b/python/src/rules_engine/pydantic_models.py index b94aeeb..a51d332 100644 --- a/python/src/rules_engine/pydantic_models.py +++ b/python/src/rules_engine/pydantic_models.py @@ -180,7 +180,7 @@ class TemperatureInput(BaseModel): temperatures: list[float] -class SummaryOutput(BaseModel): +class HeatLoadOutput(BaseModel): """From Summary tab""" estimated_balance_point: float = Field( @@ -221,7 +221,7 @@ class BalancePointGraph(BaseModel): class RulesEngineResult(BaseModel): - summary_output: SummaryOutput + heat_load_output: HeatLoadOutput balance_point_graph: BalancePointGraph billing_records: list[NormalizedBillingPeriodRecord] diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 2f0f98b..d1b66cd 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -13,7 +13,7 @@ NaturalGasBillingInput, NormalizedBillingPeriodRecordBase, HeatLoadInput, - SummaryOutput, + HeatLoadOutput, TemperatureInput, ) @@ -420,12 +420,12 @@ def test_get_outputs_normalized( sample_normalized_billing_periods, ) - assert rules_engine_result.summary_output.estimated_balance_point == 60.5 - assert rules_engine_result.summary_output.whole_home_heat_loss_rate == approx( + assert rules_engine_result.heat_load_output.estimated_balance_point == 60.5 + assert rules_engine_result.heat_load_output.whole_home_heat_loss_rate == approx( 1519.72, abs=1 ) assert ( - rules_engine_result.summary_output.standard_deviation_of_heat_loss_rate + rules_engine_result.heat_load_output.standard_deviation_of_heat_loss_rate == approx(0.0463, abs=0.01) ) assert rules_engine_result.billing_records[0].usage == 60 diff --git a/python/tests/test_rules_engine/test_natural_gas.py b/python/tests/test_rules_engine/test_natural_gas.py index d778ae6..d7a4b9d 100644 --- a/python/tests/test_rules_engine/test_natural_gas.py +++ b/python/tests/test_rules_engine/test_natural_gas.py @@ -89,7 +89,7 @@ def test_balance_point_natural_gas(data: Example) -> None: data.summary, data.temperature_data, data.natural_gas_usage ) assert data.summary.estimated_balance_point == approx( - rules_engine_result.summary_output.estimated_balance_point, abs=0.1 + rules_engine_result.heat_load_output.estimated_balance_point, abs=0.1 ) @@ -97,7 +97,7 @@ def test_whole_home_heat_loss_rate_natural_gas(data: Example) -> None: rules_engine_result = engine.get_outputs_natural_gas( data.summary, data.temperature_data, data.natural_gas_usage ) - assert rules_engine_result.summary_output.whole_home_heat_loss_rate == approx( + assert rules_engine_result.heat_load_output.whole_home_heat_loss_rate == approx( data.summary.whole_home_heat_loss_rate, abs=1 ) @@ -107,7 +107,7 @@ def test_standard_deviation_of_heat_loss_rate_natural_gas(data: Example) -> None data.summary, data.temperature_data, data.natural_gas_usage ) assert ( - rules_engine_result.summary_output.standard_deviation_of_heat_loss_rate + rules_engine_result.heat_load_output.standard_deviation_of_heat_loss_rate == approx(data.summary.standard_deviation_of_heat_loss_rate, abs=0.01) ) @@ -116,7 +116,7 @@ def test_difference_between_ti_and_tbp_natural_gas(data: Example) -> None: rules_engine_result = engine.get_outputs_natural_gas( data.summary, data.temperature_data, data.natural_gas_usage ) - assert rules_engine_result.summary_output.difference_between_ti_and_tbp == approx( + assert rules_engine_result.heat_load_output.difference_between_ti_and_tbp == approx( data.summary.difference_between_ti_and_tbp, abs=0.1 ) @@ -125,7 +125,7 @@ def test_average_heat_load_natural_gas(data: Example) -> None: rules_engine_result = engine.get_outputs_natural_gas( data.summary, data.temperature_data, data.natural_gas_usage ) - assert rules_engine_result.summary_output.average_heat_load == approx( + assert rules_engine_result.heat_load_output.average_heat_load == approx( data.summary.average_heat_load, abs=1 ) @@ -134,7 +134,7 @@ def test_design_temperature_natural_gas(data: Example) -> None: rules_engine_result = engine.get_outputs_natural_gas( data.summary, data.temperature_data, data.natural_gas_usage ) - assert rules_engine_result.summary_output.design_temperature == approx( + assert rules_engine_result.heat_load_output.design_temperature == approx( data.summary.design_temperature, abs=0.1 ) @@ -143,7 +143,7 @@ def test_maximum_heat_load_natural_gas(data: Example) -> None: rules_engine_result = engine.get_outputs_natural_gas( data.summary, data.temperature_data, data.natural_gas_usage ) - assert rules_engine_result.summary_output.maximum_heat_load == approx( + assert rules_engine_result.heat_load_output.maximum_heat_load == approx( data.summary.maximum_heat_load, abs=1 ) diff --git a/python/tests/test_rules_engine/test_utils.py b/python/tests/test_rules_engine/test_utils.py index 3f50a7f..5ec6a03 100644 --- a/python/tests/test_rules_engine/test_utils.py +++ b/python/tests/test_rules_engine/test_utils.py @@ -10,12 +10,12 @@ OilPropaneBillingInput, OilPropaneBillingRecordInput, HeatLoadInput, - SummaryOutput, + HeatLoadOutput, TemperatureInput, ) -class Summary(HeatLoadInput, SummaryOutput): +class Summary(HeatLoadInput, HeatLoadOutput): """ Holds summary.json information alongside a string referring to a local weather station. @@ -98,7 +98,7 @@ def load_fuel_billing_example_input( # Choose the correct billing period heat loss (aka "ua") # column based on the estimated balance point provided in - # SummaryOutput + # HeatLoadOutput ua_column_name = None # First we will look for an exact match to the value of # the estimated balance point From 9baddc9cb440a584b78cd0f336f9fcab1c25c525 Mon Sep 17 00:00:00 2001 From: stemgene Date: Mon, 25 Nov 2024 22:03:54 -0500 Subject: [PATCH 04/26] (Issue #264) Refactor: Rename "ProcessedBill" to "ProcessedEnergyBillIntermediate", "processed_bill" to "processed_energy_bill_intermediate" Co-authored-by: Ethan Strominger --- python/src/rules_engine/engine.py | 16 +++++----- python/src/rules_engine/refactor.md | 4 +-- python/tests/test_rules_engine/test_engine.py | 32 +++++++++---------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 2bbeca8..98ffd7e 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -162,7 +162,7 @@ def convert_to_intermediate_billing_periods( temperature_input: TemperatureInput, billing_periods: list[NormalizedBillingPeriodRecordBase], fuel_type: FuelType, -) -> list[ProcessedBill]: +) -> list[ProcessedEnergyBillIntermediate]: """ Converts temperature data and billing period inputs into internal classes used for heat loss calculations. @@ -194,7 +194,7 @@ def convert_to_intermediate_billing_periods( else: raise ValueError("Unsupported fuel type.") - intermediate_billing_period = ProcessedBill( + intermediate_billing_period = ProcessedEnergyBillIntermediate( input=billing_period, avg_temps=temperature_input.temperatures[start_idx:end_idx], usage=billing_period.usage, @@ -401,7 +401,7 @@ class Home: def _init( self, heat_load_input: HeatLoadInput, - billing_periods: list[ProcessedBill], + billing_periods: list[ProcessedEnergyBillIntermediate], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, ): @@ -413,7 +413,7 @@ def _init( self._initialize_billing_periods(billing_periods) - def _initialize_billing_periods(self, billing_periods: list[ProcessedBill]) -> None: + def _initialize_billing_periods(self, billing_periods: list[ProcessedEnergyBillIntermediate]) -> None: self.bills_winter = [] self.bills_summer = [] self.bills_shoulder = [] @@ -625,7 +625,7 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: def calculate( cls, heat_load_input: HeatLoadInput, - billing_periods: list[ProcessedBill], + billing_periods: list[ProcessedEnergyBillIntermediate], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, initial_balance_point_sensitivity: float = 0.5, @@ -655,7 +655,7 @@ def calculate( return home_instance - def initialize_ua(self, billing_period: ProcessedBill) -> None: + def initialize_ua(self, billing_period: ProcessedEnergyBillIntermediate) -> None: """ Average heating usage, partial UA, initial UA. requires that self.home have non heating usage calculated. @@ -666,7 +666,7 @@ def initialize_ua(self, billing_period: ProcessedBill) -> None: billing_period.partial_ua = self.calculate_partial_ua(billing_period) billing_period.ua = billing_period.partial_ua / billing_period.total_hdd - def calculate_partial_ua(self, billing_period: ProcessedBill) -> float: + def calculate_partial_ua(self, billing_period: ProcessedEnergyBillIntermediate) -> float: """ The portion of UA that is not dependent on the balance point """ @@ -681,7 +681,7 @@ def calculate_partial_ua(self, billing_period: ProcessedBill) -> float: ) -class ProcessedBill: +class ProcessedEnergyBillIntermediate: """ An internal class storing data whence heating usage per billing period is calculated. diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index 35eef85..6f9b93a 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -13,7 +13,7 @@ home variables used 1. Remove temporary_rules_engine.py 2. Rename rules-engine to "python" 3. Rename NormalizedBillingRecordBase class to BillingInput -4. Rename BillingPeriod to ProcessedBill and billing_period to processed_bill +4. Rename BillingPeriod to ProcessedEnergyBillIntermediate and billing_period to processed_energy_bill_intermediate 5. Combine get_outputs_normalized and convert_to_intermediate_billing_record and get rid of NormalizedBillingRecord. There is only one place NormalizedBillingRecord is used and combining code gets rid of the need for the class. - Change @@ -55,7 +55,7 @@ to inputBill.start_date, inputBill.end_date ) - processedBill = ProcessedBill( + processedBill = ProcessedEnergyBillIntermediate( input = inputBill, avg_temps = avg_temps, default_analysis_type = default_analysis_type diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index d1b66cd..238d9df 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -26,9 +26,9 @@ @pytest.fixture() -def sample_billing_periods() -> list[engine.ProcessedBill]: +def sample_billing_periods() -> list[engine.ProcessedEnergyBillIntermediate]: billing_periods = [ - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [28, 29, 30, 29], 50, @@ -36,7 +36,7 @@ def sample_billing_periods() -> list[engine.ProcessedBill]: True, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [32, 35, 35, 38], 45, @@ -44,7 +44,7 @@ def sample_billing_periods() -> list[engine.ProcessedBill]: True, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [41, 43, 42, 42], 30, @@ -52,7 +52,7 @@ def sample_billing_periods() -> list[engine.ProcessedBill]: True, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [72, 71, 70, 69], 0.96, @@ -65,9 +65,9 @@ def sample_billing_periods() -> list[engine.ProcessedBill]: @pytest.fixture() -def sample_billing_periods_with_outlier() -> list[engine.ProcessedBill]: +def sample_billing_periods_with_outlier() -> list[engine.ProcessedEnergyBillIntermediate]: billing_periods = [ - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [41.7, 41.6, 32, 25.4], 60, @@ -75,7 +75,7 @@ def sample_billing_periods_with_outlier() -> list[engine.ProcessedBill]: True, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [28, 29, 30, 29], 50, @@ -83,7 +83,7 @@ def sample_billing_periods_with_outlier() -> list[engine.ProcessedBill]: True, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [32, 35, 35, 38], 45, @@ -91,7 +91,7 @@ def sample_billing_periods_with_outlier() -> list[engine.ProcessedBill]: True, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [41, 43, 42, 42], 30, @@ -99,7 +99,7 @@ def sample_billing_periods_with_outlier() -> list[engine.ProcessedBill]: True, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [72, 71, 70, 69], 0.96, @@ -359,7 +359,7 @@ def test_convert_to_intermediate_billing_periods( ) expected_results = [ - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [41.7, 41.6, 32, 25.4], 60, @@ -367,7 +367,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [28, 29, 30, 29], 50, @@ -375,7 +375,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [32, 35, 35, 38], 45, @@ -383,7 +383,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [41, 43, 42, 42], 30, @@ -391,7 +391,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedBill( + engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, [72, 71, 70, 69], 0.96, From e131eea9ad697e91ba845bd9e2117e7fb3c0784a Mon Sep 17 00:00:00 2001 From: stemgene Date: Tue, 26 Nov 2024 20:21:50 -0500 Subject: [PATCH 05/26] add "balance_point = 0" --- python/src/rules_engine/engine.py | 20 +++++++++++-------- python/tests/test_rules_engine/test_engine.py | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 98ffd7e..20097fe 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -397,6 +397,7 @@ class Home: of fuel used, calculates the UA for different billing periods and the standard deviation of the UA values across them. """ + balance_point = 0 def _init( self, @@ -412,8 +413,9 @@ def _init( self.dhw_input = dhw_input self._initialize_billing_periods(billing_periods) - - def _initialize_billing_periods(self, billing_periods: list[ProcessedEnergyBillIntermediate]) -> None: + def _initialize_billing_periods( + self, billing_periods: list[ProcessedEnergyBillIntermediate] + ) -> None: self.bills_winter = [] self.bills_summer = [] self.bills_shoulder = [] @@ -640,11 +642,11 @@ def calculate( """ home_instance = object.__new__(cls) home_instance._init( - heat_load_input = heat_load_input, - billing_periods = billing_periods, - dhw_input = dhw_input, - initial_balance_point = initial_balance_point, - ) + heat_load_input=heat_load_input, + billing_periods=billing_periods, + dhw_input=dhw_input, + initial_balance_point=initial_balance_point, + ) home_instance._calculate_avg_non_heating_usage() home_instance._calculate_balance_point_and_ua( initial_balance_point_sensitivity, @@ -666,7 +668,9 @@ def initialize_ua(self, billing_period: ProcessedEnergyBillIntermediate) -> None billing_period.partial_ua = self.calculate_partial_ua(billing_period) billing_period.ua = billing_period.partial_ua / billing_period.total_hdd - def calculate_partial_ua(self, billing_period: ProcessedEnergyBillIntermediate) -> float: + def calculate_partial_ua( + self, billing_period: ProcessedEnergyBillIntermediate + ) -> float: """ The portion of UA that is not dependent on the balance point """ diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 238d9df..0e1cacc 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -65,7 +65,9 @@ def sample_billing_periods() -> list[engine.ProcessedEnergyBillIntermediate]: @pytest.fixture() -def sample_billing_periods_with_outlier() -> list[engine.ProcessedEnergyBillIntermediate]: +def sample_billing_periods_with_outlier() -> ( + list[engine.ProcessedEnergyBillIntermediate] +): billing_periods = [ engine.ProcessedEnergyBillIntermediate( dummy_billing_period_record, From 480e905cea6b7d9d1b52f9447d7e0824952b14f4 Mon Sep 17 00:00:00 2001 From: stemgene Date: Tue, 26 Nov 2024 20:50:50 -0500 Subject: [PATCH 06/26] update the return type annotation of class Home._init [no-untyped-def] --- python/src/rules_engine/engine.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 20097fe..256eb30 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -397,15 +397,13 @@ class Home: of fuel used, calculates the UA for different billing periods and the standard deviation of the UA values across them. """ - balance_point = 0 - def _init( self, heat_load_input: HeatLoadInput, billing_periods: list[ProcessedEnergyBillIntermediate], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, - ): + ) -> None: self.fuel_type = heat_load_input.fuel_type self.heat_sys_efficiency = heat_load_input.heating_system_efficiency self.thermostat_set_point = heat_load_input.thermostat_set_point @@ -634,7 +632,7 @@ def calculate( stdev_pct_max: float = 0.10, max_stdev_pct_diff: float = 0.01, next_balance_point_sensitivity: float = 0.5, - ) -> None: + ) -> "Home": """ For this Home, calculates avg non heating usage and then the estimated balance point and UA coefficient for the home, removing UA outliers based on a normalized standard From 599adf84ce90a2ba4c494135e43933f0ca22c042 Mon Sep 17 00:00:00 2001 From: stemgene Date: Tue, 26 Nov 2024 20:54:46 -0500 Subject: [PATCH 07/26] update --- python/src/rules_engine/engine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 256eb30..95fc1b5 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -397,13 +397,14 @@ class Home: of fuel used, calculates the UA for different billing periods and the standard deviation of the UA values across them. """ + def _init( self, heat_load_input: HeatLoadInput, billing_periods: list[ProcessedEnergyBillIntermediate], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, - ) -> None: + ) -> None: self.fuel_type = heat_load_input.fuel_type self.heat_sys_efficiency = heat_load_input.heating_system_efficiency self.thermostat_set_point = heat_load_input.thermostat_set_point From 2aac1b724cbd8b367d368b6dc617a92e3bdd1a7c Mon Sep 17 00:00:00 2001 From: stemgene Date: Tue, 26 Nov 2024 20:58:15 -0500 Subject: [PATCH 08/26] update --- python/src/rules_engine/engine.py | 4 ++-- python/tests/test_rules_engine/test_engine.py | 4 ++-- python/tests/test_rules_engine/test_utils.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 95fc1b5..ccafabd 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -16,13 +16,13 @@ Constants, DhwInput, FuelType, + HeatLoadInput, + HeatLoadOutput, NaturalGasBillingInput, NormalizedBillingPeriodRecord, NormalizedBillingPeriodRecordBase, OilPropaneBillingInput, RulesEngineResult, - HeatLoadInput, - HeatLoadOutput, TemperatureInput, ) diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 0e1cacc..c8b3cdd 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -10,10 +10,10 @@ BalancePointGraph, DhwInput, FuelType, - NaturalGasBillingInput, - NormalizedBillingPeriodRecordBase, HeatLoadInput, HeatLoadOutput, + NaturalGasBillingInput, + NormalizedBillingPeriodRecordBase, TemperatureInput, ) diff --git a/python/tests/test_rules_engine/test_utils.py b/python/tests/test_rules_engine/test_utils.py index 5ec6a03..c580102 100644 --- a/python/tests/test_rules_engine/test_utils.py +++ b/python/tests/test_rules_engine/test_utils.py @@ -5,12 +5,12 @@ from rules_engine.pydantic_models import ( FuelType, + HeatLoadInput, + HeatLoadOutput, NaturalGasBillingInput, NaturalGasBillingRecordInput, OilPropaneBillingInput, OilPropaneBillingRecordInput, - HeatLoadInput, - HeatLoadOutput, TemperatureInput, ) From eae5cb0cdc1ca9a0f0ff3e5b98331c9ed2a0fd0c Mon Sep 17 00:00:00 2001 From: stemgene Date: Tue, 26 Nov 2024 21:04:30 -0500 Subject: [PATCH 09/26] (Issue #264) Refactor: Rename "NormalizedBillingPeriodRecordBase" to "ProcessedEnergyBillInput" Co-authored-by: Ethan Strominger --- heat-stack/app/routes/_heat+/single.tsx | 6 +++--- python/src/rules_engine/engine.py | 18 +++++++++--------- python/src/rules_engine/pydantic_models.py | 4 ++-- python/src/rules_engine/refactor.md | 6 +++--- python/tests/test_rules_engine/test_engine.py | 10 +++++----- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index a24a1ad..7a2de6b 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -346,7 +346,7 @@ export async function action({ request, params }: ActionFunctionArgs) { FuelType, HeatLoadInput, TemperatureInput, - NormalizedBillingPeriodRecordBase + ProcessedEnergyBillInput ) from rules_engine import engine, helpers @@ -354,7 +354,7 @@ export async function action({ request, params }: ActionFunctionArgs) { # heat_load_input: HeatLoadInput, # dhw_input: Optional[DhwInput], # temperature_input: TemperatureInput, - # billing_periods: list[NormalizedBillingPeriodRecordBase], + # billing_periods: list[ProcessedEnergyBillInput], # ) def executeRoundtripAnalyticsFromForm(summaryInputJs, temperatureInputJs, userAdjustedData, state_id, county_id): @@ -372,7 +372,7 @@ export async function action({ request, params }: ActionFunctionArgs) { temperatureInput = TemperatureInput(**temperatureInputFromJs) # third step, re-run of the table data - userAdjustedDataFromJsToPython = [NormalizedBillingPeriodRecordBase(**record) for record in userAdjustedData['billing_records'] ] + userAdjustedDataFromJsToPython = [ProcessedEnergyBillInput(**record) for record in userAdjustedData['billing_records'] ] # print("py", userAdjustedDataFromJsToPython[0]) outputs2 = engine.get_outputs_normalized(summaryInput, None, temperatureInput, userAdjustedDataFromJsToPython) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index ccafabd..e3f77c9 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -20,7 +20,7 @@ HeatLoadOutput, NaturalGasBillingInput, NormalizedBillingPeriodRecord, - NormalizedBillingPeriodRecordBase, + ProcessedEnergyBillInput, OilPropaneBillingInput, RulesEngineResult, TemperatureInput, @@ -36,13 +36,13 @@ def get_outputs_oil_propane( """ Analyze the heat load for a home that is using oil or propane as its current heating system fuel. """ - billing_periods: list[NormalizedBillingPeriodRecordBase] = [] + billing_periods: list[ProcessedEnergyBillInput] = [] last_date = oil_propane_billing_input.preceding_delivery_date for input_val in oil_propane_billing_input.records: start_date = last_date + timedelta(days=1) billing_periods.append( - NormalizedBillingPeriodRecordBase( + ProcessedEnergyBillInput( period_start_date=start_date, period_end_date=input_val.period_end_date, usage=input_val.gallons, @@ -64,11 +64,11 @@ def get_outputs_natural_gas( """ Analyze the heat load for a home that is using natural gas as its current heating system fuel. """ - billing_periods: list[NormalizedBillingPeriodRecordBase] = [] + billing_periods: list[ProcessedEnergyBillInput] = [] for input_val in natural_gas_billing_input.records: billing_periods.append( - NormalizedBillingPeriodRecordBase( + ProcessedEnergyBillInput( period_start_date=input_val.period_start_date, period_end_date=input_val.period_end_date, usage=input_val.usage_therms, @@ -85,7 +85,7 @@ def get_outputs_normalized( heat_load_input: HeatLoadInput, dhw_input: Optional[DhwInput], temperature_input: TemperatureInput, - billing_periods: list[NormalizedBillingPeriodRecordBase], + billing_periods: list[ProcessedEnergyBillInput], ) -> RulesEngineResult: """ Analyze the heat load for a home based on normalized, fuel-type-agnostic billing records. @@ -160,7 +160,7 @@ def get_outputs_normalized( def convert_to_intermediate_billing_periods( temperature_input: TemperatureInput, - billing_periods: list[NormalizedBillingPeriodRecordBase], + billing_periods: list[ProcessedEnergyBillInput], fuel_type: FuelType, ) -> list[ProcessedEnergyBillIntermediate]: """ @@ -690,7 +690,7 @@ class ProcessedEnergyBillIntermediate: period is calculated. """ - input: NormalizedBillingPeriodRecordBase + input: ProcessedEnergyBillInput avg_heating_usage: float balance_point: float partial_ua: float @@ -700,7 +700,7 @@ class ProcessedEnergyBillIntermediate: def __init__( self, - input: NormalizedBillingPeriodRecordBase, + input: ProcessedEnergyBillInput, avg_temps: list[float], usage: float, analysis_type: AnalysisType, diff --git a/python/src/rules_engine/pydantic_models.py b/python/src/rules_engine/pydantic_models.py index a51d332..8d7f033 100644 --- a/python/src/rules_engine/pydantic_models.py +++ b/python/src/rules_engine/pydantic_models.py @@ -141,7 +141,7 @@ def overall_end_date(self) -> datetime: return max_date -class NormalizedBillingPeriodRecordBase(BaseModel): +class ProcessedEnergyBillInput(BaseModel): """ Base class for a normalized billing period record. @@ -156,7 +156,7 @@ class NormalizedBillingPeriodRecordBase(BaseModel): inclusion_override: bool = Field(frozen=True) -class NormalizedBillingPeriodRecord(NormalizedBillingPeriodRecordBase): +class NormalizedBillingPeriodRecord(ProcessedEnergyBillInput): """ Derived class for holding a normalized billing period record. diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index 6f9b93a..b487523 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -18,11 +18,11 @@ home variables used gets rid of the need for the class. - Change ``` - billing_periods: list[NormalizedBillingPeriodRecordBase] = [] + billing_periods: list[ProcessedEnergyBillInput] = [] for input_val in natural_gas_billing_input.records: billing_periods.append( - NormalizedBillingPeriodRecordBase( + ProcessedEnergyBillInput( period_start_date=input_val.period_start_date, period_end_date=input_val.period_end_date, usage=input_val.usage_therms, @@ -41,7 +41,7 @@ gets rid of the need for the class. to ``` inputBill = - NormalizedBillingPeriodRecordBase( + ProcessedEnergyBillInput( period_start_date=input_val.period_start_date, period_end_date=input_val.period_end_date, usage=input_val.usage_therms, diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index c8b3cdd..ffaff67 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -13,11 +13,11 @@ HeatLoadInput, HeatLoadOutput, NaturalGasBillingInput, - NormalizedBillingPeriodRecordBase, + ProcessedEnergyBillInput, TemperatureInput, ) -dummy_billing_period_record = NormalizedBillingPeriodRecordBase( +dummy_billing_period_record = ProcessedEnergyBillInput( period_start_date=datetime(2024, 1, 1), period_end_date=datetime(2024, 2, 1), usage=1.0, @@ -192,7 +192,7 @@ def sample_temp_inputs() -> TemperatureInput: @pytest.fixture() -def sample_normalized_billing_periods() -> list[NormalizedBillingPeriodRecordBase]: +def sample_normalized_billing_periods() -> list[ProcessedEnergyBillInput]: billing_periods_dict: Any = [ { "period_start_date": "2022-12-01", @@ -239,11 +239,11 @@ def sample_normalized_billing_periods() -> list[NormalizedBillingPeriodRecordBas ] # billing_periods = [ - # NormalizedBillingPeriodRecordBase(**x) for x in billing_periods_dict + # ProcessedEnergyBillInput(**x) for x in billing_periods_dict # ] billing_periods = [ - NormalizedBillingPeriodRecordBase( + ProcessedEnergyBillInput( period_start_date=datetime.fromisoformat(x["period_start_date"]), period_end_date=datetime.fromisoformat(x["period_end_date"]), usage=x["usage"], From cd09dd5cfb50676c1bb358e9beb06900e7e17074 Mon Sep 17 00:00:00 2001 From: stemgene Date: Tue, 26 Nov 2024 21:05:50 -0500 Subject: [PATCH 10/26] (Issue #264) Refactor: Rename "NormalizedBillingPeriodRecord" to "ProcessedEnergyBill" Co-authored-by: Ethan Strominger --- python/src/rules_engine/engine.py | 4 ++-- python/src/rules_engine/pydantic_models.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index e3f77c9..dc4d6bb 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -19,7 +19,7 @@ HeatLoadInput, HeatLoadOutput, NaturalGasBillingInput, - NormalizedBillingPeriodRecord, + ProcessedEnergyBill, ProcessedEnergyBillInput, OilPropaneBillingInput, RulesEngineResult, @@ -138,7 +138,7 @@ def get_outputs_normalized( billing_records = [] for billing_period in intermediate_billing_periods: - billing_record = NormalizedBillingPeriodRecord( + billing_record = ProcessedEnergyBill( period_start_date=billing_period.input.period_start_date, period_end_date=billing_period.input.period_end_date, usage=billing_period.input.usage, diff --git a/python/src/rules_engine/pydantic_models.py b/python/src/rules_engine/pydantic_models.py index 8d7f033..cfbf901 100644 --- a/python/src/rules_engine/pydantic_models.py +++ b/python/src/rules_engine/pydantic_models.py @@ -156,7 +156,7 @@ class ProcessedEnergyBillInput(BaseModel): inclusion_override: bool = Field(frozen=True) -class NormalizedBillingPeriodRecord(ProcessedEnergyBillInput): +class ProcessedEnergyBill(ProcessedEnergyBillInput): """ Derived class for holding a normalized billing period record. @@ -223,7 +223,7 @@ class BalancePointGraph(BaseModel): class RulesEngineResult(BaseModel): heat_load_output: HeatLoadOutput balance_point_graph: BalancePointGraph - billing_records: list[NormalizedBillingPeriodRecord] + billing_records: list[ProcessedEnergyBill] @dataclass From 39baa04f6de5a0551d489e504420a7c298e66f61 Mon Sep 17 00:00:00 2001 From: stemgene Date: Tue, 26 Nov 2024 21:10:02 -0500 Subject: [PATCH 11/26] (Issue #264) Refactor: Rename "NormalizedBillingPeriodRecord" to "ProcessedEnergyBill" Co-authored-by: Ethan Strominger --- python/src/rules_engine/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index dc4d6bb..d8d5e14 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -19,9 +19,9 @@ HeatLoadInput, HeatLoadOutput, NaturalGasBillingInput, + OilPropaneBillingInput, ProcessedEnergyBill, ProcessedEnergyBillInput, - OilPropaneBillingInput, RulesEngineResult, TemperatureInput, ) From 84bb5b60d3435ed2b09f13babb7fb6f6e9aaa62b Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:30:37 +0000 Subject: [PATCH 12/26] Update the "recommendations.json" Co-authored-by: Ethan-Strominger --- .vscode/extensions.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 67c84f4..7426882 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -7,6 +7,9 @@ "qwtel.sqlite-viewer", "yoavbls.pretty-ts-errors", "github.vscode-github-actions", - "ms-vsliveshare.vsliveshare" + "ms-vsliveshare.vsliveshare", + "ms-python.python", + "eamodio.gitlens", + "MS-vsliveshare.vsliveshare" ] } From 2c5d0b56cf34ee07581ec8f4f46d0066f532129d Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:49:37 +0000 Subject: [PATCH 13/26] Refactor: rename + setup-python.sh 1. Renamed to "IntermediateProcessedEnergyBill" 2. Created the "setup-python.sh" file. Co-authored-by: Ethan-Strominger --- python/setup-python.sh | 4 +++ python/src/rules_engine/engine.py | 16 +++++----- python/src/rules_engine/refactor.md | 4 +-- python/tests/test_rules_engine/test_engine.py | 32 +++++++++---------- 4 files changed, 30 insertions(+), 26 deletions(-) create mode 100755 python/setup-python.sh diff --git a/python/setup-python.sh b/python/setup-python.sh new file mode 100755 index 0000000..72f5432 --- /dev/null +++ b/python/setup-python.sh @@ -0,0 +1,4 @@ +python -m venv .venv +source .venv/bin/activate +pip install -e . +pip install -r requirements-dev.txt \ No newline at end of file diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index d8d5e14..8900cbd 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -162,7 +162,7 @@ def convert_to_intermediate_billing_periods( temperature_input: TemperatureInput, billing_periods: list[ProcessedEnergyBillInput], fuel_type: FuelType, -) -> list[ProcessedEnergyBillIntermediate]: +) -> list[IntermediateProcessedEnergyBill]: """ Converts temperature data and billing period inputs into internal classes used for heat loss calculations. @@ -194,7 +194,7 @@ def convert_to_intermediate_billing_periods( else: raise ValueError("Unsupported fuel type.") - intermediate_billing_period = ProcessedEnergyBillIntermediate( + intermediate_billing_period = IntermediateProcessedEnergyBill( input=billing_period, avg_temps=temperature_input.temperatures[start_idx:end_idx], usage=billing_period.usage, @@ -401,7 +401,7 @@ class Home: def _init( self, heat_load_input: HeatLoadInput, - billing_periods: list[ProcessedEnergyBillIntermediate], + billing_periods: list[IntermediateProcessedEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, ) -> None: @@ -413,7 +413,7 @@ def _init( self._initialize_billing_periods(billing_periods) def _initialize_billing_periods( - self, billing_periods: list[ProcessedEnergyBillIntermediate] + self, billing_periods: list[IntermediateProcessedEnergyBill] ) -> None: self.bills_winter = [] self.bills_summer = [] @@ -626,7 +626,7 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: def calculate( cls, heat_load_input: HeatLoadInput, - billing_periods: list[ProcessedEnergyBillIntermediate], + billing_periods: list[IntermediateProcessedEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, initial_balance_point_sensitivity: float = 0.5, @@ -656,7 +656,7 @@ def calculate( return home_instance - def initialize_ua(self, billing_period: ProcessedEnergyBillIntermediate) -> None: + def initialize_ua(self, billing_period: IntermediateProcessedEnergyBill) -> None: """ Average heating usage, partial UA, initial UA. requires that self.home have non heating usage calculated. @@ -668,7 +668,7 @@ def initialize_ua(self, billing_period: ProcessedEnergyBillIntermediate) -> None billing_period.ua = billing_period.partial_ua / billing_period.total_hdd def calculate_partial_ua( - self, billing_period: ProcessedEnergyBillIntermediate + self, billing_period: IntermediateProcessedEnergyBill ) -> float: """ The portion of UA that is not dependent on the balance point @@ -684,7 +684,7 @@ def calculate_partial_ua( ) -class ProcessedEnergyBillIntermediate: +class IntermediateProcessedEnergyBill: """ An internal class storing data whence heating usage per billing period is calculated. diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index b487523..037b529 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -13,7 +13,7 @@ home variables used 1. Remove temporary_rules_engine.py 2. Rename rules-engine to "python" 3. Rename NormalizedBillingRecordBase class to BillingInput -4. Rename BillingPeriod to ProcessedEnergyBillIntermediate and billing_period to processed_energy_bill_intermediate +4. Rename BillingPeriod to IntermediateProcessedEnergyBill and billing_period to processed_energy_bill_intermediate 5. Combine get_outputs_normalized and convert_to_intermediate_billing_record and get rid of NormalizedBillingRecord. There is only one place NormalizedBillingRecord is used and combining code gets rid of the need for the class. - Change @@ -55,7 +55,7 @@ to inputBill.start_date, inputBill.end_date ) - processedBill = ProcessedEnergyBillIntermediate( + processedBill = IntermediateProcessedEnergyBill( input = inputBill, avg_temps = avg_temps, default_analysis_type = default_analysis_type diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index ffaff67..6c54252 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -26,9 +26,9 @@ @pytest.fixture() -def sample_billing_periods() -> list[engine.ProcessedEnergyBillIntermediate]: +def sample_billing_periods() -> list[engine.IntermediateProcessedEnergyBill]: billing_periods = [ - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [28, 29, 30, 29], 50, @@ -36,7 +36,7 @@ def sample_billing_periods() -> list[engine.ProcessedEnergyBillIntermediate]: True, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [32, 35, 35, 38], 45, @@ -44,7 +44,7 @@ def sample_billing_periods() -> list[engine.ProcessedEnergyBillIntermediate]: True, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [41, 43, 42, 42], 30, @@ -52,7 +52,7 @@ def sample_billing_periods() -> list[engine.ProcessedEnergyBillIntermediate]: True, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [72, 71, 70, 69], 0.96, @@ -66,10 +66,10 @@ def sample_billing_periods() -> list[engine.ProcessedEnergyBillIntermediate]: @pytest.fixture() def sample_billing_periods_with_outlier() -> ( - list[engine.ProcessedEnergyBillIntermediate] + list[engine.IntermediateProcessedEnergyBill] ): billing_periods = [ - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [41.7, 41.6, 32, 25.4], 60, @@ -77,7 +77,7 @@ def sample_billing_periods_with_outlier() -> ( True, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [28, 29, 30, 29], 50, @@ -85,7 +85,7 @@ def sample_billing_periods_with_outlier() -> ( True, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [32, 35, 35, 38], 45, @@ -93,7 +93,7 @@ def sample_billing_periods_with_outlier() -> ( True, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [41, 43, 42, 42], 30, @@ -101,7 +101,7 @@ def sample_billing_periods_with_outlier() -> ( True, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [72, 71, 70, 69], 0.96, @@ -361,7 +361,7 @@ def test_convert_to_intermediate_billing_periods( ) expected_results = [ - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [41.7, 41.6, 32, 25.4], 60, @@ -369,7 +369,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [28, 29, 30, 29], 50, @@ -377,7 +377,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [32, 35, 35, 38], 45, @@ -385,7 +385,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [41, 43, 42, 42], 30, @@ -393,7 +393,7 @@ def test_convert_to_intermediate_billing_periods( False, False, ), - engine.ProcessedEnergyBillIntermediate( + engine.IntermediateProcessedEnergyBill( dummy_billing_period_record, [72, 71, 70, 69], 0.96, From dc8a6d2c313fb49c9882061bb8f8916e6aeeca85 Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:11:24 +0000 Subject: [PATCH 14/26] Refactor: rename Renamed to "processed_energy_bill_inputs_bill_inputs" Co-authored-by: Ethan-Strominger --- python/src/rules_engine/engine.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 8900cbd..362bcec 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -64,10 +64,10 @@ def get_outputs_natural_gas( """ Analyze the heat load for a home that is using natural gas as its current heating system fuel. """ - billing_periods: list[ProcessedEnergyBillInput] = [] + processed_energy_bill_inputs_bill_inputs: list[ProcessedEnergyBillInput] = [] for input_val in natural_gas_billing_input.records: - billing_periods.append( + processed_energy_bill_inputs_bill_inputs.append( ProcessedEnergyBillInput( period_start_date=input_val.period_start_date, period_end_date=input_val.period_end_date, @@ -77,7 +77,7 @@ def get_outputs_natural_gas( ) return get_outputs_normalized( - heat_load_input, None, temperature_input, billing_periods + heat_load_input, None, temperature_input, processed_energy_bill_inputs_bill_inputs ) From fa70e0972e5c8c3e0ace274dbac7bbf8f3cf7d10 Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Wed, 4 Dec 2024 00:35:34 +0000 Subject: [PATCH 15/26] Refactor: rename "billing_period" to "processed_energy_bill_input" Co-authored-by: Ethan-Strominger --- heat-stack/app/routes/_heat+/single.tsx | 2 +- python/src/rules_engine/engine.py | 118 +++++++++--------- python/src/rules_engine/refactor.md | 18 +-- python/tests/test_rules_engine/test_engine.py | 76 +++++------ 4 files changed, 107 insertions(+), 107 deletions(-) diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index 7a2de6b..8a5ce24 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -354,7 +354,7 @@ export async function action({ request, params }: ActionFunctionArgs) { # heat_load_input: HeatLoadInput, # dhw_input: Optional[DhwInput], # temperature_input: TemperatureInput, - # billing_periods: list[ProcessedEnergyBillInput], + # processed_energy_bill_inputs: list[ProcessedEnergyBillInput], # ) def executeRoundtripAnalyticsFromForm(summaryInputJs, temperatureInputJs, userAdjustedData, state_id, county_id): diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 362bcec..fc97049 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -36,12 +36,12 @@ def get_outputs_oil_propane( """ Analyze the heat load for a home that is using oil or propane as its current heating system fuel. """ - billing_periods: list[ProcessedEnergyBillInput] = [] + processed_energy_bill_inputs: list[ProcessedEnergyBillInput] = [] last_date = oil_propane_billing_input.preceding_delivery_date for input_val in oil_propane_billing_input.records: start_date = last_date + timedelta(days=1) - billing_periods.append( + processed_energy_bill_inputs.append( ProcessedEnergyBillInput( period_start_date=start_date, period_end_date=input_val.period_end_date, @@ -52,7 +52,7 @@ def get_outputs_oil_propane( last_date = input_val.period_end_date return get_outputs_normalized( - heat_load_input, dhw_input, temperature_input, billing_periods + heat_load_input, dhw_input, temperature_input, processed_energy_bill_inputs ) @@ -85,21 +85,21 @@ def get_outputs_normalized( heat_load_input: HeatLoadInput, dhw_input: Optional[DhwInput], temperature_input: TemperatureInput, - billing_periods: list[ProcessedEnergyBillInput], + processed_energy_bill_inputs: list[ProcessedEnergyBillInput], ) -> RulesEngineResult: """ Analyze the heat load for a home based on normalized, fuel-type-agnostic billing records. """ initial_balance_point = 60 - intermediate_billing_periods = convert_to_intermediate_billing_periods( + intermediate_processed_energy_bill_inputs = convert_to_intermediate_processed_energy_bill_inputs( temperature_input=temperature_input, - billing_periods=billing_periods, + processed_energy_bill_inputs=processed_energy_bill_inputs, fuel_type=heat_load_input.fuel_type, ) home = Home.calculate( heat_load_input=heat_load_input, - billing_periods=intermediate_billing_periods, + processed_energy_bill_inputs=intermediate_processed_energy_bill_inputs, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) @@ -137,16 +137,16 @@ def get_outputs_normalized( balance_point_graph = home.balance_point_graph billing_records = [] - for billing_period in intermediate_billing_periods: + for processed_energy_bill_input in intermediate_processed_energy_bill_inputs: billing_record = ProcessedEnergyBill( - period_start_date=billing_period.input.period_start_date, - period_end_date=billing_period.input.period_end_date, - usage=billing_period.input.usage, - inclusion_override=billing_period.input.inclusion_override, - analysis_type=billing_period.analysis_type, - default_inclusion=billing_period.default_inclusion, - eliminated_as_outlier=billing_period.eliminated_as_outlier, - whole_home_heat_loss_rate=billing_period.ua, + period_start_date=processed_energy_bill_input.input.period_start_date, + period_end_date=processed_energy_bill_input.input.period_end_date, + usage=processed_energy_bill_input.input.usage, + inclusion_override=processed_energy_bill_input.input.inclusion_override, + analysis_type=processed_energy_bill_input.analysis_type, + default_inclusion=processed_energy_bill_input.default_inclusion, + eliminated_as_outlier=processed_energy_bill_input.eliminated_as_outlier, + whole_home_heat_loss_rate=processed_energy_bill_input.ua, ) billing_records.append(billing_record) @@ -158,9 +158,9 @@ def get_outputs_normalized( return result -def convert_to_intermediate_billing_periods( +def convert_to_intermediate_processed_energy_bill_inputs( temperature_input: TemperatureInput, - billing_periods: list[ProcessedEnergyBillInput], + processed_energy_bill_inputs: list[ProcessedEnergyBillInput], fuel_type: FuelType, ) -> list[IntermediateProcessedEnergyBill]: """ @@ -170,41 +170,41 @@ def convert_to_intermediate_billing_periods( """ # Build a list of lists of temperatures, where each list of temperatures contains all the temperatures # in the corresponding billing period - intermediate_billing_periods = [] + intermediate_processed_energy_bill_inputs = [] default_inclusion = False - for billing_period in billing_periods: + for processed_energy_bill_input in processed_energy_bill_inputs: # the HEAT Excel sheet is inclusive of the temperatures that fall on both the start and end dates start_idx = bisect.bisect_left( - temperature_input.dates, billing_period.period_start_date + temperature_input.dates, processed_energy_bill_input.period_start_date ) end_idx = ( - bisect.bisect_left(temperature_input.dates, billing_period.period_end_date) + bisect.bisect_left(temperature_input.dates, processed_energy_bill_input.period_end_date) + 1 ) if fuel_type == FuelType.GAS: analysis_type, default_inclusion = _date_to_analysis_type_natural_gas( - billing_period.period_end_date + processed_energy_bill_input.period_end_date ) elif fuel_type == FuelType.OIL or fuel_type == FuelType.PROPANE: analysis_type, default_inclusion = _date_to_analysis_type_oil_propane( - billing_period.period_start_date, billing_period.period_end_date + processed_energy_bill_input.period_start_date, processed_energy_bill_input.period_end_date ) else: raise ValueError("Unsupported fuel type.") - intermediate_billing_period = IntermediateProcessedEnergyBill( - input=billing_period, + intermediate_processed_energy_bill_input = IntermediateProcessedEnergyBill( + input=processed_energy_bill_input, avg_temps=temperature_input.temperatures[start_idx:end_idx], - usage=billing_period.usage, + usage=processed_energy_bill_input.usage, analysis_type=analysis_type, default_inclusion=default_inclusion, - inclusion_override=billing_period.inclusion_override, + inclusion_override=processed_energy_bill_input.inclusion_override, ) - intermediate_billing_periods.append(intermediate_billing_period) + intermediate_processed_energy_bill_inputs.append(intermediate_processed_energy_bill_input) - return intermediate_billing_periods + return intermediate_processed_energy_bill_inputs def _date_to_analysis_type_oil_propane( @@ -401,7 +401,7 @@ class Home: def _init( self, heat_load_input: HeatLoadInput, - billing_periods: list[IntermediateProcessedEnergyBill], + processed_energy_bill_inputs: list[IntermediateProcessedEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, ) -> None: @@ -410,18 +410,18 @@ def _init( self.thermostat_set_point = heat_load_input.thermostat_set_point self.balance_point = initial_balance_point self.dhw_input = dhw_input - self._initialize_billing_periods(billing_periods) + self._initialize_processed_energy_bill_inputs(processed_energy_bill_inputs) - def _initialize_billing_periods( - self, billing_periods: list[IntermediateProcessedEnergyBill] + def _initialize_processed_energy_bill_inputs( + self, processed_energy_bill_inputs: list[IntermediateProcessedEnergyBill] ) -> None: self.bills_winter = [] self.bills_summer = [] self.bills_shoulder = [] # winter months 1 (ALLOWED_HEATING_USAGE); summer months -1 (ALLOWED_NON_HEATING_USAGE); shoulder months 0 (NOT_ALLOWED...) - for billing_period in billing_periods: - billing_period.set_initial_balance_point(self.balance_point) + for processed_energy_bill_input in processed_energy_bill_inputs: + processed_energy_bill_input.set_initial_balance_point(self.balance_point) """ The UI depicts billing period usage as several distinctive icons on the left hand column of the screen; "analysis_type" @@ -431,17 +431,17 @@ def _initialize_billing_periods( The following code implements this algorithm and adds bills accordingly to winter, summer, or shoulder (i.e. excluded) lists """ - _analysis_type = billing_period.analysis_type - _default_inclusion = billing_period.default_inclusion + _analysis_type = processed_energy_bill_input.analysis_type + _default_inclusion = processed_energy_bill_input.default_inclusion # Only bills deemed ALLOWED by the AnalysisType algorithm can be included/excluded by the user # if ( # _analysis_type == AnalysisType.ALLOWED_HEATING_USAGE # or _analysis_type == AnalysisType.ALLOWED_NON_HEATING_USAGE # ): - # if billing_period.inclusion_override: + # if processed_energy_bill_input.inclusion_override: # # The user has requested we override an inclusion algorithm decision - # if billing_period.winter_cusp_month == True: + # if processed_energy_bill_input.winter_cusp_month == True: # # This bill is on the cusp of winter; the user has requested we include it # _analysis_type = AnalysisType.ALLOWED_HEATING_USAGE # else: @@ -449,31 +449,31 @@ def _initialize_billing_periods( # _analysis_type = AnalysisType.NOT_ALLOWED_IN_CALCULATIONS # else: # # The user has chosen to not override our automatic calculations, even for a winter cusp month - # if billing_period.winter_cusp_month == True: + # if processed_energy_bill_input.winter_cusp_month == True: # _analysis_type = AnalysisType.NOT_ALLOWED_IN_CALCULATIONS # Assign the bill to the appropriate list for winter or summer calculations - if billing_period.inclusion_override: + if processed_energy_bill_input.inclusion_override: _default_inclusion = not _default_inclusion if ( _analysis_type == AnalysisType.ALLOWED_HEATING_USAGE and _default_inclusion ): - self.bills_winter.append(billing_period) + self.bills_winter.append(processed_energy_bill_input) elif ( _analysis_type == AnalysisType.ALLOWED_NON_HEATING_USAGE and _default_inclusion ): - self.bills_summer.append(billing_period) + self.bills_summer.append(processed_energy_bill_input) else: # the rest are excluded from calculations - self.bills_shoulder.append(billing_period) + self.bills_shoulder.append(processed_energy_bill_input) self._calculate_avg_summer_usage() self._calculate_avg_non_heating_usage() - for billing_period in self.bills_winter: - self.initialize_ua(billing_period) + for processed_energy_bill_input in self.bills_winter: + self.initialize_ua(processed_energy_bill_input) def _calculate_avg_summer_usage(self) -> None: """ @@ -516,7 +516,7 @@ def _calculate_balance_point_and_ua( self.balance_point_graph = BalancePointGraph(records=[]) - self.uas = [billing_period.ua for billing_period in self.bills_winter] + self.uas = [processed_energy_bill_input.ua for processed_energy_bill_input in self.bills_winter] self.avg_ua = sts.mean(self.uas) self.stdev_pct = sts.pstdev(self.uas) / self.avg_ua @@ -540,7 +540,7 @@ def _calculate_balance_point_and_ua( biggest_outlier_idx ) # removes the biggest outlier outlier.eliminated_as_outlier = True - uas_i = [billing_period.ua for billing_period in self.bills_winter] + uas_i = [processed_energy_bill_input.ua for processed_energy_bill_input in self.bills_winter] avg_ua_i = sts.mean(uas_i) stdev_pct_i = sts.pstdev(uas_i) / avg_ua_i if ( @@ -626,7 +626,7 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: def calculate( cls, heat_load_input: HeatLoadInput, - billing_periods: list[IntermediateProcessedEnergyBill], + processed_energy_bill_inputs: list[IntermediateProcessedEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, initial_balance_point_sensitivity: float = 0.5, @@ -642,7 +642,7 @@ def calculate( home_instance = object.__new__(cls) home_instance._init( heat_load_input=heat_load_input, - billing_periods=billing_periods, + processed_energy_bill_inputs=processed_energy_bill_inputs, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) @@ -656,26 +656,26 @@ def calculate( return home_instance - def initialize_ua(self, billing_period: IntermediateProcessedEnergyBill) -> None: + def initialize_ua(self, processed_energy_bill_input: IntermediateProcessedEnergyBill) -> None: """ Average heating usage, partial UA, initial UA. requires that self.home have non heating usage calculated. """ - billing_period.avg_heating_usage = ( - billing_period.usage / billing_period.days + processed_energy_bill_input.avg_heating_usage = ( + processed_energy_bill_input.usage / processed_energy_bill_input.days ) - self.avg_non_heating_usage - billing_period.partial_ua = self.calculate_partial_ua(billing_period) - billing_period.ua = billing_period.partial_ua / billing_period.total_hdd + processed_energy_bill_input.partial_ua = self.calculate_partial_ua(processed_energy_bill_input) + processed_energy_bill_input.ua = processed_energy_bill_input.partial_ua / processed_energy_bill_input.total_hdd def calculate_partial_ua( - self, billing_period: IntermediateProcessedEnergyBill + self, processed_energy_bill_input: IntermediateProcessedEnergyBill ) -> float: """ The portion of UA that is not dependent on the balance point """ return ( - billing_period.days - * billing_period.avg_heating_usage # gallons or therms + processed_energy_bill_input.days + * processed_energy_bill_input.avg_heating_usage # gallons or therms * self.fuel_type.value # therm or gallon to BTU * self.heat_sys_efficiency # unitless / 24 diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index 037b529..bdf48d3 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -13,15 +13,15 @@ home variables used 1. Remove temporary_rules_engine.py 2. Rename rules-engine to "python" 3. Rename NormalizedBillingRecordBase class to BillingInput -4. Rename BillingPeriod to IntermediateProcessedEnergyBill and billing_period to processed_energy_bill_intermediate +4. Rename BillingPeriod to IntermediateProcessedEnergyBill and processed_energy_bill_input to processed_energy_bill_intermediate 5. Combine get_outputs_normalized and convert_to_intermediate_billing_record and get rid of NormalizedBillingRecord. There is only one place NormalizedBillingRecord is used and combining code gets rid of the need for the class. - Change ``` - billing_periods: list[ProcessedEnergyBillInput] = [] + processed_energy_bill_inputs: list[ProcessedEnergyBillInput] = [] for input_val in natural_gas_billing_input.records: - billing_periods.append( + processed_energy_bill_inputs.append( ProcessedEnergyBillInput( period_start_date=input_val.period_start_date, period_end_date=input_val.period_end_date, @@ -31,11 +31,11 @@ gets rid of the need for the class. ) return get_outputs_normalized( - heat_load_input, None, temperature_input, billing_periods + heat_load_input, None, temperature_input, processed_energy_bill_inputs ) def get_outputs_normalized - loops through billing_periods and does a bunch of stuff + loops through processed_energy_bill_inputs and does a bunch of stuff ``` to @@ -93,12 +93,12 @@ avg_non_heating_usage = _get_avg_non_heating_usage ( ``` ================== - change -`for billing_period in billing_periods ...` => +`for processed_energy_bill_input in processed_energy_bill_inputs ...` => to ``` -for billing_period in billing_periods +for processed_energy_bill_input in processed_energy_bill_inputs { bills_summer, bills_winter, bills_shoulder } - =_categorize_bills_by_season (billing_periods) + =_categorize_bills_by_season (processed_energy_bill_inputs) ``` ================== - Change @@ -116,7 +116,7 @@ to ``` ================== - Change -`self.initialize_ua(billing_period)` => `_set_ua(billing_period,avg_non_heating_usage)` +`self.initialize_ua(processed_energy_bill_input)` => `_set_ua(processed_energy_bill_input,avg_non_heating_usage)` - Change?? Parameters are never set ``` diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 6c54252..b77b189 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -17,7 +17,7 @@ TemperatureInput, ) -dummy_billing_period_record = ProcessedEnergyBillInput( +dummy_processed_energy_bill_input_record = ProcessedEnergyBillInput( period_start_date=datetime(2024, 1, 1), period_end_date=datetime(2024, 2, 1), usage=1.0, @@ -26,10 +26,10 @@ @pytest.fixture() -def sample_billing_periods() -> list[engine.IntermediateProcessedEnergyBill]: - billing_periods = [ +def sample_processed_energy_bill_inputs() -> list[engine.IntermediateProcessedEnergyBill]: + processed_energy_bill_inputs = [ engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [28, 29, 30, 29], 50, AnalysisType.ALLOWED_HEATING_USAGE, @@ -37,7 +37,7 @@ def sample_billing_periods() -> list[engine.IntermediateProcessedEnergyBill]: False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [32, 35, 35, 38], 45, AnalysisType.ALLOWED_HEATING_USAGE, @@ -45,7 +45,7 @@ def sample_billing_periods() -> list[engine.IntermediateProcessedEnergyBill]: False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [41, 43, 42, 42], 30, AnalysisType.ALLOWED_HEATING_USAGE, @@ -53,7 +53,7 @@ def sample_billing_periods() -> list[engine.IntermediateProcessedEnergyBill]: False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [72, 71, 70, 69], 0.96, AnalysisType.NOT_ALLOWED_IN_CALCULATIONS, @@ -61,16 +61,16 @@ def sample_billing_periods() -> list[engine.IntermediateProcessedEnergyBill]: False, ), ] - return billing_periods + return processed_energy_bill_inputs @pytest.fixture() -def sample_billing_periods_with_outlier() -> ( +def sample_processed_energy_bill_inputs_with_outlier() -> ( list[engine.IntermediateProcessedEnergyBill] ): - billing_periods = [ + processed_energy_bill_inputs = [ engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [41.7, 41.6, 32, 25.4], 60, AnalysisType.ALLOWED_HEATING_USAGE, @@ -78,7 +78,7 @@ def sample_billing_periods_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [28, 29, 30, 29], 50, AnalysisType.ALLOWED_HEATING_USAGE, @@ -86,7 +86,7 @@ def sample_billing_periods_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [32, 35, 35, 38], 45, AnalysisType.ALLOWED_HEATING_USAGE, @@ -94,7 +94,7 @@ def sample_billing_periods_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [41, 43, 42, 42], 30, AnalysisType.ALLOWED_HEATING_USAGE, @@ -102,7 +102,7 @@ def sample_billing_periods_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [72, 71, 70, 69], 0.96, AnalysisType.NOT_ALLOWED_IN_CALCULATIONS, @@ -111,7 +111,7 @@ def sample_billing_periods_with_outlier() -> ( ), ] - return billing_periods + return processed_energy_bill_inputs @pytest.fixture() @@ -192,8 +192,8 @@ def sample_temp_inputs() -> TemperatureInput: @pytest.fixture() -def sample_normalized_billing_periods() -> list[ProcessedEnergyBillInput]: - billing_periods_dict: Any = [ +def sample_normalized_processed_energy_bill_inputs() -> list[ProcessedEnergyBillInput]: + processed_energy_bill_inputs_dict: Any = [ { "period_start_date": "2022-12-01", "period_end_date": "2022-12-04", @@ -238,21 +238,21 @@ def sample_normalized_billing_periods() -> list[ProcessedEnergyBillInput]: }, ] - # billing_periods = [ - # ProcessedEnergyBillInput(**x) for x in billing_periods_dict + # processed_energy_bill_inputs = [ + # ProcessedEnergyBillInput(**x) for x in processed_energy_bill_inputs_dict # ] - billing_periods = [ + processed_energy_bill_inputs = [ ProcessedEnergyBillInput( period_start_date=datetime.fromisoformat(x["period_start_date"]), period_end_date=datetime.fromisoformat(x["period_end_date"]), usage=x["usage"], inclusion_override=x["inclusion_override"], ) - for x in billing_periods_dict + for x in processed_energy_bill_inputs_dict ] - return billing_periods + return processed_energy_bill_inputs @pytest.mark.parametrize( @@ -314,10 +314,10 @@ def test_get_average_indoor_temperature(): assert engine.get_average_indoor_temperature(set_temp, setback, setback_hrs) == 66 -def test_bp_ua_estimates(sample_summary_inputs, sample_billing_periods): +def test_bp_ua_estimates(sample_summary_inputs, sample_processed_energy_bill_inputs): home = engine.Home.calculate( sample_summary_inputs, - sample_billing_periods, + sample_processed_energy_bill_inputs, dhw_input=None, initial_balance_point=58, ) @@ -332,10 +332,10 @@ def test_bp_ua_estimates(sample_summary_inputs, sample_billing_periods): assert home.stdev_pct == approx(0.0463, abs=0.01) -def test_bp_ua_with_outlier(sample_summary_inputs, sample_billing_periods_with_outlier): +def test_bp_ua_with_outlier(sample_summary_inputs, sample_processed_energy_bill_inputs_with_outlier): home = engine.Home.calculate( sample_summary_inputs, - sample_billing_periods_with_outlier, + sample_processed_energy_bill_inputs_with_outlier, dhw_input=None, initial_balance_point=58, ) @@ -351,18 +351,18 @@ def test_bp_ua_with_outlier(sample_summary_inputs, sample_billing_periods_with_o assert home.stdev_pct == approx(0.0463, abs=0.01) -def test_convert_to_intermediate_billing_periods( - sample_temp_inputs, sample_normalized_billing_periods +def test_convert_to_intermediate_processed_energy_bill_inputs( + sample_temp_inputs, sample_normalized_processed_energy_bill_inputs ): - results = engine.convert_to_intermediate_billing_periods( + results = engine.convert_to_intermediate_processed_energy_bill_inputs( sample_temp_inputs, - sample_normalized_billing_periods, + sample_normalized_processed_energy_bill_inputs, FuelType.GAS, ) expected_results = [ engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [41.7, 41.6, 32, 25.4], 60, AnalysisType.ALLOWED_HEATING_USAGE, @@ -370,7 +370,7 @@ def test_convert_to_intermediate_billing_periods( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [28, 29, 30, 29], 50, AnalysisType.ALLOWED_HEATING_USAGE, @@ -378,7 +378,7 @@ def test_convert_to_intermediate_billing_periods( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [32, 35, 35, 38], 45, AnalysisType.ALLOWED_HEATING_USAGE, @@ -386,7 +386,7 @@ def test_convert_to_intermediate_billing_periods( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [41, 43, 42, 42], 30, AnalysisType.ALLOWED_HEATING_USAGE, @@ -394,7 +394,7 @@ def test_convert_to_intermediate_billing_periods( False, ), engine.IntermediateProcessedEnergyBill( - dummy_billing_period_record, + dummy_processed_energy_bill_input_record, [72, 71, 70, 69], 0.96, AnalysisType.ALLOWED_HEATING_USAGE, @@ -413,13 +413,13 @@ def test_convert_to_intermediate_billing_periods( def test_get_outputs_normalized( - sample_summary_inputs, sample_temp_inputs, sample_normalized_billing_periods + sample_summary_inputs, sample_temp_inputs, sample_normalized_processed_energy_bill_inputs ): rules_engine_result = engine.get_outputs_normalized( sample_summary_inputs, None, sample_temp_inputs, - sample_normalized_billing_periods, + sample_normalized_processed_energy_bill_inputs, ) assert rules_engine_result.heat_load_output.estimated_balance_point == 60.5 From a6778ee4368dd8dcea6faabf6ca0713e30d6ca8d Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Wed, 4 Dec 2024 00:37:56 +0000 Subject: [PATCH 16/26] Refactor: rename "billing_record" to "processed_energy_bill" Co-authored-by: Ethan-Strominger Co-authored-by: AdamFinkle --- .../CaseSummaryComponents/AnalysisHeader.tsx | 4 +-- .../EnergyUseHistoryChart.tsx | 4 +-- heat-stack/app/routes/_heat+/single.tsx | 32 +++++++++---------- heat-stack/app/utils/pyodide.test.ts | 2 +- heat-stack/types/index.ts | 4 +-- python/src/rules_engine/engine.py | 8 ++--- python/src/rules_engine/pydantic_models.py | 2 +- python/src/rules_engine/refactor.md | 2 +- .../generate_example_data.py | 4 +-- python/tests/test_rules_engine/test_engine.py | 6 ++-- .../test_rules_engine/test_natural_gas.py | 4 +-- 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx index 049ecc9..b82a1b7 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/AnalysisHeader.tsx @@ -36,10 +36,10 @@ export function AnalysisHeader({ usage_data }: { usage_data: UsageDataSchema}) { // Extract the heat_load_output from usage_data const summaryOutputs = usage_data?.heat_load_output; - const totalRecords = usage_data?.billing_records?.length || "-" + const totalRecords = usage_data?.processed_energy_bills?.length || "-" // Calculate the number of billing periods included in Heating calculations - const heatingAnalysisTypeRecords = usage_data?.billing_records?.filter( + const heatingAnalysisTypeRecords = usage_data?.processed_energy_bills?.filter( (billingRecord) => billingRecord.analysis_type === 1, // Do wee need this code instead? (billingRecord) => billingRecord.analysis_type !== "NOT_ALLOWED_IN_CALCULATIONS", ); diff --git a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx index 1c440be..40e3c51 100644 --- a/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx +++ b/heat-stack/app/components/ui/heat/CaseSummaryComponents/EnergyUseHistoryChart.tsx @@ -59,9 +59,9 @@ export function EnergyUseHistoryChart({ usage_data }: { usage_data: UsageDataSch const [billingRecords, setBillingRecords] = useState([]) useEffect(() => { - if (usage_data?.billing_records) { + if (usage_data?.processed_energy_bills) { // Process the billing records directly without converting from Map - setBillingRecords(usage_data.billing_records) + setBillingRecords(usage_data.processed_energy_bills) } }, [usage_data]) diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index 8a5ce24..9ab9c41 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -335,7 +335,7 @@ export async function action({ request, params }: ActionFunctionArgs) { // type Analytics = z.infer; const foo: any = executeGetAnalyticsFromFormJs(parsedAndValidatedFormSchema, convertedDatesTIWD, uploadedTextFile, state_id, county_id).toJs() - //console.log("foo billing records [0]", foo.get('billing_records')[0] ) + //console.log("foo billing records [0]", foo.get('processed_energy_bills')[0] ) /** * second time and after, when table is modified, this becomes entrypoint @@ -359,7 +359,7 @@ export async function action({ request, params }: ActionFunctionArgs) { def executeRoundtripAnalyticsFromForm(summaryInputJs, temperatureInputJs, userAdjustedData, state_id, county_id): """ - "billing_records" is the "roundtripping" parameter to be passed as userAdjustedData. + "processed_energy_bills" is the "roundtripping" parameter to be passed as userAdjustedData. """ summaryInputFromJs = summaryInputJs.as_object_map().values()._mapping @@ -372,12 +372,12 @@ export async function action({ request, params }: ActionFunctionArgs) { temperatureInput = TemperatureInput(**temperatureInputFromJs) # third step, re-run of the table data - userAdjustedDataFromJsToPython = [ProcessedEnergyBillInput(**record) for record in userAdjustedData['billing_records'] ] + userAdjustedDataFromJsToPython = [ProcessedEnergyBillInput(**record) for record in userAdjustedData['processed_energy_bills'] ] # print("py", userAdjustedDataFromJsToPython[0]) outputs2 = engine.get_outputs_normalized(summaryInput, None, temperatureInput, userAdjustedDataFromJsToPython) - # print("py2", outputs2.billing_records[0]) + # print("py2", outputs2.processed_energy_bills[0]) return outputs2.model_dump(mode="json") executeRoundtripAnalyticsFromForm `) @@ -390,7 +390,7 @@ Traceback (most recent call last): File "", line 32, */ /* For - 'billing_records' => [ + 'processed_energy_bills' => [ Map(9) { 'period_start_date' => '2020-10-02', 'period_end_date' => '2020-11-04', @@ -403,22 +403,22 @@ Traceback (most recent call last): File "", line 32, 'whole_home_heat_loss_rate' => undefined }, */ - const gasBillDataWithUserAdjustments = foo; /* billing_records is untested here */ + const gasBillDataWithUserAdjustments = foo; /* processed_energy_bills is untested here */ - const billingRecords = foo.get('billing_records') + const billingRecords = foo.get('processed_energy_bills') billingRecords.forEach((record: any) => { record.set('inclusion_override', true); }); - // foo.set('billing_records', null) - // foo.set('billing_records', billingRecords) - //console.log("(after customization) gasBillDataWithUserAdjustments billing records[0]", gasBillDataWithUserAdjustments.get('billing_records')[0]) + // foo.set('processed_energy_bills', null) + // foo.set('processed_energy_bills', billingRecords) + //console.log("(after customization) gasBillDataWithUserAdjustments billing records[0]", gasBillDataWithUserAdjustments.get('processed_energy_bills')[0]) /* why is inclusion_override still false after roundtrip */ const foo2: any = executeRoundtripAnalyticsFromFormJs(parsedAndValidatedFormSchema, convertedDatesTIWD, gasBillDataWithUserAdjustments, state_id, county_id).toJs() - // console.log("foo2 billing records[0]", foo2.get('billing_records')[0]); + // console.log("foo2 billing records[0]", foo2.get('processed_energy_bills')[0]); // console.log("foo2", foo2); - // console.log("(after round trip) gasBillDataWithUserAdjustments billing records[0]", gasBillDataWithUserAdjustments.get('billing_records')[0]) + // console.log("(after round trip) gasBillDataWithUserAdjustments billing records[0]", gasBillDataWithUserAdjustments.get('processed_energy_bills')[0]) // const otherResult = executePy(summaryInput, convertedDatesTIWD, exampleNationalGridCSV); @@ -503,15 +503,15 @@ export default function Inputs() { /** * Where temp1 is a temporary variable with the main Map of Maps (or undefined if page not yet submitted). - * temp1.get('billing_records') + * temp1.get('processed_energy_bills') * Array(25) [ Map(9), Map(9), Map(9), Map(9), Map(9), Map(9), Map(9), Map(9), Map(9), Map(9), … ] - * temp1.get('billing_records')[0] + * temp1.get('processed_energy_bills')[0] * Map(9) { period_start_date → "2020-10-02", period_end_date → "2020-11-04", usage → 29, analysis_type_override → null, inclusion_override → true, analysis_type → 0, default_inclusion_by_calculation → false, eliminated_as_outlier → false, whole_home_heat_loss_rate → null } - * temp1.get('billing_records')[0].get('period_start_date') + * temp1.get('processed_energy_bills')[0].get('period_start_date') * "2020-10-02" */ /* @ts-ignore */ - // console.log("EnergyUseHistoryChart table data", lastResult !== undefined ? JSON.parse(lastResult.data, reviver)?.get('billing_records'): undefined) + // console.log("EnergyUseHistoryChart table data", lastResult !== undefined ? JSON.parse(lastResult.data, reviver)?.get('processed_energy_bills'): undefined) /** * Where temp1 is a temporary variable with the main Map of Maps (or undefined if page not yet submitted). diff --git a/heat-stack/app/utils/pyodide.test.ts b/heat-stack/app/utils/pyodide.test.ts index 315d793..197fce8 100644 --- a/heat-stack/app/utils/pyodide.test.ts +++ b/heat-stack/app/utils/pyodide.test.ts @@ -275,7 +275,7 @@ test('pyodide solves climate change', async () => { console.log(result.toJs().get('balance_point_graph')) /* prettify-ignore */ - const expectedRecordsToGoInTheTable = '{"dataType":"Map","value":[["heat_load_output",{"dataType":"Map","value":[["estimated_balance_point",59.5],["other_fuel_usage",8.666666666666666],["average_indoor_temperature",68],["difference_between_ti_and_tbp",8.5],["design_temperature",9.5],["whole_home_heat_loss_rate",47972.03453453454],["standard_deviation_of_heat_loss_rate",0.07742772585617895],["average_heat_load",2494545.795795796],["maximum_heat_load",2902308.0893393396]]}],["balance_point_graph",{"dataType":"Map","value":[["records",[{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",41034.85407876231],["change_in_heat_loss_rate",0],["percent_change_in_heat_loss_rate",0],["standard_deviation",0.3967358807600794]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",38592.303240740745],["change_in_heat_loss_rate",-2442.550838021569],["percent_change_in_heat_loss_rate",-6.32911392405064],["standard_deviation",0.39673588076007943]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",43807.47935435436],["change_in_heat_loss_rate",2772.625275592043],["percent_change_in_heat_loss_rate",6.329113924050622],["standard_deviation",0.3967358807600795]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",42226.71012849585],["change_in_heat_loss_rate",-2672.576590411132],["percent_change_in_heat_loss_rate",-6.329113924050639],["standard_deviation",0.30164495413734566]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",47933.022308022315],["change_in_heat_loss_rate",3033.7355891153347],["percent_change_in_heat_loss_rate",6.3291139240506284],["standard_deviation",0.3016449541373457]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",46671.62698412699],["change_in_heat_loss_rate",-2953.9004420333513],["percent_change_in_heat_loss_rate",-6.329113924050628],["standard_deviation",0.15298851745396608]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",52978.60360360361],["change_in_heat_loss_rate",3353.0761774432685],["percent_change_in_heat_loss_rate",6.329113924050636],["standard_deviation",0.1529885174539661]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",44137.56613756614],["change_in_heat_loss_rate",-2793.516844149759],["percent_change_in_heat_loss_rate",-6.329113924050642],["standard_deviation",0.10782787516463575]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",53732.689210950084],["change_in_heat_loss_rate",3630.587108847976],["percent_change_in_heat_loss_rate",6.756756756756753],["standard_deviation",0.10782787516463577]]},{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",44935.829817158934],["change_in_heat_loss_rate",-3036.2047173756073],["percent_change_in_heat_loss_rate",-6.756756756756764],["standard_deviation",0.07742772585617896]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",51448.26892109501],["change_in_heat_loss_rate",3476.2343865604707],["percent_change_in_heat_loss_rate",6.756756756756752],["standard_deviation",0.07742772585617896]]}]]]}],["billing_records",[{"dataType":"Map","value":[["period_start_date","2020-10-02"],["period_end_date","2020-11-04"],["usage",29],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2020-11-05"],["period_end_date","2020-12-03"],["usage",36],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2020-12-04"],["period_end_date","2021-01-07"],["usage",97],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-01-08"],["period_end_date","2021-02-05"],["usage",105],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-02-06"],["period_end_date","2021-03-05"],["usage",98],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-03-06"],["period_end_date","2021-04-06"],["usage",66],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-04-07"],["period_end_date","2021-05-05"],["usage",22],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-05-06"],["period_end_date","2021-06-07"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-06-08"],["period_end_date","2021-07-06"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-07-07"],["period_end_date","2021-08-04"],["usage",10],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-08-05"],["period_end_date","2021-09-08"],["usage",11],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-09-09"],["period_end_date","2021-10-05"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-10-06"],["period_end_date","2021-11-03"],["usage",13],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-11-04"],["period_end_date","2021-12-06"],["usage",41],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2021-12-07"],["period_end_date","2022-01-05"],["usage",86],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-01-06"],["period_end_date","2022-02-03"],["usage",132],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-02-04"],["period_end_date","2022-03-07"],["usage",116],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-03-08"],["period_end_date","2022-04-04"],["usage",49],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-04-05"],["period_end_date","2022-05-05"],["usage",39],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-05-06"],["period_end_date","2022-06-06"],["usage",20],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-06-07"],["period_end_date","2022-07-05"],["usage",9],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-07-06"],["period_end_date","2022-08-03"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-08-04"],["period_end_date","2022-09-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-09-04"],["period_end_date","2022-10-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-10-04"],["period_end_date","2022-11-03"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]}]]]}' + const expectedRecordsToGoInTheTable = '{"dataType":"Map","value":[["heat_load_output",{"dataType":"Map","value":[["estimated_balance_point",59.5],["other_fuel_usage",8.666666666666666],["average_indoor_temperature",68],["difference_between_ti_and_tbp",8.5],["design_temperature",9.5],["whole_home_heat_loss_rate",47972.03453453454],["standard_deviation_of_heat_loss_rate",0.07742772585617895],["average_heat_load",2494545.795795796],["maximum_heat_load",2902308.0893393396]]}],["balance_point_graph",{"dataType":"Map","value":[["records",[{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",41034.85407876231],["change_in_heat_loss_rate",0],["percent_change_in_heat_loss_rate",0],["standard_deviation",0.3967358807600794]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",38592.303240740745],["change_in_heat_loss_rate",-2442.550838021569],["percent_change_in_heat_loss_rate",-6.32911392405064],["standard_deviation",0.39673588076007943]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",43807.47935435436],["change_in_heat_loss_rate",2772.625275592043],["percent_change_in_heat_loss_rate",6.329113924050622],["standard_deviation",0.3967358807600795]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",42226.71012849585],["change_in_heat_loss_rate",-2672.576590411132],["percent_change_in_heat_loss_rate",-6.329113924050639],["standard_deviation",0.30164495413734566]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",47933.022308022315],["change_in_heat_loss_rate",3033.7355891153347],["percent_change_in_heat_loss_rate",6.3291139240506284],["standard_deviation",0.3016449541373457]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",46671.62698412699],["change_in_heat_loss_rate",-2953.9004420333513],["percent_change_in_heat_loss_rate",-6.329113924050628],["standard_deviation",0.15298851745396608]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",52978.60360360361],["change_in_heat_loss_rate",3353.0761774432685],["percent_change_in_heat_loss_rate",6.329113924050636],["standard_deviation",0.1529885174539661]]},{"dataType":"Map","value":[["balance_point",60.5],["heat_loss_rate",44137.56613756614],["change_in_heat_loss_rate",-2793.516844149759],["percent_change_in_heat_loss_rate",-6.329113924050642],["standard_deviation",0.10782787516463575]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59.5],["heat_loss_rate",50102.10210210211],["change_in_heat_loss_rate",3171.0191203862123],["percent_change_in_heat_loss_rate",6.329113924050639],["standard_deviation",0.10782787516463574]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",53732.689210950084],["change_in_heat_loss_rate",3630.587108847976],["percent_change_in_heat_loss_rate",6.756756756756753],["standard_deviation",0.10782787516463577]]},{"dataType":"Map","value":[["balance_point",60],["heat_loss_rate",44935.829817158934],["change_in_heat_loss_rate",-3036.2047173756073],["percent_change_in_heat_loss_rate",-6.756756756756764],["standard_deviation",0.07742772585617896]]},{"dataType":"Map","value":[["balance_point",59],["heat_loss_rate",51448.26892109501],["change_in_heat_loss_rate",3476.2343865604707],["percent_change_in_heat_loss_rate",6.756756756756752],["standard_deviation",0.07742772585617896]]}]]]}],["processed_energy_bills",[{"dataType":"Map","value":[["period_start_date","2020-10-02"],["period_end_date","2020-11-04"],["usage",29],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2020-11-05"],["period_end_date","2020-12-03"],["usage",36],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2020-12-04"],["period_end_date","2021-01-07"],["usage",97],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-01-08"],["period_end_date","2021-02-05"],["usage",105],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-02-06"],["period_end_date","2021-03-05"],["usage",98],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-03-06"],["period_end_date","2021-04-06"],["usage",66],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-04-07"],["period_end_date","2021-05-05"],["usage",22],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-05-06"],["period_end_date","2021-06-07"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-06-08"],["period_end_date","2021-07-06"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-07-07"],["period_end_date","2021-08-04"],["usage",10],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-08-05"],["period_end_date","2021-09-08"],["usage",11],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-09-09"],["period_end_date","2021-10-05"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-10-06"],["period_end_date","2021-11-03"],["usage",13],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2021-11-04"],["period_end_date","2021-12-06"],["usage",41],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2021-12-07"],["period_end_date","2022-01-05"],["usage",86],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-01-06"],["period_end_date","2022-02-03"],["usage",132],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-02-04"],["period_end_date","2022-03-07"],["usage",116],["analysis_type_override",null],["inclusion_override",false],["analysis_type",1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",true]]},{"dataType":"Map","value":[["period_start_date","2022-03-08"],["period_end_date","2022-04-04"],["usage",49],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-04-05"],["period_end_date","2022-05-05"],["usage",39],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-05-06"],["period_end_date","2022-06-06"],["usage",20],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-06-07"],["period_end_date","2022-07-05"],["usage",9],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-07-06"],["period_end_date","2022-08-03"],["usage",7],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-08-04"],["period_end_date","2022-09-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",-1],["default_inclusion_by_calculation",true],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-09-04"],["period_end_date","2022-10-03"],["usage",8],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]},{"dataType":"Map","value":[["period_start_date","2022-10-04"],["period_end_date","2022-11-03"],["usage",19],["analysis_type_override",null],["inclusion_override",false],["analysis_type",0],["default_inclusion_by_calculation",false],["eliminated_as_outlier",false]]}]]]}' // how you do "dir()"" in python // console.log(Object.getOwnPropertyNames(result.toJs())); diff --git a/heat-stack/types/index.ts b/heat-stack/types/index.ts index cd39945..96910f5 100644 --- a/heat-stack/types/index.ts +++ b/heat-stack/types/index.ts @@ -121,12 +121,12 @@ export const oneBillingRecordSchema = z.object({ whole_home_heat_loss_rate: z.number(), }); -// Define the schema for the 'billing_records' list +// Define the schema for the 'processed_energy_bills' list export const allBillingRecordsSchema = z.array(oneBillingRecordSchema); // Define the schema for the 'usage_data' key export const usageDataSchema = z.object({ heat_load_output: summaryOutputSchema, balance_point_graph: balancePointGraphSchema, - billing_records: allBillingRecordsSchema, + processed_energy_bills: allBillingRecordsSchema, }) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index fc97049..b38d4d2 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -136,9 +136,9 @@ def get_outputs_normalized( balance_point_graph = home.balance_point_graph - billing_records = [] + processed_energy_bills = [] for processed_energy_bill_input in intermediate_processed_energy_bill_inputs: - billing_record = ProcessedEnergyBill( + processed_energy_bill = ProcessedEnergyBill( period_start_date=processed_energy_bill_input.input.period_start_date, period_end_date=processed_energy_bill_input.input.period_end_date, usage=processed_energy_bill_input.input.usage, @@ -148,12 +148,12 @@ def get_outputs_normalized( eliminated_as_outlier=processed_energy_bill_input.eliminated_as_outlier, whole_home_heat_loss_rate=processed_energy_bill_input.ua, ) - billing_records.append(billing_record) + processed_energy_bills.append(processed_energy_bill) result = RulesEngineResult( heat_load_output=heat_load_output, balance_point_graph=balance_point_graph, - billing_records=billing_records, + processed_energy_bills=processed_energy_bills, ) return result diff --git a/python/src/rules_engine/pydantic_models.py b/python/src/rules_engine/pydantic_models.py index cfbf901..7a10fdd 100644 --- a/python/src/rules_engine/pydantic_models.py +++ b/python/src/rules_engine/pydantic_models.py @@ -223,7 +223,7 @@ class BalancePointGraph(BaseModel): class RulesEngineResult(BaseModel): heat_load_output: HeatLoadOutput balance_point_graph: BalancePointGraph - billing_records: list[ProcessedEnergyBill] + processed_energy_bills: list[ProcessedEnergyBill] @dataclass diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index bdf48d3..94347b9 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -14,7 +14,7 @@ home variables used 2. Rename rules-engine to "python" 3. Rename NormalizedBillingRecordBase class to BillingInput 4. Rename BillingPeriod to IntermediateProcessedEnergyBill and processed_energy_bill_input to processed_energy_bill_intermediate -5. Combine get_outputs_normalized and convert_to_intermediate_billing_record and get rid of NormalizedBillingRecord. There is only one place NormalizedBillingRecord is used and combining code +5. Combine get_outputs_normalized and convert_to_intermediate_processed_energy_bill and get rid of NormalizedBillingRecord. There is only one place NormalizedBillingRecord is used and combining code gets rid of the need for the class. - Change ``` diff --git a/python/tests/test_rules_engine/generate_example_data.py b/python/tests/test_rules_engine/generate_example_data.py index 72fc9c4..5693d8a 100644 --- a/python/tests/test_rules_engine/generate_example_data.py +++ b/python/tests/test_rules_engine/generate_example_data.py @@ -90,7 +90,7 @@ def generate_summary_json(workbook: Any, working_directory: Path) -> str: return fuel_type -def generate_billing_record_input_csv( +def generate_processed_energy_bill_input_csv( workbook: Any, fuel_type: str, working_directory: Path ) -> None: """ @@ -192,6 +192,6 @@ def generate_billing_record_input_csv( continue print("Processing test directory:", working_directory) fuel_type = generate_summary_json(workbook, working_directory) - generate_billing_record_input_csv(workbook, fuel_type, working_directory) + generate_processed_energy_bill_input_csv(workbook, fuel_type, working_directory) workbook.close() del workbook diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index b77b189..83f0bd8 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -430,9 +430,9 @@ def test_get_outputs_normalized( rules_engine_result.heat_load_output.standard_deviation_of_heat_loss_rate == approx(0.0463, abs=0.01) ) - assert rules_engine_result.billing_records[0].usage == 60 - assert rules_engine_result.billing_records[0].whole_home_heat_loss_rate != None - assert rules_engine_result.billing_records[5].whole_home_heat_loss_rate == None + assert rules_engine_result.processed_energy_bills[0].usage == 60 + assert rules_engine_result.processed_energy_bills[0].whole_home_heat_loss_rate != None + assert rules_engine_result.processed_energy_bills[5].whole_home_heat_loss_rate == None @pytest.mark.parametrize( diff --git a/python/tests/test_rules_engine/test_natural_gas.py b/python/tests/test_rules_engine/test_natural_gas.py index d7a4b9d..963788a 100644 --- a/python/tests/test_rules_engine/test_natural_gas.py +++ b/python/tests/test_rules_engine/test_natural_gas.py @@ -148,13 +148,13 @@ def test_maximum_heat_load_natural_gas(data: Example) -> None: ) -def test_billing_records_whole_home_heat_loss_rate(data: Example) -> None: +def test_processed_energy_bills_whole_home_heat_loss_rate(data: Example) -> None: rules_engine_result = engine.get_outputs_natural_gas( data.summary, data.temperature_data, data.natural_gas_usage ) data_iter = iter(data.natural_gas_usage.records) - for result in rules_engine_result.billing_records: + for result in rules_engine_result.processed_energy_bills: example = next(data_iter) whole_home_heat_loss_rate = ( example.whole_home_heat_loss_rate From 421ac4e31e521a3099bbeaf798e5edd1f591f0de Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Wed, 4 Dec 2024 00:46:24 +0000 Subject: [PATCH 17/26] update the Lint format --- python/src/rules_engine/engine.py | 49 ++++++++++++++----- python/tests/test_rules_engine/test_engine.py | 20 ++++++-- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index b38d4d2..597fd5d 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -77,7 +77,10 @@ def get_outputs_natural_gas( ) return get_outputs_normalized( - heat_load_input, None, temperature_input, processed_energy_bill_inputs_bill_inputs + heat_load_input, + None, + temperature_input, + processed_energy_bill_inputs_bill_inputs, ) @@ -91,10 +94,12 @@ def get_outputs_normalized( Analyze the heat load for a home based on normalized, fuel-type-agnostic billing records. """ initial_balance_point = 60 - intermediate_processed_energy_bill_inputs = convert_to_intermediate_processed_energy_bill_inputs( - temperature_input=temperature_input, - processed_energy_bill_inputs=processed_energy_bill_inputs, - fuel_type=heat_load_input.fuel_type, + intermediate_processed_energy_bill_inputs = ( + convert_to_intermediate_processed_energy_bill_inputs( + temperature_input=temperature_input, + processed_energy_bill_inputs=processed_energy_bill_inputs, + fuel_type=heat_load_input.fuel_type, + ) ) home = Home.calculate( @@ -179,7 +184,9 @@ def convert_to_intermediate_processed_energy_bill_inputs( temperature_input.dates, processed_energy_bill_input.period_start_date ) end_idx = ( - bisect.bisect_left(temperature_input.dates, processed_energy_bill_input.period_end_date) + bisect.bisect_left( + temperature_input.dates, processed_energy_bill_input.period_end_date + ) + 1 ) @@ -189,7 +196,8 @@ def convert_to_intermediate_processed_energy_bill_inputs( ) elif fuel_type == FuelType.OIL or fuel_type == FuelType.PROPANE: analysis_type, default_inclusion = _date_to_analysis_type_oil_propane( - processed_energy_bill_input.period_start_date, processed_energy_bill_input.period_end_date + processed_energy_bill_input.period_start_date, + processed_energy_bill_input.period_end_date, ) else: raise ValueError("Unsupported fuel type.") @@ -202,7 +210,9 @@ def convert_to_intermediate_processed_energy_bill_inputs( default_inclusion=default_inclusion, inclusion_override=processed_energy_bill_input.inclusion_override, ) - intermediate_processed_energy_bill_inputs.append(intermediate_processed_energy_bill_input) + intermediate_processed_energy_bill_inputs.append( + intermediate_processed_energy_bill_input + ) return intermediate_processed_energy_bill_inputs @@ -516,7 +526,10 @@ def _calculate_balance_point_and_ua( self.balance_point_graph = BalancePointGraph(records=[]) - self.uas = [processed_energy_bill_input.ua for processed_energy_bill_input in self.bills_winter] + self.uas = [ + processed_energy_bill_input.ua + for processed_energy_bill_input in self.bills_winter + ] self.avg_ua = sts.mean(self.uas) self.stdev_pct = sts.pstdev(self.uas) / self.avg_ua @@ -540,7 +553,10 @@ def _calculate_balance_point_and_ua( biggest_outlier_idx ) # removes the biggest outlier outlier.eliminated_as_outlier = True - uas_i = [processed_energy_bill_input.ua for processed_energy_bill_input in self.bills_winter] + uas_i = [ + processed_energy_bill_input.ua + for processed_energy_bill_input in self.bills_winter + ] avg_ua_i = sts.mean(uas_i) stdev_pct_i = sts.pstdev(uas_i) / avg_ua_i if ( @@ -656,7 +672,9 @@ def calculate( return home_instance - def initialize_ua(self, processed_energy_bill_input: IntermediateProcessedEnergyBill) -> None: + def initialize_ua( + self, processed_energy_bill_input: IntermediateProcessedEnergyBill + ) -> None: """ Average heating usage, partial UA, initial UA. requires that self.home have non heating usage calculated. @@ -664,8 +682,13 @@ def initialize_ua(self, processed_energy_bill_input: IntermediateProcessedEnergy processed_energy_bill_input.avg_heating_usage = ( processed_energy_bill_input.usage / processed_energy_bill_input.days ) - self.avg_non_heating_usage - processed_energy_bill_input.partial_ua = self.calculate_partial_ua(processed_energy_bill_input) - processed_energy_bill_input.ua = processed_energy_bill_input.partial_ua / processed_energy_bill_input.total_hdd + processed_energy_bill_input.partial_ua = self.calculate_partial_ua( + processed_energy_bill_input + ) + processed_energy_bill_input.ua = ( + processed_energy_bill_input.partial_ua + / processed_energy_bill_input.total_hdd + ) def calculate_partial_ua( self, processed_energy_bill_input: IntermediateProcessedEnergyBill diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 83f0bd8..91078bb 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -26,7 +26,9 @@ @pytest.fixture() -def sample_processed_energy_bill_inputs() -> list[engine.IntermediateProcessedEnergyBill]: +def sample_processed_energy_bill_inputs() -> ( + list[engine.IntermediateProcessedEnergyBill] +): processed_energy_bill_inputs = [ engine.IntermediateProcessedEnergyBill( dummy_processed_energy_bill_input_record, @@ -332,7 +334,9 @@ def test_bp_ua_estimates(sample_summary_inputs, sample_processed_energy_bill_inp assert home.stdev_pct == approx(0.0463, abs=0.01) -def test_bp_ua_with_outlier(sample_summary_inputs, sample_processed_energy_bill_inputs_with_outlier): +def test_bp_ua_with_outlier( + sample_summary_inputs, sample_processed_energy_bill_inputs_with_outlier +): home = engine.Home.calculate( sample_summary_inputs, sample_processed_energy_bill_inputs_with_outlier, @@ -413,7 +417,9 @@ def test_convert_to_intermediate_processed_energy_bill_inputs( def test_get_outputs_normalized( - sample_summary_inputs, sample_temp_inputs, sample_normalized_processed_energy_bill_inputs + sample_summary_inputs, + sample_temp_inputs, + sample_normalized_processed_energy_bill_inputs, ): rules_engine_result = engine.get_outputs_normalized( sample_summary_inputs, @@ -431,8 +437,12 @@ def test_get_outputs_normalized( == approx(0.0463, abs=0.01) ) assert rules_engine_result.processed_energy_bills[0].usage == 60 - assert rules_engine_result.processed_energy_bills[0].whole_home_heat_loss_rate != None - assert rules_engine_result.processed_energy_bills[5].whole_home_heat_loss_rate == None + assert ( + rules_engine_result.processed_energy_bills[0].whole_home_heat_loss_rate != None + ) + assert ( + rules_engine_result.processed_energy_bills[5].whole_home_heat_loss_rate == None + ) @pytest.mark.parametrize( From 97ff4af34197c2d34e923bb9d0941cf1624d3120 Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Wed, 4 Dec 2024 01:28:34 +0000 Subject: [PATCH 18/26] Refactor: rename "processed_energy_bill_inputs_bill_inputs" to "processed_energy_bill_inputs" Co-authored-by: Ethan-Strominger Co-authored-by: AdamFinkle --- python/src/rules_engine/engine.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 597fd5d..44a3e24 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -64,10 +64,10 @@ def get_outputs_natural_gas( """ Analyze the heat load for a home that is using natural gas as its current heating system fuel. """ - processed_energy_bill_inputs_bill_inputs: list[ProcessedEnergyBillInput] = [] + processed_energy_bill_inputs: list[ProcessedEnergyBillInput] = [] for input_val in natural_gas_billing_input.records: - processed_energy_bill_inputs_bill_inputs.append( + processed_energy_bill_inputs.append( ProcessedEnergyBillInput( period_start_date=input_val.period_start_date, period_end_date=input_val.period_end_date, @@ -80,7 +80,7 @@ def get_outputs_natural_gas( heat_load_input, None, temperature_input, - processed_energy_bill_inputs_bill_inputs, + processed_energy_bill_inputs, ) From b6733be733c3d6ad12b723358278bcce5ce9a9c0 Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Thu, 5 Dec 2024 20:32:42 +0000 Subject: [PATCH 19/26] temporary save Co-authored-by: Ethan-Strominger Co-authored-by: AdamFinkle --- python/src/rules_engine/engine.py | 106 +++++++++++++++--------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 44a3e24..ce3ffb1 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -94,8 +94,8 @@ def get_outputs_normalized( Analyze the heat load for a home based on normalized, fuel-type-agnostic billing records. """ initial_balance_point = 60 - intermediate_processed_energy_bill_inputs = ( - convert_to_intermediate_processed_energy_bill_inputs( + intermediate_processed_energy_bills = ( + convert_to_intermediate_processed_energy_bills( temperature_input=temperature_input, processed_energy_bill_inputs=processed_energy_bill_inputs, fuel_type=heat_load_input.fuel_type, @@ -104,7 +104,7 @@ def get_outputs_normalized( home = Home.calculate( heat_load_input=heat_load_input, - processed_energy_bill_inputs=intermediate_processed_energy_bill_inputs, + processed_energy_bills=intermediate_processed_energy_bills, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) @@ -142,16 +142,16 @@ def get_outputs_normalized( balance_point_graph = home.balance_point_graph processed_energy_bills = [] - for processed_energy_bill_input in intermediate_processed_energy_bill_inputs: + for intermediate_processed_energy_bill in intermediate_processed_energy_bills: processed_energy_bill = ProcessedEnergyBill( - period_start_date=processed_energy_bill_input.input.period_start_date, - period_end_date=processed_energy_bill_input.input.period_end_date, - usage=processed_energy_bill_input.input.usage, - inclusion_override=processed_energy_bill_input.input.inclusion_override, - analysis_type=processed_energy_bill_input.analysis_type, - default_inclusion=processed_energy_bill_input.default_inclusion, - eliminated_as_outlier=processed_energy_bill_input.eliminated_as_outlier, - whole_home_heat_loss_rate=processed_energy_bill_input.ua, + period_start_date=intermediate_processed_energy_bill.input.period_start_date, + period_end_date=intermediate_processed_energy_bill.input.period_end_date, + usage=intermediate_processed_energy_bill.input.usage, + inclusion_override=intermediate_processed_energy_bill.input.inclusion_override, + analysis_type=intermediate_processed_energy_bill.analysis_type, + default_inclusion=intermediate_processed_energy_bill.default_inclusion, + eliminated_as_outlier=intermediate_processed_energy_bill.eliminated_as_outlier, + whole_home_heat_loss_rate=intermediate_processed_energy_bill.ua, ) processed_energy_bills.append(processed_energy_bill) @@ -163,7 +163,7 @@ def get_outputs_normalized( return result -def convert_to_intermediate_processed_energy_bill_inputs( +def convert_to_intermediate_processed_energy_bills( temperature_input: TemperatureInput, processed_energy_bill_inputs: list[ProcessedEnergyBillInput], fuel_type: FuelType, @@ -202,7 +202,7 @@ def convert_to_intermediate_processed_energy_bill_inputs( else: raise ValueError("Unsupported fuel type.") - intermediate_processed_energy_bill_input = IntermediateProcessedEnergyBill( + intermediate_processed_energy_bill = IntermediateProcessedEnergyBill( input=processed_energy_bill_input, avg_temps=temperature_input.temperatures[start_idx:end_idx], usage=processed_energy_bill_input.usage, @@ -211,7 +211,7 @@ def convert_to_intermediate_processed_energy_bill_inputs( inclusion_override=processed_energy_bill_input.inclusion_override, ) intermediate_processed_energy_bill_inputs.append( - intermediate_processed_energy_bill_input + intermediate_processed_energy_bill ) return intermediate_processed_energy_bill_inputs @@ -411,7 +411,7 @@ class Home: def _init( self, heat_load_input: HeatLoadInput, - processed_energy_bill_inputs: list[IntermediateProcessedEnergyBill], + processed_energy_bills: list[IntermediateProcessedEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, ) -> None: @@ -420,18 +420,18 @@ def _init( self.thermostat_set_point = heat_load_input.thermostat_set_point self.balance_point = initial_balance_point self.dhw_input = dhw_input - self._initialize_processed_energy_bill_inputs(processed_energy_bill_inputs) + self._initialize_processed_energy_bill_inputs(processed_energy_bills) def _initialize_processed_energy_bill_inputs( - self, processed_energy_bill_inputs: list[IntermediateProcessedEnergyBill] + self, processed_energy_bills: list[IntermediateProcessedEnergyBill] ) -> None: - self.bills_winter = [] - self.bills_summer = [] - self.bills_shoulder = [] + self.winter_processed_energy_bills = [] + self.summer_processed_energy_bills = [] + self.shoulder_processed_energy_bills = [] # winter months 1 (ALLOWED_HEATING_USAGE); summer months -1 (ALLOWED_NON_HEATING_USAGE); shoulder months 0 (NOT_ALLOWED...) - for processed_energy_bill_input in processed_energy_bill_inputs: - processed_energy_bill_input.set_initial_balance_point(self.balance_point) + for processed_energy_bill in processed_energy_bills: + processed_energy_bill.set_initial_balance_point(self.balance_point) """ The UI depicts billing period usage as several distinctive icons on the left hand column of the screen; "analysis_type" @@ -441,8 +441,8 @@ def _initialize_processed_energy_bill_inputs( The following code implements this algorithm and adds bills accordingly to winter, summer, or shoulder (i.e. excluded) lists """ - _analysis_type = processed_energy_bill_input.analysis_type - _default_inclusion = processed_energy_bill_input.default_inclusion + _analysis_type = processed_energy_bill.analysis_type + _default_inclusion = processed_energy_bill.default_inclusion # Only bills deemed ALLOWED by the AnalysisType algorithm can be included/excluded by the user # if ( @@ -464,33 +464,33 @@ def _initialize_processed_energy_bill_inputs( # Assign the bill to the appropriate list for winter or summer calculations - if processed_energy_bill_input.inclusion_override: + if processed_energy_bill.inclusion_override: _default_inclusion = not _default_inclusion if ( _analysis_type == AnalysisType.ALLOWED_HEATING_USAGE and _default_inclusion ): - self.bills_winter.append(processed_energy_bill_input) + self.winter_processed_energy_bills.append(processed_energy_bill) elif ( _analysis_type == AnalysisType.ALLOWED_NON_HEATING_USAGE and _default_inclusion ): - self.bills_summer.append(processed_energy_bill_input) + self.summer_processed_energy_bills.append(processed_energy_bill) else: # the rest are excluded from calculations - self.bills_shoulder.append(processed_energy_bill_input) + self.shoulder_processed_energy_bills.append(processed_energy_bill) self._calculate_avg_summer_usage() self._calculate_avg_non_heating_usage() - for processed_energy_bill_input in self.bills_winter: - self.initialize_ua(processed_energy_bill_input) + for processed_energy_bill in self.winter_processed_energy_bills: + self.initialize_ua(processed_energy_bill) def _calculate_avg_summer_usage(self) -> None: """ Calculate average daily summer usage """ - summer_usage_total = sum([bp.usage for bp in self.bills_summer]) - summer_days = sum([bp.days for bp in self.bills_summer]) + summer_usage_total = sum([bp.usage for bp in self.summer_processed_energy_bills]) + summer_days = sum([bp.days for bp in self.summer_processed_energy_bills]) if summer_days != 0: self.avg_summer_usage = summer_usage_total / summer_days else: @@ -527,8 +527,8 @@ def _calculate_balance_point_and_ua( self.balance_point_graph = BalancePointGraph(records=[]) self.uas = [ - processed_energy_bill_input.ua - for processed_energy_bill_input in self.bills_winter + processed_energy_bill.ua + for processed_energy_bill in self.winter_processed_energy_bills ] self.avg_ua = sts.mean(self.uas) self.stdev_pct = sts.pstdev(self.uas) / self.avg_ua @@ -546,16 +546,16 @@ def _calculate_balance_point_and_ua( self._refine_balance_point(initial_balance_point_sensitivity) while self.stdev_pct > stdev_pct_max: - outliers = [abs(bill.ua - self.avg_ua) for bill in self.bills_winter] + outliers = [abs(bill.ua - self.avg_ua) for bill in self.winter_processed_energy_bills] biggest_outlier = max(outliers) biggest_outlier_idx = outliers.index(biggest_outlier) - outlier = self.bills_winter.pop( + outlier = self.winter_processed_energy_bills.pop( biggest_outlier_idx ) # removes the biggest outlier outlier.eliminated_as_outlier = True uas_i = [ - processed_energy_bill_input.ua - for processed_energy_bill_input in self.bills_winter + processed_energy_bill.ua + for processed_energy_bill in self.winter_processed_energy_bills ] avg_ua_i = sts.mean(uas_i) stdev_pct_i = sts.pstdev(uas_i) / avg_ua_i @@ -565,7 +565,7 @@ def _calculate_balance_point_and_ua( < max_stdev_pct_diff ): # if it's a small enough change # add the outlier back in - self.bills_winter.append( + self.winter_processed_energy_bills.append( outlier ) # then it's not worth removing it, and we exit outlier.eliminated_as_outlier = False @@ -592,11 +592,11 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: break # may want to raise some kind of warning as well period_hdds_i = [ - period_hdd(bill.avg_temps, bp_i) for bill in self.bills_winter + period_hdd(bill.avg_temps, bp_i) for bill in self.winter_processed_energy_bills ] uas_i = [ bill.partial_ua / period_hdds_i[n] - for n, bill in enumerate(self.bills_winter) + for n, bill in enumerate(self.winter_processed_energy_bills) ] avg_ua_i = sts.mean(uas_i) stdev_pct_i = sts.pstdev(uas_i) / avg_ua_i @@ -631,7 +631,7 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: ) self.balance_point_graph.records.append(balance_point_graph_row) - for n, bill in enumerate(self.bills_winter): + for n, bill in enumerate(self.winter_processed_energy_bills): bill.total_hdd = period_hdds_i[n] bill.ua = uas_i[n] @@ -642,7 +642,7 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: def calculate( cls, heat_load_input: HeatLoadInput, - processed_energy_bill_inputs: list[IntermediateProcessedEnergyBill], + processed_energy_bills: list[IntermediateProcessedEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, initial_balance_point_sensitivity: float = 0.5, @@ -658,7 +658,7 @@ def calculate( home_instance = object.__new__(cls) home_instance._init( heat_load_input=heat_load_input, - processed_energy_bill_inputs=processed_energy_bill_inputs, + processed_energy_bills=processed_energy_bills, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) @@ -673,21 +673,21 @@ def calculate( return home_instance def initialize_ua( - self, processed_energy_bill_input: IntermediateProcessedEnergyBill + self, processed_energy_bill: IntermediateProcessedEnergyBill ) -> None: """ Average heating usage, partial UA, initial UA. requires that self.home have non heating usage calculated. """ - processed_energy_bill_input.avg_heating_usage = ( - processed_energy_bill_input.usage / processed_energy_bill_input.days + processed_energy_bill.avg_heating_usage = ( + processed_energy_bill.usage / processed_energy_bill.days ) - self.avg_non_heating_usage - processed_energy_bill_input.partial_ua = self.calculate_partial_ua( - processed_energy_bill_input + processed_energy_bill.partial_ua = self.calculate_partial_ua( + processed_energy_bill ) - processed_energy_bill_input.ua = ( - processed_energy_bill_input.partial_ua - / processed_energy_bill_input.total_hdd + processed_energy_bill.ua = ( + processed_energy_bill.partial_ua + / processed_energy_bill.total_hdd ) def calculate_partial_ua( From c5eba9bc04337df105bdba0a7c1f64340834a55e Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:47:59 +0000 Subject: [PATCH 20/26] Refactor: fix "billing_period" renaming issue. Co-authored-by: Ethan-Strominger --- python/src/rules_engine/refactor.md | 4 ++-- python/tests/test_rules_engine/test_engine.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index 94347b9..020432c 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -97,7 +97,7 @@ avg_non_heating_usage = _get_avg_non_heating_usage ( to ``` for processed_energy_bill_input in processed_energy_bill_inputs - { bills_summer, bills_winter, bills_shoulder } + { summer_processed_energy_bills, winter_processed_energy_bills, shoulder_processed_energy_bills } =_categorize_bills_by_season (processed_energy_bill_inputs) ``` ================== @@ -158,7 +158,7 @@ self._calculate_balance_point_and_ua( stdev_pct_max, max_stdev_pct_diff, next_balance_point_sensitivity, - bills_winter) + winter_processed_energy_bills) ``` ================== diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 91078bb..5eee15d 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -324,7 +324,7 @@ def test_bp_ua_estimates(sample_summary_inputs, sample_processed_energy_bill_inp initial_balance_point=58, ) - ua_1, ua_2, ua_3 = [bill.ua for bill in home.bills_winter] + ua_1, ua_2, ua_3 = [bill.ua for bill in home.winter_processed_energy_bills] assert home.balance_point == 60.5 assert ua_1 == approx(1455.03, abs=0.01) @@ -344,8 +344,8 @@ def test_bp_ua_with_outlier( initial_balance_point=58, ) - # expect that ua_1 is considered an outlier and not used in bills_winter - ua_2, ua_3, ua_4 = [bill.ua for bill in home.bills_winter] + # expect that ua_1 is considered an outlier and not used in winter_processed_energy_bills + ua_2, ua_3, ua_4 = [bill.ua for bill in home.winter_processed_energy_bills] assert home.balance_point == 60.5 assert ua_2 == approx(1455.03, abs=0.01) @@ -355,10 +355,10 @@ def test_bp_ua_with_outlier( assert home.stdev_pct == approx(0.0463, abs=0.01) -def test_convert_to_intermediate_processed_energy_bill_inputs( +def test_convert_to_intermediate_processed_energy_bills( sample_temp_inputs, sample_normalized_processed_energy_bill_inputs ): - results = engine.convert_to_intermediate_processed_energy_bill_inputs( + results = engine.convert_to_intermediate_processed_energy_bills( sample_temp_inputs, sample_normalized_processed_energy_bill_inputs, FuelType.GAS, From c9ed49aec3a595c3c6c656b7a2a030d3dc65dd31 Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:52:21 +0000 Subject: [PATCH 21/26] Refactor: fix "billing_period" renaming issue. Co-authored-by: Ethan-Strominger --- python/src/rules_engine/engine.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index ce3ffb1..8b8df75 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -673,32 +673,32 @@ def calculate( return home_instance def initialize_ua( - self, processed_energy_bill: IntermediateProcessedEnergyBill + self, intermediate_processed_energy_bill: IntermediateProcessedEnergyBill ) -> None: """ Average heating usage, partial UA, initial UA. requires that self.home have non heating usage calculated. """ - processed_energy_bill.avg_heating_usage = ( - processed_energy_bill.usage / processed_energy_bill.days + intermediate_processed_energy_bill.avg_heating_usage = ( + intermediate_processed_energy_bill.usage / intermediate_processed_energy_bill.days ) - self.avg_non_heating_usage - processed_energy_bill.partial_ua = self.calculate_partial_ua( - processed_energy_bill + intermediate_processed_energy_bill.partial_ua = self.calculate_partial_ua( + intermediate_processed_energy_bill ) - processed_energy_bill.ua = ( - processed_energy_bill.partial_ua - / processed_energy_bill.total_hdd + intermediate_processed_energy_bill.ua = ( + intermediate_processed_energy_bill.partial_ua + / intermediate_processed_energy_bill.total_hdd ) def calculate_partial_ua( - self, processed_energy_bill_input: IntermediateProcessedEnergyBill + self, intermediate_processed_energy_bill: IntermediateProcessedEnergyBill ) -> float: """ The portion of UA that is not dependent on the balance point """ return ( - processed_energy_bill_input.days - * processed_energy_bill_input.avg_heating_usage # gallons or therms + intermediate_processed_energy_bill.days + * intermediate_processed_energy_bill.avg_heating_usage # gallons or therms * self.fuel_type.value # therm or gallon to BTU * self.heat_sys_efficiency # unitless / 24 From d34e900cb236455e8ee87c4c10dcc33df14f5d8b Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:01:10 +0000 Subject: [PATCH 22/26] Refactor: removed the commented out code Co-authored-by: Ethan-Strominger --- heat-stack/app/routes/_heat+/single.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/heat-stack/app/routes/_heat+/single.tsx b/heat-stack/app/routes/_heat+/single.tsx index 9ab9c41..25be9d3 100644 --- a/heat-stack/app/routes/_heat+/single.tsx +++ b/heat-stack/app/routes/_heat+/single.tsx @@ -350,12 +350,6 @@ export async function action({ request, params }: ActionFunctionArgs) { ) from rules_engine import engine, helpers - # def get_outputs_normalized( - # heat_load_input: HeatLoadInput, - # dhw_input: Optional[DhwInput], - # temperature_input: TemperatureInput, - # processed_energy_bill_inputs: list[ProcessedEnergyBillInput], - # ) def executeRoundtripAnalyticsFromForm(summaryInputJs, temperatureInputJs, userAdjustedData, state_id, county_id): """ From be7ab41b6ae95564e0a924941ae90a209c399e83 Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:50:49 +0000 Subject: [PATCH 23/26] Refactor: fix "billing_records" renaming issue. Co-authored-by: Ethan-Strominger --- heat-stack/types/index.ts | 6 +++--- heat-stack/types/types.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/heat-stack/types/index.ts b/heat-stack/types/index.ts index 96910f5..e55f34c 100644 --- a/heat-stack/types/index.ts +++ b/heat-stack/types/index.ts @@ -98,7 +98,7 @@ export const naturalGasUsageSchema = z.map( ) // Define the schema for one billing record -export const oneBillingRecordSchema = z.object({ +export const oneProcessedEnergyBillSchema = z.object({ period_start_date: z.string(), period_end_date: z.string(), usage: z.number(), @@ -122,11 +122,11 @@ export const oneBillingRecordSchema = z.object({ }); // Define the schema for the 'processed_energy_bills' list -export const allBillingRecordsSchema = z.array(oneBillingRecordSchema); +export const allProcessedEnergyBillsSchema = z.array(oneProcessedEnergyBillSchema); // Define the schema for the 'usage_data' key export const usageDataSchema = z.object({ heat_load_output: summaryOutputSchema, balance_point_graph: balancePointGraphSchema, - processed_energy_bills: allBillingRecordsSchema, + processed_energy_bills: allProcessedEnergyBillsSchema, }) diff --git a/heat-stack/types/types.ts b/heat-stack/types/types.ts index ba6039d..6437463 100644 --- a/heat-stack/types/types.ts +++ b/heat-stack/types/types.ts @@ -3,8 +3,8 @@ import { type balancePointGraphRecordSchema, type balancePointGraphSchema, type summaryOutputSchema, - type oneBillingRecordSchema, - type allBillingRecordsSchema, + type oneProcessedEnergyBillSchema, + type allProcessedEnergyBillsSchema, type usageDataSchema, type naturalGasUsageSchema } from './index.ts' @@ -14,6 +14,6 @@ export type NaturalGasUsageDataSchema = z.infer; export type BalancePoointGraphRecordSchema = z.infer; export type BalancePintGraphSchema = z.infer; export type SummaryOutputSchema = z.infer; -export type BillingRecordSchema = z.infer; -export type BillingRecordsSchema = z.infer; +export type BillingRecordSchema = z.infer; +export type BillingRecordsSchema = z.infer; export type UsageDataSchema = z.infer; \ No newline at end of file From ec82535789857c07551ac156024bc6fb6d89240d Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:22:06 +0000 Subject: [PATCH 24/26] Refactor: Rename "sample_summary_inputs" to "sample_heat_load_inputs" Co-authored-by: AdamFinkle Co-authored-by: Ethan-Strominger --- python/src/rules_engine/engine.py | 2 +- python/tests/test_rules_engine/test_engine.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 8b8df75..372d275 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -517,7 +517,7 @@ def _calculate_balance_point_and_ua( stdev_pct_max: float = 0.10, max_stdev_pct_diff: float = 0.01, next_balance_point_sensitivity: float = 0.5, - ) -> None: + ) -> any: """ Calculates the estimated balance point and UA coefficient for the home, removing UA outliers based on a normalized standard diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 5eee15d..0ad9d2d 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -117,7 +117,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( @pytest.fixture() -def sample_summary_inputs() -> HeatLoadInput: +def sample_heat_load_inputs() -> HeatLoadInput: heat_sys_efficiency = 0.88 living_area = 1000 @@ -316,9 +316,9 @@ def test_get_average_indoor_temperature(): assert engine.get_average_indoor_temperature(set_temp, setback, setback_hrs) == 66 -def test_bp_ua_estimates(sample_summary_inputs, sample_processed_energy_bill_inputs): +def test_bp_ua_estimates(sample_heat_load_inputs, sample_processed_energy_bill_inputs): home = engine.Home.calculate( - sample_summary_inputs, + sample_heat_load_inputs, sample_processed_energy_bill_inputs, dhw_input=None, initial_balance_point=58, @@ -335,10 +335,10 @@ def test_bp_ua_estimates(sample_summary_inputs, sample_processed_energy_bill_inp def test_bp_ua_with_outlier( - sample_summary_inputs, sample_processed_energy_bill_inputs_with_outlier + sample_heat_load_inputs, sample_processed_energy_bill_inputs_with_outlier ): home = engine.Home.calculate( - sample_summary_inputs, + sample_heat_load_inputs, sample_processed_energy_bill_inputs_with_outlier, dhw_input=None, initial_balance_point=58, @@ -417,12 +417,12 @@ def test_convert_to_intermediate_processed_energy_bills( def test_get_outputs_normalized( - sample_summary_inputs, + sample_heat_load_inputs, sample_temp_inputs, sample_normalized_processed_energy_bill_inputs, ): rules_engine_result = engine.get_outputs_normalized( - sample_summary_inputs, + sample_heat_load_inputs, None, sample_temp_inputs, sample_normalized_processed_energy_bill_inputs, From 196d584c60608dad22e1133eb55a85c03b2d17e5 Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:25:52 +0000 Subject: [PATCH 25/26] Refactor: Rename "dummy_processed_energy_bill_input_record" to "_dummy_processed_energy_bill_input" Co-authored-by: AdamFinkle Co-authored-by: Ethan-Strominger --- python/tests/test_rules_engine/test_engine.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index 0ad9d2d..e796b7a 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -17,7 +17,7 @@ TemperatureInput, ) -dummy_processed_energy_bill_input_record = ProcessedEnergyBillInput( +_dummy_processed_energy_bill_input = ProcessedEnergyBillInput( period_start_date=datetime(2024, 1, 1), period_end_date=datetime(2024, 2, 1), usage=1.0, @@ -31,7 +31,7 @@ def sample_processed_energy_bill_inputs() -> ( ): processed_energy_bill_inputs = [ engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [28, 29, 30, 29], 50, AnalysisType.ALLOWED_HEATING_USAGE, @@ -39,7 +39,7 @@ def sample_processed_energy_bill_inputs() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [32, 35, 35, 38], 45, AnalysisType.ALLOWED_HEATING_USAGE, @@ -47,7 +47,7 @@ def sample_processed_energy_bill_inputs() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [41, 43, 42, 42], 30, AnalysisType.ALLOWED_HEATING_USAGE, @@ -55,7 +55,7 @@ def sample_processed_energy_bill_inputs() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [72, 71, 70, 69], 0.96, AnalysisType.NOT_ALLOWED_IN_CALCULATIONS, @@ -72,7 +72,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( ): processed_energy_bill_inputs = [ engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [41.7, 41.6, 32, 25.4], 60, AnalysisType.ALLOWED_HEATING_USAGE, @@ -80,7 +80,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [28, 29, 30, 29], 50, AnalysisType.ALLOWED_HEATING_USAGE, @@ -88,7 +88,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [32, 35, 35, 38], 45, AnalysisType.ALLOWED_HEATING_USAGE, @@ -96,7 +96,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [41, 43, 42, 42], 30, AnalysisType.ALLOWED_HEATING_USAGE, @@ -104,7 +104,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [72, 71, 70, 69], 0.96, AnalysisType.NOT_ALLOWED_IN_CALCULATIONS, @@ -366,7 +366,7 @@ def test_convert_to_intermediate_processed_energy_bills( expected_results = [ engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [41.7, 41.6, 32, 25.4], 60, AnalysisType.ALLOWED_HEATING_USAGE, @@ -374,7 +374,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [28, 29, 30, 29], 50, AnalysisType.ALLOWED_HEATING_USAGE, @@ -382,7 +382,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [32, 35, 35, 38], 45, AnalysisType.ALLOWED_HEATING_USAGE, @@ -390,7 +390,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [41, 43, 42, 42], 30, AnalysisType.ALLOWED_HEATING_USAGE, @@ -398,7 +398,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, ), engine.IntermediateProcessedEnergyBill( - dummy_processed_energy_bill_input_record, + _dummy_processed_energy_bill_input, [72, 71, 70, 69], 0.96, AnalysisType.ALLOWED_HEATING_USAGE, From 14f235c7df211746a8bf5df3c22937e91ca0772e Mon Sep 17 00:00:00 2001 From: stemgene <35020077+stemgene@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:54:04 +0000 Subject: [PATCH 26/26] Refactor: corrected variable naming issue of "IntermediateEnergyBill" Co-authored-by: AdamFinkle Co-authored-by: Ethan-Strominger --- python/src/rules_engine/engine.py | 62 +++++++++---------- python/src/rules_engine/refactor.md | 4 +- python/tests/test_rules_engine/test_engine.py | 52 ++++++++-------- python/tests/test_rules_engine/test_utils.py | 2 +- 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/python/src/rules_engine/engine.py b/python/src/rules_engine/engine.py index 372d275..1424ee1 100644 --- a/python/src/rules_engine/engine.py +++ b/python/src/rules_engine/engine.py @@ -104,7 +104,7 @@ def get_outputs_normalized( home = Home.calculate( heat_load_input=heat_load_input, - processed_energy_bills=intermediate_processed_energy_bills, + intermediate_energy_bills=intermediate_processed_energy_bills, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) @@ -142,16 +142,16 @@ def get_outputs_normalized( balance_point_graph = home.balance_point_graph processed_energy_bills = [] - for intermediate_processed_energy_bill in intermediate_processed_energy_bills: + for intermediate_energy_bill in intermediate_processed_energy_bills: processed_energy_bill = ProcessedEnergyBill( - period_start_date=intermediate_processed_energy_bill.input.period_start_date, - period_end_date=intermediate_processed_energy_bill.input.period_end_date, - usage=intermediate_processed_energy_bill.input.usage, - inclusion_override=intermediate_processed_energy_bill.input.inclusion_override, - analysis_type=intermediate_processed_energy_bill.analysis_type, - default_inclusion=intermediate_processed_energy_bill.default_inclusion, - eliminated_as_outlier=intermediate_processed_energy_bill.eliminated_as_outlier, - whole_home_heat_loss_rate=intermediate_processed_energy_bill.ua, + period_start_date=intermediate_energy_bill.input.period_start_date, + period_end_date=intermediate_energy_bill.input.period_end_date, + usage=intermediate_energy_bill.input.usage, + inclusion_override=intermediate_energy_bill.input.inclusion_override, + analysis_type=intermediate_energy_bill.analysis_type, + default_inclusion=intermediate_energy_bill.default_inclusion, + eliminated_as_outlier=intermediate_energy_bill.eliminated_as_outlier, + whole_home_heat_loss_rate=intermediate_energy_bill.ua, ) processed_energy_bills.append(processed_energy_bill) @@ -167,7 +167,7 @@ def convert_to_intermediate_processed_energy_bills( temperature_input: TemperatureInput, processed_energy_bill_inputs: list[ProcessedEnergyBillInput], fuel_type: FuelType, -) -> list[IntermediateProcessedEnergyBill]: +) -> list[IntermediateEnergyBill]: """ Converts temperature data and billing period inputs into internal classes used for heat loss calculations. @@ -202,7 +202,7 @@ def convert_to_intermediate_processed_energy_bills( else: raise ValueError("Unsupported fuel type.") - intermediate_processed_energy_bill = IntermediateProcessedEnergyBill( + intermediate_energy_bill = IntermediateEnergyBill( input=processed_energy_bill_input, avg_temps=temperature_input.temperatures[start_idx:end_idx], usage=processed_energy_bill_input.usage, @@ -211,7 +211,7 @@ def convert_to_intermediate_processed_energy_bills( inclusion_override=processed_energy_bill_input.inclusion_override, ) intermediate_processed_energy_bill_inputs.append( - intermediate_processed_energy_bill + intermediate_energy_bill ) return intermediate_processed_energy_bill_inputs @@ -411,7 +411,7 @@ class Home: def _init( self, heat_load_input: HeatLoadInput, - processed_energy_bills: list[IntermediateProcessedEnergyBill], + intermediate_energy_bills: list[IntermediateEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, ) -> None: @@ -420,17 +420,17 @@ def _init( self.thermostat_set_point = heat_load_input.thermostat_set_point self.balance_point = initial_balance_point self.dhw_input = dhw_input - self._initialize_processed_energy_bill_inputs(processed_energy_bills) + self._initialize_processed_energy_bill_inputs(intermediate_energy_bills) def _initialize_processed_energy_bill_inputs( - self, processed_energy_bills: list[IntermediateProcessedEnergyBill] + self, intermediate_energy_bills: list[IntermediateEnergyBill] ) -> None: self.winter_processed_energy_bills = [] self.summer_processed_energy_bills = [] self.shoulder_processed_energy_bills = [] # winter months 1 (ALLOWED_HEATING_USAGE); summer months -1 (ALLOWED_NON_HEATING_USAGE); shoulder months 0 (NOT_ALLOWED...) - for processed_energy_bill in processed_energy_bills: + for processed_energy_bill in intermediate_energy_bills: processed_energy_bill.set_initial_balance_point(self.balance_point) """ @@ -642,7 +642,7 @@ def _refine_balance_point(self, balance_point_sensitivity: float) -> None: def calculate( cls, heat_load_input: HeatLoadInput, - processed_energy_bills: list[IntermediateProcessedEnergyBill], + intermediate_energy_bills: list[IntermediateEnergyBill], dhw_input: Optional[DhwInput], initial_balance_point: float = 60, initial_balance_point_sensitivity: float = 0.5, @@ -658,7 +658,7 @@ def calculate( home_instance = object.__new__(cls) home_instance._init( heat_load_input=heat_load_input, - processed_energy_bills=processed_energy_bills, + intermediate_energy_bills=intermediate_energy_bills, dhw_input=dhw_input, initial_balance_point=initial_balance_point, ) @@ -673,32 +673,32 @@ def calculate( return home_instance def initialize_ua( - self, intermediate_processed_energy_bill: IntermediateProcessedEnergyBill + self, intermediate_energy_bill: IntermediateEnergyBill ) -> None: """ Average heating usage, partial UA, initial UA. requires that self.home have non heating usage calculated. """ - intermediate_processed_energy_bill.avg_heating_usage = ( - intermediate_processed_energy_bill.usage / intermediate_processed_energy_bill.days + intermediate_energy_bill.avg_heating_usage = ( + intermediate_energy_bill.usage / intermediate_energy_bill.days ) - self.avg_non_heating_usage - intermediate_processed_energy_bill.partial_ua = self.calculate_partial_ua( - intermediate_processed_energy_bill + intermediate_energy_bill.partial_ua = self.calculate_partial_ua( + intermediate_energy_bill ) - intermediate_processed_energy_bill.ua = ( - intermediate_processed_energy_bill.partial_ua - / intermediate_processed_energy_bill.total_hdd + intermediate_energy_bill.ua = ( + intermediate_energy_bill.partial_ua + / intermediate_energy_bill.total_hdd ) def calculate_partial_ua( - self, intermediate_processed_energy_bill: IntermediateProcessedEnergyBill + self, intermediate_energy_bill: IntermediateEnergyBill ) -> float: """ The portion of UA that is not dependent on the balance point """ return ( - intermediate_processed_energy_bill.days - * intermediate_processed_energy_bill.avg_heating_usage # gallons or therms + intermediate_energy_bill.days + * intermediate_energy_bill.avg_heating_usage # gallons or therms * self.fuel_type.value # therm or gallon to BTU * self.heat_sys_efficiency # unitless / 24 @@ -707,7 +707,7 @@ def calculate_partial_ua( ) -class IntermediateProcessedEnergyBill: +class IntermediateEnergyBill: """ An internal class storing data whence heating usage per billing period is calculated. diff --git a/python/src/rules_engine/refactor.md b/python/src/rules_engine/refactor.md index 020432c..f13b00f 100644 --- a/python/src/rules_engine/refactor.md +++ b/python/src/rules_engine/refactor.md @@ -13,7 +13,7 @@ home variables used 1. Remove temporary_rules_engine.py 2. Rename rules-engine to "python" 3. Rename NormalizedBillingRecordBase class to BillingInput -4. Rename BillingPeriod to IntermediateProcessedEnergyBill and processed_energy_bill_input to processed_energy_bill_intermediate +4. Rename BillingPeriod to IntermediateEnergyBill and processed_energy_bill_input to processed_energy_bill_intermediate 5. Combine get_outputs_normalized and convert_to_intermediate_processed_energy_bill and get rid of NormalizedBillingRecord. There is only one place NormalizedBillingRecord is used and combining code gets rid of the need for the class. - Change @@ -55,7 +55,7 @@ to inputBill.start_date, inputBill.end_date ) - processedBill = IntermediateProcessedEnergyBill( + processedBill = IntermediateEnergyBill( input = inputBill, avg_temps = avg_temps, default_analysis_type = default_analysis_type diff --git a/python/tests/test_rules_engine/test_engine.py b/python/tests/test_rules_engine/test_engine.py index e796b7a..cfd1723 100644 --- a/python/tests/test_rules_engine/test_engine.py +++ b/python/tests/test_rules_engine/test_engine.py @@ -26,11 +26,11 @@ @pytest.fixture() -def sample_processed_energy_bill_inputs() -> ( - list[engine.IntermediateProcessedEnergyBill] +def sample_intermediate_energy_bill_inputs() -> ( + list[engine.IntermediateEnergyBill] ): - processed_energy_bill_inputs = [ - engine.IntermediateProcessedEnergyBill( + intermediate_energy_bill_inputs = [ + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [28, 29, 30, 29], 50, @@ -38,7 +38,7 @@ def sample_processed_energy_bill_inputs() -> ( True, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [32, 35, 35, 38], 45, @@ -46,7 +46,7 @@ def sample_processed_energy_bill_inputs() -> ( True, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [41, 43, 42, 42], 30, @@ -54,7 +54,7 @@ def sample_processed_energy_bill_inputs() -> ( True, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [72, 71, 70, 69], 0.96, @@ -63,15 +63,15 @@ def sample_processed_energy_bill_inputs() -> ( False, ), ] - return processed_energy_bill_inputs + return intermediate_energy_bill_inputs @pytest.fixture() -def sample_processed_energy_bill_inputs_with_outlier() -> ( - list[engine.IntermediateProcessedEnergyBill] +def sample_intermediate_energy_bill_inputs_with_outlier() -> ( + list[engine.IntermediateEnergyBill] ): - processed_energy_bill_inputs = [ - engine.IntermediateProcessedEnergyBill( + intermediate_energy_bill_inputs = [ + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [41.7, 41.6, 32, 25.4], 60, @@ -79,7 +79,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( True, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [28, 29, 30, 29], 50, @@ -87,7 +87,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( True, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [32, 35, 35, 38], 45, @@ -95,7 +95,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( True, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [41, 43, 42, 42], 30, @@ -103,7 +103,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( True, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [72, 71, 70, 69], 0.96, @@ -113,7 +113,7 @@ def sample_processed_energy_bill_inputs_with_outlier() -> ( ), ] - return processed_energy_bill_inputs + return intermediate_energy_bill_inputs @pytest.fixture() @@ -316,10 +316,10 @@ def test_get_average_indoor_temperature(): assert engine.get_average_indoor_temperature(set_temp, setback, setback_hrs) == 66 -def test_bp_ua_estimates(sample_heat_load_inputs, sample_processed_energy_bill_inputs): +def test_bp_ua_estimates(sample_heat_load_inputs, sample_intermediate_energy_bill_inputs): home = engine.Home.calculate( sample_heat_load_inputs, - sample_processed_energy_bill_inputs, + sample_intermediate_energy_bill_inputs, dhw_input=None, initial_balance_point=58, ) @@ -335,11 +335,11 @@ def test_bp_ua_estimates(sample_heat_load_inputs, sample_processed_energy_bill_i def test_bp_ua_with_outlier( - sample_heat_load_inputs, sample_processed_energy_bill_inputs_with_outlier + sample_heat_load_inputs, sample_intermediate_energy_bill_inputs_with_outlier ): home = engine.Home.calculate( sample_heat_load_inputs, - sample_processed_energy_bill_inputs_with_outlier, + sample_intermediate_energy_bill_inputs_with_outlier, dhw_input=None, initial_balance_point=58, ) @@ -365,7 +365,7 @@ def test_convert_to_intermediate_processed_energy_bills( ) expected_results = [ - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [41.7, 41.6, 32, 25.4], 60, @@ -373,7 +373,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [28, 29, 30, 29], 50, @@ -381,7 +381,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [32, 35, 35, 38], 45, @@ -389,7 +389,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [41, 43, 42, 42], 30, @@ -397,7 +397,7 @@ def test_convert_to_intermediate_processed_energy_bills( False, False, ), - engine.IntermediateProcessedEnergyBill( + engine.IntermediateEnergyBill( _dummy_processed_energy_bill_input, [72, 71, 70, 69], 0.96, diff --git a/python/tests/test_rules_engine/test_utils.py b/python/tests/test_rules_engine/test_utils.py index c580102..08efa0b 100644 --- a/python/tests/test_rules_engine/test_utils.py +++ b/python/tests/test_rules_engine/test_utils.py @@ -14,7 +14,7 @@ TemperatureInput, ) - +# TODO: Need to be reviewed class Summary(HeatLoadInput, HeatLoadOutput): """ Holds summary.json information alongside a string referring to a