From 7b116c75b1ad4b4f82e62b0b6dc7164779159a8f Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Mon, 6 Jan 2025 22:42:45 -0700 Subject: [PATCH 1/5] Improve test description, avoid using Dates.jl in runtests.jl --- test/runtests.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 0a472190d..c01541604 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3087,17 +3087,17 @@ else # run HiGHS tests input_data["ElectricLoad"]["loads_kw"] = zeros(8760) # Weekday off-peak February 28th, to set February Facility demand charge input_data["ElectricLoad"]["loads_kw"][31*24+27*24+8] = peak_load - # Weekday off-peak Feb 29th for leap year, to make sure not adding March facility demand charge if non-leap year or if Feb handled as 28 days for leap year (wrong) + # Weekday off-peak Feb 29th for leap year, March 1st for non-leap year (also if Feb is wrongly handled as 28 days for leap year) input_data["ElectricLoad"]["loads_kw"][31*24+28*24+8] = peak_load s = Scenario(input_data) inputs = REoptInputs(s) m = Model(optimizer_with_attributes(HiGHS.Optimizer, "mip_rel_gap" => 0.01, "output_flag" => false, "log_to_console" => false)) results = run_reopt(m, inputs) flat_rate = input_data["ElectricTariff"]["urdb_response"]["flatdemandstructure"][3][1]["rate"] - if isleapyear(year) + if year == 2024 demand_charge_expected = flat_rate * peak_load - else - demand_charge_expected = 2* flat_rate * peak_load + elseif year == 2023 + demand_charge_expected = 2 * flat_rate * peak_load end @test results["ElectricTariff"]["year_one_demand_cost_before_tax"] ≈ demand_charge_expected atol=1E-6 end From 780dde3146b254de9cc0986bb4394d54ee78f4fc Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Mon, 6 Jan 2025 22:51:25 -0700 Subject: [PATCH 2/5] Add leap year test input file --- test/runtests.jl | 2 +- test/scenarios/leap_year.json | 1414 +++++++++++++++++++++++++++++++++ 2 files changed, 1415 insertions(+), 1 deletion(-) create mode 100644 test/scenarios/leap_year.json diff --git a/test/runtests.jl b/test/runtests.jl index c01541604..2a12bbfaa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3056,7 +3056,7 @@ else # run HiGHS tests Flat/Facility (non-TOU) demand charges of 18.05/kW all month TOU demand charges of 10/kW between 2pm-7pm on weekdays """ - input_data = JSON.parsefile("./scenarios/leap_year.json") + input_data = JSON.parsefile("/scenarios/leap_year.json") # Set the load profile to zeros except for certain timesteps to test alignment of load with rate structure peak_load = 10.0 diff --git a/test/scenarios/leap_year.json b/test/scenarios/leap_year.json new file mode 100644 index 000000000..21ed7abb8 --- /dev/null +++ b/test/scenarios/leap_year.json @@ -0,0 +1,1414 @@ +{ + "Site": { + "latitude": 37.78, + "longitude": -122.45 + }, + "ElectricLoad": { + "year": 2024 + }, + "Financial": { + "elec_cost_escalation_rate_fraction": 0.0, + "om_cost_escalation_rate_fraction": 0.0, + "offtaker_discount_rate_fraction": 0.0, + "offtaker_tax_rate_fraction": 0.0, + "existing_boiler_fuel_cost_escalation_rate_fraction": 0.0 + }, + "ElectricTariff": { + "urdb_response": { + "energyweekdayschedule": [ + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ] + ], + "energyweekendschedule": [ + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + ], + "energyratestructure": [ + [ + { + "rate": 0, + "unit": "kWh" + } + ], + [ + { + "rate": 0.28, + "unit": "kWh" + } + ], + [ + { + "rate": 0.36, + "unit": "kWh" + } + ] + ], + "flatdemandstructure": [ + [ + { + "rate": 0 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ], + [ + { + "rate": 18.05 + } + ] + ], + "flatdemandmonths": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12 + ], + "lookbackmonths": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "demandratestructure": [ + [ + { + "rate": 0, + "unit": "kW" + } + ], + [ + { + "rate": 0.0, + "unit": "kW" + } + ], + [ + { + "rate": 10.0, + "unit": "kW" + } + ] + ], + "demandweekdayschedule": [ + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1 + ] + ], + "demandweekendschedule": [ + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + ], + "lookbackpercent": 0.0, + "fixedchargefirstmeter": 24.878, + "fixedchargeunits": "$/day" + } + } +} \ No newline at end of file From a381abe8b4beca9335c71ccd02c87813fec460fd Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Tue, 7 Jan 2025 09:53:07 -0700 Subject: [PATCH 3/5] Fix input file path formatting --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 2a12bbfaa..9a9757da9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3056,7 +3056,7 @@ else # run HiGHS tests Flat/Facility (non-TOU) demand charges of 18.05/kW all month TOU demand charges of 10/kW between 2pm-7pm on weekdays """ - input_data = JSON.parsefile("/scenarios/leap_year.json") + input_data = JSON.parsefile("scenarios/leap_year.json") # Set the load profile to zeros except for certain timesteps to test alignment of load with rate structure peak_load = 10.0 From b7f4590cdc55071b3b088a01d461c68c3d5ab7f5 Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Wed, 8 Jan 2025 10:20:27 -0700 Subject: [PATCH 4/5] Update changelog for leap year fix --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 220f95b08..70d6f689e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,11 @@ Classify the change according to the following categories: ### Removed +## leap-year-fix +### Fixed +- Handling of leap years for `ElectricLoad.loads_kw` inputs to align with URDB rate structures + + ## v0.49.0 ### Added - Ability to normalize and scale a custom load profile input to annual or monthly energy input values, for all load types From d6f7d4f369a640afe748e68e51f6659869a49069 Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Wed, 8 Jan 2025 10:21:11 -0700 Subject: [PATCH 5/5] Include 2023 and 2024 years for all new tests --- test/runtests.jl | 61 ++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 9a9757da9..3123b25e5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3050,7 +3050,7 @@ else # run HiGHS tests """ We tell users to truncate/cut-off the last day of the year of their load profile for leap years, to preserve the weekday/weekend and month alignment of the load with the rate structure - + The input .json file has a custom rate tariff to test leap year behavior for timesteps beyond end of February Higher energy price weekdays between 7AM (ts 8, 32, etc) through 7pm (ts 20, 44, etc) Flat/Facility (non-TOU) demand charges of 18.05/kW all month @@ -3059,31 +3059,42 @@ else # run HiGHS tests input_data = JSON.parsefile("scenarios/leap_year.json") # Set the load profile to zeros except for certain timesteps to test alignment of load with rate structure peak_load = 10.0 - - # Test for TOU energy and demand charges alignment with load profile for leap years - input_data["ElectricLoad"]["loads_kw"] = zeros(8760) - # Monday (on-peak) March 4, 2024, but Sunday (weekend, off-peak) if February handled as 28 days (as it was in REopt prior to 2025) - input_data["ElectricLoad"]["loads_kw"][31*24+29*24+3*24+16] = peak_load - s = Scenario(input_data) - inputs = REoptInputs(s) - m = Model(optimizer_with_attributes(HiGHS.Optimizer, "mip_rel_gap" => 0.01, "output_flag" => false, "log_to_console" => false)) - results = run_reopt(m, inputs) - - # TOU Energy charges - weekend_rate = input_data["ElectricTariff"]["urdb_response"]["energyratestructure"][2][1]["rate"] # Not used in this test - weekday_rate = input_data["ElectricTariff"]["urdb_response"]["energyratestructure"][3][1]["rate"] - energy_charge_expected = weekday_rate * peak_load - @test results["ElectricTariff"]["year_one_energy_cost_before_tax"] ≈ energy_charge_expected atol=1E-6 - - # TOU Demand charges - flat_rate = input_data["ElectricTariff"]["urdb_response"]["flatdemandstructure"][3][1]["rate"] - tou_rate = input_data["ElectricTariff"]["urdb_response"]["demandratestructure"][3][1]["rate"] - demand_charge_expected = (flat_rate + tou_rate) * peak_load - @test results["ElectricTariff"]["year_one_demand_cost_before_tax"] ≈ demand_charge_expected atol=1E-6 - - # Test for flat/facility (non-TOU) demand charge for 2023 (non-leap year) and 2024 (leap year) for year in [2023, 2024] input_data["ElectricLoad"]["year"] = year + + # Test for TOU energy and demand charges alignment with load profile for leap years + input_data["ElectricLoad"]["loads_kw"] = zeros(8760) + # Sunday (off-peak) March 3, 2023, so expect off-peak energy and demand charges for 2023 + # Monday (on-peak) March 4, 2024, but Sunday (weekend, off-peak) if February handled as 28 days for leap year (as it was in REopt prior to 2025) + input_data["ElectricLoad"]["loads_kw"][31*24+29*24+3*24+16] = peak_load + s = Scenario(input_data) + inputs = REoptInputs(s) + m = Model(optimizer_with_attributes(HiGHS.Optimizer, "mip_rel_gap" => 0.01, "output_flag" => false, "log_to_console" => false)) + results = run_reopt(m, inputs) + + # TOU Energy charges + weekend_rate = input_data["ElectricTariff"]["urdb_response"]["energyratestructure"][2][1]["rate"] # Not used in this test + weekday_rate = input_data["ElectricTariff"]["urdb_response"]["energyratestructure"][3][1]["rate"] + + # TOU Demand charges + flat_rate = input_data["ElectricTariff"]["urdb_response"]["flatdemandstructure"][3][1]["rate"] + tou_rate = input_data["ElectricTariff"]["urdb_response"]["demandratestructure"][3][1]["rate"] + + energy_charge_expected = 0.0 + demand_charge_expected = 0.0 + if year == 2023 + energy_charge_expected = weekend_rate * peak_load + demand_charge_expected = flat_rate * peak_load + elseif year == 2024 # Leap year + energy_charge_expected = weekday_rate * peak_load + demand_charge_expected = (flat_rate + tou_rate) * peak_load + end + println("year = ", year) + @test results["ElectricTariff"]["year_one_energy_cost_before_tax"] ≈ energy_charge_expected atol=1E-6 + @test results["ElectricTariff"]["year_one_demand_cost_before_tax"] ≈ demand_charge_expected atol=1E-6 + + + # Flat/facility (non-TOU) demand charge input_data["ElectricLoad"]["loads_kw"] = zeros(8760) # Weekday off-peak February 28th, to set February Facility demand charge input_data["ElectricLoad"]["loads_kw"][31*24+27*24+8] = peak_load @@ -3094,7 +3105,7 @@ else # run HiGHS tests m = Model(optimizer_with_attributes(HiGHS.Optimizer, "mip_rel_gap" => 0.01, "output_flag" => false, "log_to_console" => false)) results = run_reopt(m, inputs) flat_rate = input_data["ElectricTariff"]["urdb_response"]["flatdemandstructure"][3][1]["rate"] - if year == 2024 + if year == 2024 # Leap year demand_charge_expected = flat_rate * peak_load elseif year == 2023 demand_charge_expected = 2 * flat_rate * peak_load