From 518d9507a215ceb10f75a61d7d6a34d6238919d7 Mon Sep 17 00:00:00 2001 From: "Rathod, Bhavesh" Date: Mon, 29 Sep 2025 13:26:55 -0400 Subject: [PATCH 01/18] Updated model with outputs for testing --- reoptjl/models.py | 152 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/reoptjl/models.py b/reoptjl/models.py index 2d48782ea..f1a3e925b 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -1506,6 +1506,24 @@ class ElectricLoadOutputs(BaseModel, models.Model): null=True, blank=True, help_text="Annual energy consumption calculated by summing up load_series_kw. Does not include electric load for any new heating or cooling techs." ) + monthly_calculated_kwh = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Monthly energy consumption calculated by summing up load_series_kw. Does not include electric load for any new heating or cooling techs." + ) + monthly_peak_kw = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Monthly peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs." + ) + annual_peak_kw = models.FloatField( + null=True, blank=True, + help_text="Annual peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs." + ) annual_electric_load_with_thermal_conversions_kwh = models.FloatField( null=True, blank=True, help_text="Total end-use electrical load, including electrified heating and cooling end-use load." @@ -2563,6 +2581,140 @@ class ElectricTariffOutputs(BaseModel, models.Model): related_name="ElectricTariffOutputs", primary_key=True ) + year_one_monthly_fixed_cost = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Year one fixed utility costs for each month." + ) + + year_one_electric_to_load_energy_cost_series_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of cost of power purchased from grid to serve load in each timestep." + ) + monthly_electric_to_load_energy_cost_series_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of monthly cost of power purchased from grid to serve loads." + ) + year_one_electric_to_storage_energy_cost_series_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of cost of power purchased from grid to charge battery storage system in each timestep." + ) + monthly_electric_to_storage_energy_cost_series_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of monthly cost of power purchased from grid to charge battery storage system." + ) + monthly_facility_demand_cost_series_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of total monthly facility demand charges by month." + ) + monthly_gross_tou_demand_cost_series_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of total time of use demand charges by month." + ) + NEM_export_rate_series = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of compensation rate in each timestep for exporting power to grid using systems sized up to net metering limit." + ) + NEM_electric_to_grid_series_kw = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of power exports to the grid up to net metering limit for each timestep." + ) + NEM_monthly_export_series_kwh = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Year one cost of electricity consumed in each month." + ) + NEM_monthly_export_cost_benefit_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Year one cost of electricity consumed in each month." + ) + WHL_export_rate_series = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of compensation rate in each timestep for exporting power to grid for wholesale." + ) + WHL_electric_to_grid_series_kw = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of power exports to the grid for wholesale in each timestep." + ) + WHL_monthly_export_series_kwh = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of monthly energy exports to grid under wholesale benefit." + ) + WHL_monthly_export_cost_benefit_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of monthly monetary benefit from exporting power to grid at wholesale rate." + ) + EXC_export_rate_series = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of compensation rate in each timestep for exporting power to grid beyond net metering limit." + ) + EXC_electric_to_grid_series_kw = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of power exports to the grid above net metering limit for each timestep." + ) + EXC_monthly_export_series_kwh = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of monthly energy exports to grid above net metering limit." + ) + EXC_monthly_export_cost_benefit_before_tax = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of monthly monetary benefit from exporting power to grid above net metering limit." + ) year_one_energy_cost_before_tax = models.FloatField( null=True, blank=True, help_text="Optimal year one utility energy cost" From ea88d75f73f42b42e9a0efce1938fc35b87af24b Mon Sep 17 00:00:00 2001 From: "Rathod, Bhavesh" Date: Tue, 30 Sep 2025 12:25:09 -0400 Subject: [PATCH 02/18] Update julia version and make migrations --- julia_src/Manifest.toml | 6 +- ...tricloadoutputs_annual_peak_kw_and_more.py | 124 ++++++++++++++++++ 2 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 499e0c00a..e0ad46b68 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -922,9 +922,11 @@ uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "4db74039055f6084d8bd45304de9de856462d917" +git-tree-sha1 = "1283214f265ecc53d02b4bc9318676a9f02dadcb" +repo-rev = "elec_util_usage" +repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.53.2" +version = "0.54.0" [[deps.Random]] deps = ["SHA"] diff --git a/reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py b/reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py new file mode 100644 index 000000000..42a5beb83 --- /dev/null +++ b/reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py @@ -0,0 +1,124 @@ +# Generated by Django 4.0.7 on 2025-09-30 14:52 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0092_merge_20250613_0525'), + ] + + operations = [ + migrations.AddField( + model_name='electricloadoutputs', + name='annual_peak_kw', + field=models.FloatField(blank=True, help_text='Annual peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs.', null=True), + ), + migrations.AddField( + model_name='electricloadoutputs', + name='monthly_calculated_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Monthly energy consumption calculated by summing up load_series_kw. Does not include electric load for any new heating or cooling techs.', size=None), + ), + migrations.AddField( + model_name='electricloadoutputs', + name='monthly_peak_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Monthly peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_electric_to_grid_series_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid above net metering limit for each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_export_rate_series', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid beyond net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_monthly_export_cost_benefit_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly monetary benefit from exporting power to grid above net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_monthly_export_series_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly energy exports to grid above net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_electric_to_grid_series_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid up to net metering limit for each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_export_rate_series', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid using systems sized up to net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_monthly_export_cost_benefit_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one cost of electricity consumed in each month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_monthly_export_series_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one cost of electricity consumed in each month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_electric_to_grid_series_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid for wholesale in each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_export_rate_series', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid for wholesale.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_monthly_export_cost_benefit_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly monetary benefit from exporting power to grid at wholesale rate.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_monthly_export_series_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly energy exports to grid under wholesale benefit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_electric_to_load_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly cost of power purchased from grid to serve loads.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_electric_to_storage_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly cost of power purchased from grid to charge battery storage system.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_facility_demand_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of total monthly facility demand charges by month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_gross_tou_demand_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of total time of use demand charges by month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_electric_to_load_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of cost of power purchased from grid to serve load in each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_electric_to_storage_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of cost of power purchased from grid to charge battery storage system in each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_monthly_fixed_cost', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one fixed utility costs for each month.', size=None), + ), + ] From 08a9ccf13e2af054663c678b2a65b0a843a609a6 Mon Sep 17 00:00:00 2001 From: Rathod Date: Thu, 2 Oct 2025 14:35:57 -0400 Subject: [PATCH 03/18] Remove migration 0093 and add billed energy rate field Deleted the migration file 0093_electricloadoutputs_annual_peak_kw_and_more.py and added the year_one_billed_energy_rate_series ArrayField to the ElectricTariffOutputs model. This change likely reflects a schema update and migration reset to accommodate the new field. --- ...tricloadoutputs_annual_peak_kw_and_more.py | 124 ------------------ reoptjl/models.py | 9 ++ 2 files changed, 9 insertions(+), 124 deletions(-) delete mode 100644 reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py diff --git a/reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py b/reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py deleted file mode 100644 index 42a5beb83..000000000 --- a/reoptjl/migrations/0093_electricloadoutputs_annual_peak_kw_and_more.py +++ /dev/null @@ -1,124 +0,0 @@ -# Generated by Django 4.0.7 on 2025-09-30 14:52 - -import django.contrib.postgres.fields -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('reoptjl', '0092_merge_20250613_0525'), - ] - - operations = [ - migrations.AddField( - model_name='electricloadoutputs', - name='annual_peak_kw', - field=models.FloatField(blank=True, help_text='Annual peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs.', null=True), - ), - migrations.AddField( - model_name='electricloadoutputs', - name='monthly_calculated_kwh', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Monthly energy consumption calculated by summing up load_series_kw. Does not include electric load for any new heating or cooling techs.', size=None), - ), - migrations.AddField( - model_name='electricloadoutputs', - name='monthly_peak_kw', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Monthly peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='EXC_electric_to_grid_series_kw', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid above net metering limit for each timestep.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='EXC_export_rate_series', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid beyond net metering limit.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='EXC_monthly_export_cost_benefit_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly monetary benefit from exporting power to grid above net metering limit.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='EXC_monthly_export_series_kwh', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly energy exports to grid above net metering limit.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='NEM_electric_to_grid_series_kw', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid up to net metering limit for each timestep.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='NEM_export_rate_series', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid using systems sized up to net metering limit.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='NEM_monthly_export_cost_benefit_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one cost of electricity consumed in each month.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='NEM_monthly_export_series_kwh', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one cost of electricity consumed in each month.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='WHL_electric_to_grid_series_kw', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid for wholesale in each timestep.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='WHL_export_rate_series', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid for wholesale.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='WHL_monthly_export_cost_benefit_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly monetary benefit from exporting power to grid at wholesale rate.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='WHL_monthly_export_series_kwh', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly energy exports to grid under wholesale benefit.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='monthly_electric_to_load_energy_cost_series_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly cost of power purchased from grid to serve loads.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='monthly_electric_to_storage_energy_cost_series_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly cost of power purchased from grid to charge battery storage system.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='monthly_facility_demand_cost_series_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of total monthly facility demand charges by month.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='monthly_gross_tou_demand_cost_series_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of total time of use demand charges by month.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='year_one_electric_to_load_energy_cost_series_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of cost of power purchased from grid to serve load in each timestep.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='year_one_electric_to_storage_energy_cost_series_before_tax', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of cost of power purchased from grid to charge battery storage system in each timestep.', size=None), - ), - migrations.AddField( - model_name='electrictariffoutputs', - name='year_one_monthly_fixed_cost', - field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one fixed utility costs for each month.', size=None), - ), - ] diff --git a/reoptjl/models.py b/reoptjl/models.py index f1a3e925b..f58eb3cf0 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -2715,6 +2715,15 @@ class ElectricTariffOutputs(BaseModel, models.Model): default=list, help_text="Series of monthly monetary benefit from exporting power to grid above net metering limit." ) + + year_one_billed_energy_rate_series = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, + help_text="Series of billed energy rates for each timestep in year one." + ) + year_one_energy_cost_before_tax = models.FloatField( null=True, blank=True, help_text="Optimal year one utility energy cost" From 39c7b2b4bff250c920e3e788377fc9a2f5be2554 Mon Sep 17 00:00:00 2001 From: "Rathod, Bhavesh" Date: Wed, 8 Oct 2025 19:44:40 -0400 Subject: [PATCH 04/18] Add new electric load and tariff output fields Introduces multiple new fields to ElectricLoadOutputs and ElectricTariffOutputs models for tracking annual peak kW, monthly energy and peak demand, export series, and various billed rate series. Updates Julia HTTP handler to log processing steps and ensures certain result matrices are converted to vectors before response. --- julia_src/http.jl | 5 + ...tricloadoutputs_annual_peak_kw_and_more.py | 164 ++++++++++++++++++ reoptjl/models.py | 39 ++++- 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 reoptjl/migrations/0106_electricloadoutputs_annual_peak_kw_and_more.py diff --git a/julia_src/http.jl b/julia_src/http.jl index 8e4b0a4fc..a25671938 100644 --- a/julia_src/http.jl +++ b/julia_src/http.jl @@ -56,6 +56,7 @@ function reopt(req::HTTP.Request) # Catch handled/unhandled exceptions in data pre-processing, JuMP setup try model_inputs = reoptjl.REoptInputs(d) + @info "Successfully processed REopt inputs." catch e @error "Something went wrong during REopt inputs processing!" exception=(e, catch_backtrace()) error_response["error"] = sprint(showerror, e) @@ -67,6 +68,7 @@ function reopt(req::HTTP.Request) # Catch handled/unhandled exceptions in optimization try results = reoptjl.run_reopt(ms, model_inputs) + @info "Successfully ran REopt optimization." inputs_with_defaults_from_easiur = [ :NOx_grid_cost_per_tonne, :SO2_grid_cost_per_tonne, :PM25_grid_cost_per_tonne, :NOx_onsite_fuelburn_cost_per_tonne, :SO2_onsite_fuelburn_cost_per_tonne, :PM25_onsite_fuelburn_cost_per_tonne, @@ -185,6 +187,9 @@ function reopt(req::HTTP.Request) if isempty(error_response) @info "REopt model solved with status $(results["status"])." + # these are matrices that need to be vector. + results["ElectricTariff"]["year_one_electric_to_load_energy_cost_series_before_tax"] = results["ElectricTariff"]["year_one_electric_to_load_energy_cost_series_before_tax"][:,1] + results["ElectricTariff"]["monthly_facility_demand_cost_series_before_tax"] = results["ElectricTariff"]["monthly_facility_demand_cost_series_before_tax"][:,1] response = Dict( "results" => results, "reopt_version" => string(pkgversion(reoptjl)) diff --git a/reoptjl/migrations/0106_electricloadoutputs_annual_peak_kw_and_more.py b/reoptjl/migrations/0106_electricloadoutputs_annual_peak_kw_and_more.py new file mode 100644 index 000000000..8add1d9cb --- /dev/null +++ b/reoptjl/migrations/0106_electricloadoutputs_annual_peak_kw_and_more.py @@ -0,0 +1,164 @@ +# Generated by Django 4.2.24 on 2025-10-06 17:06 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0105_alter_chpoutputs_initial_capital_costs_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='electricloadoutputs', + name='annual_peak_kw', + field=models.FloatField(blank=True, help_text='Annual peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs.', null=True), + ), + migrations.AddField( + model_name='electricloadoutputs', + name='monthly_calculated_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Monthly energy consumption calculated by summing up load_series_kw. Does not include electric load for any new heating or cooling techs.', size=None), + ), + migrations.AddField( + model_name='electricloadoutputs', + name='monthly_peak_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Monthly peak energy demand determined from load_series_kw. Does not include electric load for any new heating or cooling techs.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_electric_to_grid_series_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid above net metering limit for each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_export_rate_series', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid beyond net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_monthly_export_cost_benefit_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly monetary benefit from exporting power to grid above net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='EXC_monthly_export_series_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly energy exports to grid above net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_electric_to_grid_series_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid up to net metering limit for each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_export_rate_series', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid using systems sized up to net metering limit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_monthly_export_cost_benefit_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one cost of electricity consumed in each month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='NEM_monthly_export_series_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one cost of electricity consumed in each month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_electric_to_grid_series_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of power exports to the grid for wholesale in each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_export_rate_series', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of compensation rate in each timestep for exporting power to grid for wholesale.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_monthly_export_cost_benefit_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly monetary benefit from exporting power to grid at wholesale rate.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='WHL_monthly_export_series_kwh', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly energy exports to grid under wholesale benefit.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_electric_to_load_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly cost of power purchased from grid to serve loads.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_electric_to_storage_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of monthly cost of power purchased from grid to charge battery storage system.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_facility_demand_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of total monthly facility demand charges by month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_gross_tou_demand_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of total time of use demand charges by month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='monthly_tou_demand_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of total time of use demand charges for each month.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='tou_demand_metrics', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_billed_demand_rate_series', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_billed_energy_rate_series', + field=models.JSONField(blank=True, help_text='Series of billed energy rates for each timestep in year one.', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_billed_energy_rate_tier_limits', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_billed_facilitydemand_monthly_rate_series', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_billed_facilitydemand_monthly_rate_tier_limits', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_billed_tou_demand_rate_tier_limits', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_electric_to_load_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of cost of power purchased from grid to serve load in each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_electric_to_storage_energy_cost_series_before_tax', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Series of cost of power purchased from grid to charge battery storage system in each timestep.', size=None), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='year_one_monthly_fixed_cost', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, help_text='Year one fixed utility costs for each month.', size=None), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 0229e0026..c068360d1 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -2716,12 +2716,47 @@ class ElectricTariffOutputs(BaseModel, models.Model): help_text="Series of monthly monetary benefit from exporting power to grid above net metering limit." ) - year_one_billed_energy_rate_series = ArrayField( + year_one_billed_energy_rate_series = models.JSONField( + null=True, blank=True, + help_text="Series of billed energy rates for each timestep in year one." + ) + + monthly_tou_demand_cost_series_before_tax = ArrayField( models.FloatField( null=True, blank=True ), default=list, - help_text="Series of billed energy rates for each timestep in year one." + help_text="Series of total time of use demand charges for each month." + ) + + tou_demand_metrics = models.JSONField( + null=True, blank=True, + help_text="" + ) + + year_one_billed_facilitydemand_monthly_rate_tier_limits = models.JSONField( + null=True, blank=True, + help_text="" + ) + + year_one_billed_facilitydemand_monthly_rate_series = models.JSONField( + null=True, blank=True, + help_text="" + ) + + year_one_billed_tou_demand_rate_tier_limits = models.JSONField( + null=True, blank=True, + help_text="" + ) + + year_one_billed_energy_rate_tier_limits = models.JSONField( + null=True, blank=True, + help_text="" + ) + + year_one_billed_demand_rate_series = models.JSONField( + null=True, blank=True, + help_text="" ) year_one_energy_cost_before_tax = models.FloatField( From a8dcb7bbbfa77016facb0f00cb80a69a450ca123 Mon Sep 17 00:00:00 2001 From: Grant Ellwood <120485824+gellwood@users.noreply.github.com> Date: Fri, 10 Oct 2025 11:26:23 -0700 Subject: [PATCH 05/18] Added custom ANCCR table draft --- reoptjl/custom_table_config.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/reoptjl/custom_table_config.py b/reoptjl/custom_table_config.py index f12854ceb..c678cdb84 100644 --- a/reoptjl/custom_table_config.py +++ b/reoptjl/custom_table_config.py @@ -110,6 +110,22 @@ } ] + +custom_table_anccr = [ + { + "key": "site", + "bau_value": lambda df: "", + "scenario_value": lambda df: safe_get(df, "inputs.Meta.description", "None provided") + }, + { + "label": "Site Address", + "key": "site_address", + "bau_value": lambda df: safe_get(df, "inputs.Meta.address", "None provided"), + "scenario_value": lambda df: safe_get(df, "inputs.Meta.address", "None provided") + }, + + + # Webtool table configuration custom_table_webtool = [ ##################################################################################################### From 84956395b6706938e6bd2228616afa7556a6c951 Mon Sep 17 00:00:00 2001 From: "Rathod, Bhavesh" Date: Thu, 16 Oct 2025 16:54:49 -0400 Subject: [PATCH 06/18] Add URDB fields to ElectricTariffOutputs model Added multiple new fields to the ElectricTariffOutputs model and migration to store URDB-related metadata, including label, rate name, utility, effective date, voltage level, rate description, peak kW capacity min/max, additional info, energy and demand comments, and URL link. These changes support enhanced storage and retrieval of utility rate information. --- ...ffoutputs_urdb_demand_comments_and_more.py | 73 +++++++++++++++++++ reoptjl/models.py | 49 +++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 reoptjl/migrations/0107_electrictariffoutputs_urdb_demand_comments_and_more.py diff --git a/reoptjl/migrations/0107_electrictariffoutputs_urdb_demand_comments_and_more.py b/reoptjl/migrations/0107_electrictariffoutputs_urdb_demand_comments_and_more.py new file mode 100644 index 000000000..7dddf6eb4 --- /dev/null +++ b/reoptjl/migrations/0107_electrictariffoutputs_urdb_demand_comments_and_more.py @@ -0,0 +1,73 @@ +# Generated by Django 4.2.24 on 2025-10-16 20:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0106_electricloadoutputs_annual_peak_kw_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_demand_comments', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_energy_comments', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_label', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_peak_kw_capacity_max', + field=models.FloatField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_peak_kw_capacity_min', + field=models.FloatField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_rate_additional_info', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_rate_description', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_rate_effective_date', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_rate_name', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_url_link', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_utility', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + migrations.AddField( + model_name='electrictariffoutputs', + name='urdb_voltage_level', + field=models.TextField(blank=True, help_text='Business as usual life cycle utility minimum charge adder, after-tax', null=True), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index c068360d1..d6c421075 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -2759,6 +2759,55 @@ class ElectricTariffOutputs(BaseModel, models.Model): help_text="" ) + urdb_label = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_rate_name = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_utility = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_rate_effective_date = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_voltage_level = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_rate_description = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_peak_kw_capacity_min = models.FloatField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_peak_kw_capacity_max = models.FloatField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_rate_additional_info = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_energy_comments = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_demand_comments = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + urdb_url_link = models.TextField( + null=True, blank=True, + help_text="Business as usual life cycle utility minimum charge adder, after-tax" + ) + year_one_energy_cost_before_tax = models.FloatField( null=True, blank=True, help_text="Optimal year one utility energy cost" From 4b3078a0a02720f98ddb97722a3eb9548def464a Mon Sep 17 00:00:00 2001 From: Grant Ellwood <120485824+gellwood@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:20:29 -0700 Subject: [PATCH 07/18] Created custom table for ANCCR results Adds custom_table_anccr with a comprehensive configuration including general info, rate analysis, annual and monthly costs, load metrics, URDB rate info, and detailed monthly breakdowns. --- reoptjl/custom_table_config.py | 705 ++++++++++++++++++++++++++++++++- 1 file changed, 688 insertions(+), 17 deletions(-) diff --git a/reoptjl/custom_table_config.py b/reoptjl/custom_table_config.py index c678cdb84..3beb1d4b7 100644 --- a/reoptjl/custom_table_config.py +++ b/reoptjl/custom_table_config.py @@ -110,22 +110,6 @@ } ] - -custom_table_anccr = [ - { - "key": "site", - "bau_value": lambda df: "", - "scenario_value": lambda df: safe_get(df, "inputs.Meta.description", "None provided") - }, - { - "label": "Site Address", - "key": "site_address", - "bau_value": lambda df: safe_get(df, "inputs.Meta.address", "None provided"), - "scenario_value": lambda df: safe_get(df, "inputs.Meta.address", "None provided") - }, - - - # Webtool table configuration custom_table_webtool = [ ##################################################################################################### @@ -1257,4 +1241,691 @@ "formula": lambda col, bau, headers: f'=({bau["placeholder1_value"]}-{col}{headers["Placeholder2"] + 2})/{bau["placeholder1_value"]}' # This formula calculates the percentage change of Placeholder2 using Placeholder1's BAU value as the reference. } -] \ No newline at end of file +] + + + +custom_table_anccr = [ +##################################################################################################### +################################ Need to get the RATE NAME to appear in header ################ +##################################################################################################### + + # { + # "label": "Rate Headers", + # "key": "site", + # "bau_value": lambda df: "", + # "scenario_value": lambda df: safe_get(df, "", "") + # }, + +##################################################################################################### +################################ General Information ################################ +##################################################################################################### + + { + "label": "Installation Name", # Not REopt result; Name based on UTRMS Data + "key": "installation_name", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Site Location", # Not REopt result; Name based on User input + "key": "site_location", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Utility Name", # Not REopt result; Name based on User input + "key": "utility_name", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Rate Analysis Summary ################################ +##################################################################################################### + + { + "label": "Rate Analysis Summary", + "key": "rate_analysis_summary_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Rate Name", # Not REopt result; Name based on User input + "key": "rate_name", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Voltage Level", # Not REopt result; Name based on User input + "key": "voltage_level", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Fixed Charges ($)", + "key": "year_1_fixed_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_fixed_cost_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Energy Charges ($)", + "key": "year_1_energy_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_energy_cost_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Demand Charges ($)", + "key": "year_1_demand_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_demand_cost_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Total Bill Charges ($)", + "key": "year_1_total_bill_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_bill_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Change in Year 1 Charges ($)", # this value will need to be calculated compared to the current rate + "key": "change_in_year_1_charges", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Year 1 Annual Costs ################################ +##################################################################################################### + + { + "label": "Year 1 Annual Costs", + "key": "year_1_annual_costs_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Fixed Charges ($)", + "key": "year_1_fixed_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_fixed_cost_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Fixed Charges Percent Change (%)", # this value will need to be calculated compared to the current rate + "key": "year_1_fixed_charges_percent_change", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Energy Charges ($)", + "key": "year_1_energy_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_energy_cost_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Energy Charges Percent Change (%)", # this value will need to be calculated compared to the current rate + "key": "year_1_energy_charges_percent_change", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Demand Charges ($)", + "key": "year_1_demand_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_demand_cost_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Demand Charges Percent Change (%)", # this value will need to be calculated compared to the current rate + "key": "year_1_demand_charges_percent_change", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Total Bill Charges ($)", + "key": "year_1_total_bill_charges", + "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_bill_before_tax_bau"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Total Bill Charges Percent Change (%)", # this value will need to be calculated compared to the current rate + "key": "year_1_total_bill_charges_percent_change", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Year 1 Annual Costs as a Percent of Total Bill ################################ +##################################################################################################### + + { + "label": "Year 1 Annual Costs as a Percent of Total Bill", + "key": "year_1_annual_costs_percent_of_total_bill_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Fixed Charges Percent of Total Bill (%)", # value will be a calculation + "key": "year_1_fixed_charges_percent_of_total_bill", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Energy Charges Percent of Total Bill (%)", # value will be a calculation + "key": "year_1_energy_charges_percent_of_total_bill", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Demand Charges Percent of Total Bill (%)", # value will be a calculation + "key": "year_1_demand_charges_percent_of_total_bill", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Load Metrics ################################ +##################################################################################################### + + { + "label": "Load Metrics", + "key": "year_1_load_metrics_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Annual Grid Purchases (kWh)", + "key": "annual_grid_purchases_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.annual_calculated_kwh"), + "scenario_value": lambda df: "" + }, + { + "label": "Year 1 Peak Load (kW)", + "key": "year_1_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.annual_peak_kw"), + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ URDB Rate Information ################################ +##################################################################################################### + { + "label": "URDB Rate Information", + "key": "urdb_rate_information_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "URDB Label", # will need to pull from URDB + "key": "urdb_label", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Rate Effective Date (latest_update)", # will need to pull from URDB + "key": "rate_effective_date", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Voltage Level (voltagecategory)", # will need to pull from URDB + "key": "voltage_level_urdb", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Peak kW Capacity Min (peakkwcapacitymin)", # will need to pull from URDB + "key": "peak_kw_capacity_min", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Peak kW Capacity Max (peakkwcapacitymax)", # will need to pull from URDB + "key": "peak_kw_capacity_max", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Rate Description (description)", # will need to pull from URDB + "key": "rate_description", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Additional Information (basicinformationcomments)", # will need to pull from URDB + "key": "additional_information", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Energy Comments (energycomments)", # will need to pull from URDB + "key": "energy_comments", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "Demand Comments (demandcomments)", # will need to pull from URDB + "key": "demand_comments", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "URDB Link", # will need to pull from URDB + "key": "urdb_link", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Year 1 Monthly Energy Costs ################################ +##################################################################################################### + + { + "label": "Year 1 Monthly Energy Costs ($)", + "key": "year_1_monthly_energy_costs_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "January Energy Cost ($)", + "key": "january_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.0"), + "scenario_value": lambda df: "" + }, + { + "label": "February Energy Cost ($)", + "key": "february_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.1"), + "scenario_value": lambda df: "" + }, + { + "label": "March Energy Cost ($)", + "key": "march_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.2"), + "scenario_value": lambda df: "" + }, + { + "label": "April Energy Cost ($)", + "key": "april_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.3"), + "scenario_value": lambda df: "" + }, + { + "label": "May Energy Cost ($)", + "key": "may_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.4"), + "scenario_value": lambda df: "" + }, + { + "label": "June Energy Cost ($)", + "key": "june_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.5"), + "scenario_value": lambda df: "" + }, + { + "label": "July Energy Cost ($)", + "key": "july_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.6"), + "scenario_value": lambda df: "" + }, + { + "label": "August Energy Cost ($)", + "key": "august_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.7"), + "scenario_value": lambda df: "" + }, + { + "label": "September Energy Cost ($)", + "key": "september_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.8"), + "scenario_value": lambda df: "" + }, + { + "label": "October Energy Cost ($)", + "key": "october_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.9"), + "scenario_value": lambda df: "" + }, + { + "label": "November Energy Cost ($)", + "key": "november_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.10"), + "scenario_value": lambda df: "" + }, + { + "label": "December Energy Cost ($)", + "key": "december_energy_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.11"), + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Year 1 Monthly Demand Costs ################################ +##################################################################################################### + + { + "label": "Year 1 Monthly Demand Costs ($)", + "key": "year_1_monthly_demand_costs_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "January Demand Cost ($)", + "key": "january_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.0") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.0"), + "scenario_value": lambda df: "" + }, + { + "label": "February Demand Cost ($)", + "key": "february_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.1") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.1"), + "scenario_value": lambda df: "" + }, + { + "label": "March Demand Cost ($)", + "key": "march_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.2") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.2"), + "scenario_value": lambda df: "" + }, + { + "label": "April Demand Cost ($)", + "key": "april_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.3") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.3"), + "scenario_value": lambda df: "" + }, + { + "label": "May Demand Cost ($)", + "key": "may_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.4") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.4"), + "scenario_value": lambda df: "" + }, + { + "label": "June Demand Cost ($)", + "key": "june_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.5") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.5"), + "scenario_value": lambda df: "" + }, + { + "label": "July Demand Cost ($)", + "key": "july_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.6") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.6"), + "scenario_value": lambda df: "" + }, + { + "label": "August Demand Cost ($)", + "key": "august_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.7") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.7"), + "scenario_value": lambda df: "" + }, + { + "label": "September Demand Cost ($)", + "key": "september_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.8") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.8"), + "scenario_value": lambda df: "" + }, + { + "label": "October Demand Cost ($)", + "key": "october_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.9") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.9"), + "scenario_value": lambda df: "" + }, + { + "label": "November Demand Cost ($)", + "key": "november_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.10") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.10"), + "scenario_value": lambda df: "" + }, + { + "label": "December Demand Cost ($)", + "key": "december_demand_cost", + "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.11") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.11"), + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Year 1 Monthly Total Bill Costs ################################ +##################################################################################################### + + { + "label": "Year 1 Monthly Total Bill Costs ($)", + "key": "year_1_monthly_total_bill_costs_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "January Total Bill Cost ($)", # not sure if we have a monthly total bill cost output in REopt -- need to ask Bhavesh + "key": "january_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "February Total Bill Cost ($)", + "key": "february_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "March Total Bill Cost ($)", + "key": "march_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "April Total Bill Cost ($)", + "key": "april_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "May Total Bill Cost ($)", + "key": "may_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "June Total Bill Cost ($)", + "key": "june_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "July Total Bill Cost ($)", + "key": "july_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "August Total Bill Cost ($)", + "key": "august_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "September Total Bill Cost ($)", + "key": "september_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "October Total Bill Cost ($)", + "key": "october_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "November Total Bill Cost ($)", + "key": "november_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "December Total Bill Cost ($)", + "key": "december_total_bill_cost", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Monthly Energy Consumption (kWh) ################################ +##################################################################################################### + + { + "label": "Monthly Energy Consumption (kWh)", + "key": "monthly_energy_consumption_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "January Energy Consumption (kWh)", + "key": "january_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.0"), + "scenario_value": lambda df: "" + }, + { + "label": "February Energy Consumption (kWh)", + "key": "february_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.1"), + "scenario_value": lambda df: "" + }, + { + "label": "March Energy Consumption (kWh)", + "key": "march_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.2"), + "scenario_value": lambda df: "" + }, + { + "label": "April Energy Consumption (kWh)", + "key": "april_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.3"), + "scenario_value": lambda df: "" + }, + { + "label": "May Energy Consumption (kWh)", + "key": "may_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.4"), + "scenario_value": lambda df: "" + }, + { + "label": "June Energy Consumption (kWh)", + "key": "june_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.5"), + "scenario_value": lambda df: "" + }, + { + "label": "July Energy Consumption (kWh)", + "key": "july_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.6"), + "scenario_value": lambda df: "" + }, + { + "label": "August Energy Consumption (kWh)", + "key": "august_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.7"), + "scenario_value": lambda df: "" + }, + { + "label": "September Energy Consumption (kWh)", + "key": "september_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.8"), + "scenario_value": lambda df: "" + }, + { + "label": "October Energy Consumption (kWh)", + "key": "october_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.9"), + "scenario_value": lambda df: "" + }, + { + "label": "November Energy Consumption (kWh)", + "key": "november_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.10"), + "scenario_value": lambda df: "" + }, + { + "label": "December Energy Consumption (kWh)", + "key": "december_energy_consumption_kwh", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.11"), + "scenario_value": lambda df: "" + }, + +##################################################################################################### +################################ Monthly Peak Load (kW) ################################ +##################################################################################################### + + { + "label": "Monthly Peak Load (kW)", + "key": "monthly_peak_load_separator", + "bau_value": lambda df: "", + "scenario_value": lambda df: "" + }, + { + "label": "January Peak Load (kW)", + "key": "january_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.0"), + "scenario_value": lambda df: "" + }, + { + "label": "February Peak Load (kW)", + "key": "february_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.1"), + "scenario_value": lambda df: "" + }, + { + "label": "March Peak Load (kW)", + "key": "march_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.2"), + "scenario_value": lambda df: "" + }, + { + "label": "April Peak Load (kW)", + "key": "april_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.3"), + "scenario_value": lambda df: "" + }, + { + "label": "May Peak Load (kW)", + "key": "may_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.4"), + "scenario_value": lambda df: "" + }, + { + "label": "June Peak Load (kW)", + "key": "june_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.5"), + "scenario_value": lambda df: "" + }, + { + "label": "July Peak Load (kW)", + "key": "july_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.6"), + "scenario_value": lambda df: "" + }, + { + "label": "August Peak Load (kW)", + "key": "august_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.7"), + "scenario_value": lambda df: "" + }, + { + "label": "September Peak Load (kW)", + "key": "september_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.8"), + "scenario_value": lambda df: "" + }, + { + "label": "October Peak Load (kW)", + "key": "october_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.9"), + "scenario_value": lambda df: "" + }, + { + "label": "November Peak Load (kW)", + "key": "november_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.10"), + "scenario_value": lambda df: "" + }, + { + "label": "December Peak Load (kW)", + "key": "december_peak_load_kw", + "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.11"), + "scenario_value": lambda df: "" + } +] From aebd41ffd88fe8494670a322f8d66d6d7c2fd367 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 12:16:36 -0600 Subject: [PATCH 08/18] Update REopt#elec_util_usage after develop merge --- julia_src/Manifest.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 196aae6bd..794ce8c5e 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -948,9 +948,11 @@ version = "1.11.0" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "103761fa0f7447377726347af656cde6ab1160cc" +git-tree-sha1 = "dc4c262d7bab3c195154f48daa92451cf8769fea" +repo-rev = "elec_util_usage" +repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.55.1" +version = "0.55.0" [[deps.Random]] deps = ["SHA"] From a7fdea9b9f1fcc3125aa55a57b9e9cefbbcc6f24 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 12:17:05 -0600 Subject: [PATCH 09/18] Migration --merge after merging develop --- reoptjl/migrations/0110_merge_20251022_1752.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 reoptjl/migrations/0110_merge_20251022_1752.py diff --git a/reoptjl/migrations/0110_merge_20251022_1752.py b/reoptjl/migrations/0110_merge_20251022_1752.py new file mode 100644 index 000000000..cb76a4e89 --- /dev/null +++ b/reoptjl/migrations/0110_merge_20251022_1752.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.25 on 2025-10-22 17:52 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0107_electrictariffoutputs_urdb_demand_comments_and_more'), + ('reoptjl', '0109_remove_ghpoutputs_iterations_auto_guess_and_more'), + ] + + operations = [ + ] From 19d2bb2e1ca3527e4f47f12b19d63baf7aaf7377 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 17:08:40 -0600 Subject: [PATCH 10/18] Move urdb_metadata into ElectricTariffInputs and group into single json field instead of separate --- ...ffoutputs_urdb_demand_comments_and_more.py | 66 +++++++++++++++++++ reoptjl/models.py | 53 ++------------- 2 files changed, 70 insertions(+), 49 deletions(-) create mode 100644 reoptjl/migrations/0111_remove_electrictariffoutputs_urdb_demand_comments_and_more.py diff --git a/reoptjl/migrations/0111_remove_electrictariffoutputs_urdb_demand_comments_and_more.py b/reoptjl/migrations/0111_remove_electrictariffoutputs_urdb_demand_comments_and_more.py new file mode 100644 index 000000000..f4eeb281d --- /dev/null +++ b/reoptjl/migrations/0111_remove_electrictariffoutputs_urdb_demand_comments_and_more.py @@ -0,0 +1,66 @@ +# Generated by Django 4.2.25 on 2025-10-22 22:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0110_merge_20251022_1752'), + ] + + operations = [ + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_demand_comments', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_energy_comments', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_label', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_peak_kw_capacity_max', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_peak_kw_capacity_min', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_rate_additional_info', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_rate_description', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_rate_effective_date', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_rate_name', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_url_link', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_utility', + ), + migrations.RemoveField( + model_name='electrictariffoutputs', + name='urdb_voltage_level', + ), + migrations.AddField( + model_name='electrictariffinputs', + name='urdb_metadata', + field=models.JSONField(blank=True, help_text='Utility rate meta data from Utility Rate Database API', null=True), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 38ec9f3be..5e01d86f5 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -1738,6 +1738,10 @@ class ElectricTariffInputs(BaseModel, models.Model): help_text=("Optional coincident peak demand charge that is applied to the max load during the time_steps " "specified in coincident_peak_load_active_time_steps") ) + urdb_metadata = models.JSONField( + null=True, blank=True, + help_text=("Utility rate meta data from Utility Rate Database API") + ) def clean(self): error_messages = {} @@ -2799,55 +2803,6 @@ class ElectricTariffOutputs(BaseModel, models.Model): help_text="" ) - urdb_label = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_rate_name = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_utility = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_rate_effective_date = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_voltage_level = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_rate_description = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_peak_kw_capacity_min = models.FloatField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_peak_kw_capacity_max = models.FloatField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_rate_additional_info = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_energy_comments = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_demand_comments = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - urdb_url_link = models.TextField( - null=True, blank=True, - help_text="Business as usual life cycle utility minimum charge adder, after-tax" - ) - year_one_energy_cost_before_tax = models.FloatField( null=True, blank=True, help_text="Optimal year one utility energy cost" From b2a3b6bebbb1c31ce576bb8955893f92cf0cb71b Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 17:11:06 -0600 Subject: [PATCH 11/18] Rename export types to whole words --- ...et_metering_electric_to_grid_series_kw_.py | 73 +++++++++++++++++++ reoptjl/models.py | 24 +++--- 2 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 reoptjl/migrations/0112_rename_nem_electric_to_grid_series_kw_electrictariffoutputs_net_metering_electric_to_grid_series_kw_.py diff --git a/reoptjl/migrations/0112_rename_nem_electric_to_grid_series_kw_electrictariffoutputs_net_metering_electric_to_grid_series_kw_.py b/reoptjl/migrations/0112_rename_nem_electric_to_grid_series_kw_electrictariffoutputs_net_metering_electric_to_grid_series_kw_.py new file mode 100644 index 000000000..5b99f0d3c --- /dev/null +++ b/reoptjl/migrations/0112_rename_nem_electric_to_grid_series_kw_electrictariffoutputs_net_metering_electric_to_grid_series_kw_.py @@ -0,0 +1,73 @@ +# Generated by Django 4.2.25 on 2025-10-22 22:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0111_remove_electrictariffoutputs_urdb_demand_comments_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='NEM_electric_to_grid_series_kw', + new_name='net_metering_electric_to_grid_series_kw', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='EXC_electric_to_grid_series_kw', + new_name='net_metering_excess_electric_to_grid_series_kw', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='EXC_export_rate_series', + new_name='net_metering_excess_export_rate_series', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='EXC_monthly_export_cost_benefit_before_tax', + new_name='net_metering_excess_monthly_export_cost_benefit_before_tax', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='EXC_monthly_export_series_kwh', + new_name='net_metering_excess_monthly_export_series_kwh', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='NEM_export_rate_series', + new_name='net_metering_export_rate_series', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='NEM_monthly_export_cost_benefit_before_tax', + new_name='net_metering_monthly_export_cost_benefit_before_tax', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='NEM_monthly_export_series_kwh', + new_name='net_metering_monthly_export_series_kwh', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='WHL_electric_to_grid_series_kw', + new_name='wholesale_electric_to_grid_series_kw', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='WHL_export_rate_series', + new_name='wholesale_export_rate_series', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='WHL_monthly_export_cost_benefit_before_tax', + new_name='wholesale_monthly_export_cost_benefit_before_tax', + ), + migrations.RenameField( + model_name='electrictariffoutputs', + old_name='WHL_monthly_export_series_kwh', + new_name='wholesale_monthly_export_series_kwh', + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 5e01d86f5..59786030a 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -2675,84 +2675,84 @@ class ElectricTariffOutputs(BaseModel, models.Model): default=list, help_text="Series of total time of use demand charges by month." ) - NEM_export_rate_series = ArrayField( + net_metering_export_rate_series = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of compensation rate in each timestep for exporting power to grid using systems sized up to net metering limit." ) - NEM_electric_to_grid_series_kw = ArrayField( + net_metering_electric_to_grid_series_kw = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of power exports to the grid up to net metering limit for each timestep." ) - NEM_monthly_export_series_kwh = ArrayField( + net_metering_monthly_export_series_kwh = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Year one cost of electricity consumed in each month." ) - NEM_monthly_export_cost_benefit_before_tax = ArrayField( + net_metering_monthly_export_cost_benefit_before_tax = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Year one cost of electricity consumed in each month." ) - WHL_export_rate_series = ArrayField( + wholesale_export_rate_series = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of compensation rate in each timestep for exporting power to grid for wholesale." ) - WHL_electric_to_grid_series_kw = ArrayField( + wholesale_electric_to_grid_series_kw = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of power exports to the grid for wholesale in each timestep." ) - WHL_monthly_export_series_kwh = ArrayField( + wholesale_monthly_export_series_kwh = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of monthly energy exports to grid under wholesale benefit." ) - WHL_monthly_export_cost_benefit_before_tax = ArrayField( + wholesale_monthly_export_cost_benefit_before_tax = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of monthly monetary benefit from exporting power to grid at wholesale rate." ) - EXC_export_rate_series = ArrayField( + net_metering_excess_export_rate_series = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of compensation rate in each timestep for exporting power to grid beyond net metering limit." ) - EXC_electric_to_grid_series_kw = ArrayField( + net_metering_excess_electric_to_grid_series_kw = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of power exports to the grid above net metering limit for each timestep." ) - EXC_monthly_export_series_kwh = ArrayField( + net_metering_excess_monthly_export_series_kwh = ArrayField( models.FloatField( null=True, blank=True ), default=list, help_text="Series of monthly energy exports to grid above net metering limit." ) - EXC_monthly_export_cost_benefit_before_tax = ArrayField( + net_metering_excess_monthly_export_cost_benefit_before_tax = ArrayField( models.FloatField( null=True, blank=True ), From 1a3e4fd84dada8ab012ee2fcffca42a52621d134 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 17:24:28 -0600 Subject: [PATCH 12/18] Update ElectricTariffInputs urdb_metadata from Julia in process_results --- julia_src/Manifest.toml | 4 ++-- julia_src/http.jl | 11 ++++++++++- reoptjl/src/process_results.py | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 794ce8c5e..88fc351af 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -948,11 +948,11 @@ version = "1.11.0" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "dc4c262d7bab3c195154f48daa92451cf8769fea" +git-tree-sha1 = "18d4e3f1c74fa7804716f9fedf53f9c0755c7248" repo-rev = "elec_util_usage" repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.55.0" +version = "0.55.1" [[deps.Random]] deps = ["SHA"] diff --git a/julia_src/http.jl b/julia_src/http.jl index 817b8837d..4674fd24e 100644 --- a/julia_src/http.jl +++ b/julia_src/http.jl @@ -237,6 +237,14 @@ function reopt(req::HTTP.Request) high_temp_storage_dict = Dict(key=>getfield(model_inputs.s.storage.attr["HighTempThermalStorage"], key) for key in inputs_with_defaults_from_julia_high_temp_storage) else high_temp_storage_dict = Dict() + end + if haskey(d, "ElectricTariff") && !isempty(get(d["ElectricTariff"], "urdb_metadata", Dict())) + inputs_from_julia_electric_tariff = [ + :urdb_metadata + ] + electric_tariff_dict = Dict(key=>getfield(model_inputs.s.electric_tariff, key) for key in inputs_from_julia_electric_tariff) + else + electric_tariff_dict = Dict() end inputs_with_defaults_set_in_julia = Dict( "Financial" => Dict(key=>getfield(model_inputs.s.financial, key) for key in inputs_with_defaults_from_julia_financial), @@ -253,7 +261,8 @@ function reopt(req::HTTP.Request) "ElectricStorage" => electric_storage_dict, "ColdThermalStorage" => cold_storage_dict, "HotThermalStorage" => hot_storage_dict, - "HighTempThermalStorage" => high_temp_storage_dict + "HighTempThermalStorage" => high_temp_storage_dict, + "ElectricTariff" => electric_tariff_dict ) catch e @error "Something went wrong in REopt optimization!" exception=(e, catch_backtrace()) diff --git a/reoptjl/src/process_results.py b/reoptjl/src/process_results.py index 20b26e209..22bf0a292 100644 --- a/reoptjl/src/process_results.py +++ b/reoptjl/src/process_results.py @@ -9,7 +9,7 @@ SteamTurbineOutputs, GHPInputs, GHPOutputs, ExistingChillerInputs, \ ElectricHeaterOutputs, ASHPSpaceHeaterOutputs, ASHPWaterHeaterOutputs, \ SiteInputs, ASHPSpaceHeaterInputs, ASHPWaterHeaterInputs, CSTInputs, CSTOutputs, PVInputs, \ - HighTempThermalStorageInputs, HighTempThermalStorageOutputs + HighTempThermalStorageInputs, HighTempThermalStorageOutputs, ElectricTariffInputs import numpy as np import sys import traceback as tb @@ -179,6 +179,9 @@ def update_inputs_in_database(inputs_to_update: dict, run_uuid: str) -> None: if inputs_to_update.get("HighTempThermalStorage") is not None: prune_update_fields(HighTempThermalStorageInputs, inputs_to_update["HighTempThermalStorage"]) HighTempThermalStorageInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["HighTempThermalStorage"]) + if inputs_to_update.get("ElectricTariff"): + prune_update_fields(ElectricTariffInputs, inputs_to_update["ElectricTariff"]) + ElectricTariffInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["ElectricTariff"]) except Exception as e: exc_type, exc_value, exc_traceback = sys.exc_info() debug_msg = "exc_type: {}; exc_value: {}; exc_traceback: {}".format( From 242dede222411baeefdc5ccdc67e1b8db39cb1d9 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 20:37:18 -0600 Subject: [PATCH 13/18] Avoid error handling breakdown if ElectricTariff is not present, and fix check for urdb_metadata --- julia_src/http.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/julia_src/http.jl b/julia_src/http.jl index 4674fd24e..b59e8f418 100644 --- a/julia_src/http.jl +++ b/julia_src/http.jl @@ -238,7 +238,7 @@ function reopt(req::HTTP.Request) else high_temp_storage_dict = Dict() end - if haskey(d, "ElectricTariff") && !isempty(get(d["ElectricTariff"], "urdb_metadata", Dict())) + if haskey(d, "ElectricTariff") && !isempty(model_inputs.s.electric_tariff.urdb_metadata) inputs_from_julia_electric_tariff = [ :urdb_metadata ] @@ -283,9 +283,11 @@ function reopt(req::HTTP.Request) if isempty(error_response) @info "REopt model solved with status $(results["status"])." - # these are matrices that need to be vector. - results["ElectricTariff"]["year_one_electric_to_load_energy_cost_series_before_tax"] = results["ElectricTariff"]["year_one_electric_to_load_energy_cost_series_before_tax"][:,1] - results["ElectricTariff"]["monthly_facility_demand_cost_series_before_tax"] = results["ElectricTariff"]["monthly_facility_demand_cost_series_before_tax"][:,1] + # These are matrices that need to be vector. + if haskey(results, "ElectricTariff") + results["ElectricTariff"]["year_one_electric_to_load_energy_cost_series_before_tax"] = results["ElectricTariff"]["year_one_electric_to_load_energy_cost_series_before_tax"][:,1] + results["ElectricTariff"]["monthly_facility_demand_cost_series_before_tax"] = results["ElectricTariff"]["monthly_facility_demand_cost_series_before_tax"][:,1] + end response = Dict( "results" => results, "reopt_version" => string(pkgversion(reoptjl)) From 8260d010970ea1d98c659d2857c0f0e34d3a7f3a Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 20:37:52 -0600 Subject: [PATCH 14/18] Update to latest REopt#elec_util_usage --- julia_src/Manifest.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 88fc351af..a9dd913a1 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -948,7 +948,7 @@ version = "1.11.0" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "18d4e3f1c74fa7804716f9fedf53f9c0755c7248" +git-tree-sha1 = "0a5d1d2a086cd400d9b0e4758b34da51a07d6dbd" repo-rev = "elec_util_usage" repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" From 60d90fe9c5430b8b01a6a0f5c23de85625ba6661 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 22 Oct 2025 20:38:53 -0600 Subject: [PATCH 15/18] Reduce complexity of long-solving sector defaults test --- reoptjl/test/posts/sector_defaults_post.json | 40 +++++--------------- reoptjl/test/test_job_endpoint.py | 2 - 2 files changed, 10 insertions(+), 32 deletions(-) diff --git a/reoptjl/test/posts/sector_defaults_post.json b/reoptjl/test/posts/sector_defaults_post.json index 1df5abbae..ca174468f 100644 --- a/reoptjl/test/posts/sector_defaults_post.json +++ b/reoptjl/test/posts/sector_defaults_post.json @@ -23,44 +23,24 @@ "ExistingBoiler": { "fuel_cost_per_mmbtu": 10.0 }, - "CHP": { - "prime_mover": "recip_engine", - "max_kw": 100, - "fuel_cost_per_mmbtu": 10.0, - "can_supply_steam_turbine": true - }, "PV": { "min_kw": 1000.0, "max_kw": 1000.0, "federal_itc_fraction": 0.2 }, - "SteamTurbine":{ - "min_kw": 100, - "max_kw": 100 - }, - "HighTempThermalStorage": { - "min_kwh": 10, - "max_kwh": 10, - "thermal_decay_rate_fraction": 0.0 - }, "Wind": { "min_kw": 100, "max_kw": 100 }, - "GHP": { - "require_ghp_purchase": true, - "building_sqft": 50000.0, - "can_serve_dhw": false, - "space_heating_efficiency_thermal_factor": 0.85, - "cooling_efficiency_thermal_factor": 0.6, - "ghpghx_inputs": [{ - "borehole_depth_ft": 400.0, - "simulation_years": 20, - "solver_eft_tolerance_f": 2.0, - "ghx_model": "TESS", - "tess_ghx_minimum_timesteps_per_hour": 1, - "max_sizing_iterations": 10, - "init_sizing_factor_ft_per_peak_ton": 300.0 - }] + "ElectricStorage": { + "min_kw": 50, + "max_kw": 50, + "min_kwh": 100, + "max_kwh": 100 + }, + "Boiler": { + "fuel_cost_per_mmbtu": 10.0, + "min_mmbtu_per_hour": 0.5, + "max_mmbtu_per_hour": 0.5 } } \ No newline at end of file diff --git a/reoptjl/test/test_job_endpoint.py b/reoptjl/test/test_job_endpoint.py index 6f74663aa..f880ba921 100644 --- a/reoptjl/test/test_job_endpoint.py +++ b/reoptjl/test/test_job_endpoint.py @@ -178,8 +178,6 @@ def test_sector_defaults_from_julia(self): self.assertEqual(saved_model_inputs.get(input_key), post[model_name][input_key]) else: # Check that default got assigned consistent with /sector_defaults - if model_name == "SteamTurbine" and input_key == "federal_itc_fraction": - continue #ST doesn't have federal_itc_fraction input self.assertEqual(saved_model_inputs.get(input_key), default_input_val) def test_chp_defaults_from_julia(self): From 6b5099b163ad75f0bc92a6893c4067b77d4652fa Mon Sep 17 00:00:00 2001 From: Grant Ellwood <120485824+gellwood@users.noreply.github.com> Date: Thu, 23 Oct 2025 12:04:23 -0700 Subject: [PATCH 16/18] Update ANCCR table config to use outputs.* keys and add new fields Updated all references from 'ElectricTariff.*' and 'ElectricLoad.*' to 'outputs.ElectricTariff.*' and 'outputs.ElectricLoad.*' for BAU values in the ANCCR custom table configuration. Added new fields to pull additional metadata from 'inputs.ElectricTariff.urdb_metadata'. Added placeholder calculations for ANCCR percent change and percent of total bill metrics. Also updated or clarified some field labels and keys for consistency. --- reoptjl/custom_table_config.py | 208 ++++++++++++++++++++------------- 1 file changed, 129 insertions(+), 79 deletions(-) diff --git a/reoptjl/custom_table_config.py b/reoptjl/custom_table_config.py index 3beb1d4b7..8d7dd6889 100644 --- a/reoptjl/custom_table_config.py +++ b/reoptjl/custom_table_config.py @@ -1240,6 +1240,43 @@ "name": "Placeholder Calculation With BAU Reference", "formula": lambda col, bau, headers: f'=({bau["placeholder1_value"]}-{col}{headers["Placeholder2"] + 2})/{bau["placeholder1_value"]}' # This formula calculates the percentage change of Placeholder2 using Placeholder1's BAU value as the reference. + }, + + # ANCCR Calculations -- none of these are used yet because the current in-spreadsheet calcs to not compare BAU to BAU + { + "name": "Year 1 Total Bill Charges Percent Change (%)", + "formula": lambda col, bau, headers: f'= {col}{headers["Placeholder1"] + 2}+{col}{headers["Placeholder2"] + 2}' ### need to update this + # This formula calculates the change in year 1 costs from BAU_alt_rate_x vs. BAU_current_rate + }, + { + "name": "Year 1 Fixed Charges Percent Change (%)", + "formula": lambda col, bau, headers: f'= {col}{headers["Placeholder1"] + 2}+{col}{headers["Placeholder2"] + 2}' ### need to update this + # This formula calculates the change in year 1 costs from BAU_alt_rate_x vs. BAU_current_rate + }, + { + "name": "Year 1 Energy Charges Percent Change (%)", + "formula": lambda col, bau, headers: f'= {col}{headers["Placeholder1"] + 2}+{col}{headers["Placeholder2"] + 2}' ### need to update this + # This formula calculates the change in year 1 costs from BAU_alt_rate_x vs. BAU_current_rate + }, + { + "name": "Year 1 Demand Charges Percent Change (%)", + "formula": lambda col, bau, headers: f'= {col}{headers["Placeholder1"] + 2}+{col}{headers["Placeholder2"] + 2}' ### need to update this + # This formula calculates the change in year 1 costs from BAU_alt_rate_x vs. BAU_current_rate + }, + { + "name": "Year 1 Fixed Charges Percent of Total Bill (%)", + "formula": lambda col, bau, headers: f'= {col}{headers["Placeholder1"] + 2}+{col}{headers["Placeholder2"] + 2}' ### need to update this + # This formula calculates the change in year 1 costs from BAU_alt_rate_x vs. BAU_current_rate + }, + { + "name": "Year 1 Energy Charges Percent of Total Bill (%)", + "formula": lambda col, bau, headers: f'= {col}{headers["Placeholder1"] + 2}+{col}{headers["Placeholder2"] + 2}' ### need to update this + # This formula calculates the change in year 1 costs from BAU_alt_rate_x vs. BAU_current_rate + }, + { + "name": "Year 1 Demand Charges Percent of Total Bill (%)", + "formula": lambda col, bau, headers: f'= {col}{headers["Placeholder1"] + 2}+{col}{headers["Placeholder2"] + 2}' ### need to update this + # This formula calculates the change in year 1 costs from BAU_alt_rate_x vs. BAU_current_rate } ] @@ -1260,23 +1297,23 @@ ##################################################################################################### ################################ General Information ################################ ##################################################################################################### - +# maybe we remove this section since we are missing installation name and site location from REopt results { - "label": "Installation Name", # Not REopt result; Name based on UTRMS Data + "label": "Installation Name", # Not REopt result; Name based on UTRMS Data -- maybe we delete? "key": "installation_name", "bau_value": lambda df: "", "scenario_value": lambda df: "" }, { - "label": "Site Location", # Not REopt result; Name based on User input + "label": "Site Location", # Not REopt result; Name based on User input -- maybe we delete? "key": "site_location", "bau_value": lambda df: "", "scenario_value": lambda df: "" }, { - "label": "Utility Name", # Not REopt result; Name based on User input + "label": "Utility Name", "key": "utility_name", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_utility", ""), "scenario_value": lambda df: "" }, @@ -1291,44 +1328,45 @@ "scenario_value": lambda df: "" }, { - "label": "Rate Name", # Not REopt result; Name based on User input + "label": "Rate Name", "key": "rate_name", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_rate_name", ""), "scenario_value": lambda df: "" }, { - "label": "Voltage Level", # Not REopt result; Name based on User input + "label": "Voltage Level", "key": "voltage_level", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.", ""), "scenario_value": lambda df: "" }, { "label": "Year 1 Fixed Charges ($)", "key": "year_1_fixed_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_fixed_cost_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_fixed_cost_before_tax_bau"), "scenario_value": lambda df: "" }, { "label": "Year 1 Energy Charges ($)", "key": "year_1_energy_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_energy_cost_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_energy_cost_before_tax_bau"), "scenario_value": lambda df: "" }, { "label": "Year 1 Demand Charges ($)", "key": "year_1_demand_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_demand_cost_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_demand_cost_before_tax_bau"), "scenario_value": lambda df: "" }, { "label": "Year 1 Total Bill Charges ($)", "key": "year_1_total_bill_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_bill_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_bill_before_tax_bau"), "scenario_value": lambda df: "" }, + # Calculated Value { - "label": "Change in Year 1 Charges ($)", # this value will need to be calculated compared to the current rate - "key": "change_in_year_1_charges", + "label": "Year 1 Total Bill Charges Percent Change (%)", # this value will need to be calculated compared to the current rate + "key": "year_1_total_bill_charges_percent_change", "bau_value": lambda df: "", "scenario_value": lambda df: "" }, @@ -1346,7 +1384,7 @@ { "label": "Year 1 Fixed Charges ($)", "key": "year_1_fixed_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_fixed_cost_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_fixed_cost_before_tax_bau"), "scenario_value": lambda df: "" }, { @@ -1358,7 +1396,7 @@ { "label": "Year 1 Energy Charges ($)", "key": "year_1_energy_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_energy_cost_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_energy_cost_before_tax_bau"), "scenario_value": lambda df: "" }, { @@ -1370,7 +1408,7 @@ { "label": "Year 1 Demand Charges ($)", "key": "year_1_demand_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_demand_cost_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_demand_cost_before_tax_bau"), "scenario_value": lambda df: "" }, { @@ -1382,7 +1420,7 @@ { "label": "Year 1 Total Bill Charges ($)", "key": "year_1_total_bill_charges", - "bau_value": lambda df: safe_get(df, "ElectricTariff.year_one_bill_before_tax_bau"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.year_one_bill_before_tax_bau"), "scenario_value": lambda df: "" }, { @@ -1434,13 +1472,13 @@ { "label": "Annual Grid Purchases (kWh)", "key": "annual_grid_purchases_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.annual_calculated_kwh"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.annual_calculated_kwh"), "scenario_value": lambda df: "" }, { "label": "Year 1 Peak Load (kW)", "key": "year_1_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.annual_peak_kw"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.annual_peak_kw"), "scenario_value": lambda df: "" }, @@ -1453,64 +1491,76 @@ "bau_value": lambda df: "", "scenario_value": lambda df: "" }, + { + "label": "Rate Name", # Not REopt result; Name based on User input + "key": "rate_name", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_rate_name", ""), + "scenario_value": lambda df: "" + }, { "label": "URDB Label", # will need to pull from URDB "key": "urdb_label", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_label", ""), + "scenario_value": lambda df: "" + }, + { + "label": "Utility Name", # Not REopt result; Name based on User input + "key": "utility_name", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_utility", ""), "scenario_value": lambda df: "" }, { "label": "Rate Effective Date (latest_update)", # will need to pull from URDB "key": "rate_effective_date", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_rate_effective_date", ""), "scenario_value": lambda df: "" }, { "label": "Voltage Level (voltagecategory)", # will need to pull from URDB "key": "voltage_level_urdb", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_voltage_level", ""), "scenario_value": lambda df: "" }, { "label": "Peak kW Capacity Min (peakkwcapacitymin)", # will need to pull from URDB "key": "peak_kw_capacity_min", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_peak_kw_capacity_min", ""), "scenario_value": lambda df: "" }, { "label": "Peak kW Capacity Max (peakkwcapacitymax)", # will need to pull from URDB "key": "peak_kw_capacity_max", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_peak_kw_capacity_max", ""), "scenario_value": lambda df: "" }, { "label": "Rate Description (description)", # will need to pull from URDB "key": "rate_description", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_rate_description", ""), "scenario_value": lambda df: "" }, { "label": "Additional Information (basicinformationcomments)", # will need to pull from URDB "key": "additional_information", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_rate_additional_info", ""), "scenario_value": lambda df: "" }, { "label": "Energy Comments (energycomments)", # will need to pull from URDB "key": "energy_comments", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_energy_comments", ""), "scenario_value": lambda df: "" }, { "label": "Demand Comments (demandcomments)", # will need to pull from URDB "key": "demand_comments", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_demand_comments", ""), "scenario_value": lambda df: "" }, { "label": "URDB Link", # will need to pull from URDB "key": "urdb_link", - "bau_value": lambda df: "", + "bau_value": lambda df: safe_get(df, "inputs.ElectricTariff.urdb_metadata.urdb_url_link", ""), "scenario_value": lambda df: "" }, @@ -1527,73 +1577,73 @@ { "label": "January Energy Cost ($)", "key": "january_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.0"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.0"), "scenario_value": lambda df: "" }, { "label": "February Energy Cost ($)", "key": "february_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.1"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.1"), "scenario_value": lambda df: "" }, { "label": "March Energy Cost ($)", "key": "march_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.2"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.2"), "scenario_value": lambda df: "" }, { "label": "April Energy Cost ($)", "key": "april_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.3"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.3"), "scenario_value": lambda df: "" }, { "label": "May Energy Cost ($)", "key": "may_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.4"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.4"), "scenario_value": lambda df: "" }, { "label": "June Energy Cost ($)", "key": "june_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.5"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.5"), "scenario_value": lambda df: "" }, { "label": "July Energy Cost ($)", "key": "july_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.6"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.6"), "scenario_value": lambda df: "" }, { "label": "August Energy Cost ($)", "key": "august_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.7"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.7"), "scenario_value": lambda df: "" }, { "label": "September Energy Cost ($)", "key": "september_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.8"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.8"), "scenario_value": lambda df: "" }, { "label": "October Energy Cost ($)", "key": "october_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.9"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.9"), "scenario_value": lambda df: "" }, { "label": "November Energy Cost ($)", "key": "november_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.10"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.10"), "scenario_value": lambda df: "" }, { "label": "December Energy Cost ($)", "key": "december_energy_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.11"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_electric_to_load_energy_cost_series_before_tax.11"), "scenario_value": lambda df: "" }, @@ -1610,73 +1660,73 @@ { "label": "January Demand Cost ($)", "key": "january_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.0") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.0"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.0") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.0"), "scenario_value": lambda df: "" }, { "label": "February Demand Cost ($)", "key": "february_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.1") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.1"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.1") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.1"), "scenario_value": lambda df: "" }, { "label": "March Demand Cost ($)", "key": "march_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.2") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.2"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.2") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.2"), "scenario_value": lambda df: "" }, { "label": "April Demand Cost ($)", "key": "april_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.3") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.3"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.3") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.3"), "scenario_value": lambda df: "" }, { "label": "May Demand Cost ($)", "key": "may_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.4") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.4"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.4") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.4"), "scenario_value": lambda df: "" }, { "label": "June Demand Cost ($)", "key": "june_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.5") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.5"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.5") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.5"), "scenario_value": lambda df: "" }, { "label": "July Demand Cost ($)", "key": "july_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.6") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.6"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.6") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.6"), "scenario_value": lambda df: "" }, { "label": "August Demand Cost ($)", "key": "august_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.7") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.7"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.7") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.7"), "scenario_value": lambda df: "" }, { "label": "September Demand Cost ($)", "key": "september_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.8") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.8"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.8") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.8"), "scenario_value": lambda df: "" }, { "label": "October Demand Cost ($)", "key": "october_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.9") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.9"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.9") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.9"), "scenario_value": lambda df: "" }, { "label": "November Demand Cost ($)", "key": "november_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.10") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.10"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.10") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.10"), "scenario_value": lambda df: "" }, { "label": "December Demand Cost ($)", "key": "december_demand_cost", - "bau_value": lambda df: safe_get(df, "ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.11") + safe_get(df, "ElectricTariff.monthly_facility_demand_cost_series_before_tax.11"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricTariff.monthly_gross_tou_demand_cost_series_before_tax.11") + safe_get(df, "outputs.ElectricTariff.monthly_facility_demand_cost_series_before_tax.11"), "scenario_value": lambda df: "" }, @@ -1776,73 +1826,73 @@ { "label": "January Energy Consumption (kWh)", "key": "january_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.0"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.0"), "scenario_value": lambda df: "" }, { "label": "February Energy Consumption (kWh)", "key": "february_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.1"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.1"), "scenario_value": lambda df: "" }, { "label": "March Energy Consumption (kWh)", "key": "march_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.2"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.2"), "scenario_value": lambda df: "" }, { "label": "April Energy Consumption (kWh)", "key": "april_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.3"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.3"), "scenario_value": lambda df: "" }, { "label": "May Energy Consumption (kWh)", "key": "may_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.4"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.4"), "scenario_value": lambda df: "" }, { "label": "June Energy Consumption (kWh)", "key": "june_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.5"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.5"), "scenario_value": lambda df: "" }, { "label": "July Energy Consumption (kWh)", "key": "july_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.6"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.6"), "scenario_value": lambda df: "" }, { "label": "August Energy Consumption (kWh)", "key": "august_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.7"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.7"), "scenario_value": lambda df: "" }, { "label": "September Energy Consumption (kWh)", "key": "september_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.8"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.8"), "scenario_value": lambda df: "" }, { "label": "October Energy Consumption (kWh)", "key": "october_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.9"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.9"), "scenario_value": lambda df: "" }, { "label": "November Energy Consumption (kWh)", "key": "november_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.10"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.10"), "scenario_value": lambda df: "" }, { "label": "December Energy Consumption (kWh)", "key": "december_energy_consumption_kwh", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_calculated_kwh.11"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_calculated_kwh.11"), "scenario_value": lambda df: "" }, @@ -1859,73 +1909,73 @@ { "label": "January Peak Load (kW)", "key": "january_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.0"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.0"), "scenario_value": lambda df: "" }, { "label": "February Peak Load (kW)", "key": "february_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.1"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.1"), "scenario_value": lambda df: "" }, { "label": "March Peak Load (kW)", "key": "march_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.2"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.2"), "scenario_value": lambda df: "" }, { "label": "April Peak Load (kW)", "key": "april_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.3"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.3"), "scenario_value": lambda df: "" }, { "label": "May Peak Load (kW)", "key": "may_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.4"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.4"), "scenario_value": lambda df: "" }, { "label": "June Peak Load (kW)", "key": "june_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.5"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.5"), "scenario_value": lambda df: "" }, { "label": "July Peak Load (kW)", "key": "july_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.6"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.6"), "scenario_value": lambda df: "" }, { "label": "August Peak Load (kW)", "key": "august_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.7"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.7"), "scenario_value": lambda df: "" }, { "label": "September Peak Load (kW)", "key": "september_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.8"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.8"), "scenario_value": lambda df: "" }, { "label": "October Peak Load (kW)", "key": "october_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.9"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.9"), "scenario_value": lambda df: "" }, { "label": "November Peak Load (kW)", "key": "november_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.10"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.10"), "scenario_value": lambda df: "" }, { "label": "December Peak Load (kW)", "key": "december_peak_load_kw", - "bau_value": lambda df: safe_get(df, "ElectricLoad.monthly_peak_kw.11"), + "bau_value": lambda df: safe_get(df, "outputs.ElectricLoad.monthly_peak_kw.11"), "scenario_value": lambda df: "" } ] From 6cadf5b798c41dfcd7cf615f2837707eae434c8f Mon Sep 17 00:00:00 2001 From: bill-becker Date: Thu, 23 Oct 2025 16:35:33 -0600 Subject: [PATCH 17/18] Make output.ElectricLoad.monthly_peak_kw consistent with upcoming new input monthly_peaks_kw --- ..._kw_electricloadoutputs_monthly_peaks_kw.py | 18 ++++++++++++++++++ reoptjl/models.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 reoptjl/migrations/0113_rename_monthly_peak_kw_electricloadoutputs_monthly_peaks_kw.py diff --git a/reoptjl/migrations/0113_rename_monthly_peak_kw_electricloadoutputs_monthly_peaks_kw.py b/reoptjl/migrations/0113_rename_monthly_peak_kw_electricloadoutputs_monthly_peaks_kw.py new file mode 100644 index 000000000..625c6323c --- /dev/null +++ b/reoptjl/migrations/0113_rename_monthly_peak_kw_electricloadoutputs_monthly_peaks_kw.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.25 on 2025-10-23 22:33 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0112_rename_nem_electric_to_grid_series_kw_electrictariffoutputs_net_metering_electric_to_grid_series_kw_'), + ] + + operations = [ + migrations.RenameField( + model_name='electricloadoutputs', + old_name='monthly_peak_kw', + new_name='monthly_peaks_kw', + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 59786030a..b46c33482 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -1553,7 +1553,7 @@ class ElectricLoadOutputs(BaseModel, models.Model): default=list, help_text="Monthly energy consumption calculated by summing up load_series_kw. Does not include electric load for any new heating or cooling techs." ) - monthly_peak_kw = ArrayField( + monthly_peaks_kw = ArrayField( models.FloatField( null=True, blank=True ), From 08f8e1e12fcfee902bf7d7d2ac93f65bc4da5231 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Thu, 23 Oct 2025 19:01:49 -0600 Subject: [PATCH 18/18] Update REopt#elec_util_usage for updated monthly_peaks_kw name --- julia_src/Manifest.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index a9dd913a1..16e510202 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -948,7 +948,7 @@ version = "1.11.0" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "0a5d1d2a086cd400d9b0e4758b34da51a07d6dbd" +git-tree-sha1 = "277df4545cd30a5fc227bf982897ef65d5ea3520" repo-rev = "elec_util_usage" repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6"