From d8d18135fb9254934830441a5b3fcbb9b6b4f213 Mon Sep 17 00:00:00 2001 From: adfarth Date: Thu, 20 Mar 2025 09:44:26 -0600 Subject: [PATCH 01/24] add new inputs --- reoptjl/models.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/reoptjl/models.py b/reoptjl/models.py index 47d088f7a..c222d20f6 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -786,6 +786,24 @@ class FinancialInputs(BaseModel, models.Model): default=0.0, help_text=("Only applicable when off_grid_flag is true. These per year costs are considered tax deductible for owner.") ) + min_initial_capital_costs_before_incentives = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1e12) + ], + blank=True, + null=True, + help_text=("Minimum up-front capital cost for all technologies, excluding replacement costs and incentives.") + ) + max_initial_capital_costs_before_incentives = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1e12) + ], + blank=True, + null=True, + help_text=("Maximum up-front capital cost for all technologies, excluding replacement costs and incentives.") + ) CO2_cost_per_tonne = models.FloatField( validators=[ MinValueValidator(0), From bad79cc91faace2633cac4d09ef764e1a0c77e06 Mon Sep 17 00:00:00 2001 From: adfarth Date: Tue, 15 Apr 2025 15:46:08 -0600 Subject: [PATCH 02/24] changelog and all_inputs test --- CHANGELOG.md | 7 ++++++- reoptjl/test/posts/all_inputs_test.json | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d2b8ec87..73c856100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,9 +26,14 @@ Classify the change according to the following categories: ##### Removed ### Patches +## add-capex-constraint +### Minor Updates +#### Added +- Add **Financial** inputs **min_initial_capital_costs_before_incentives** and **max_initial_capital_costs_before_incentives** + ## v3.12.0 ### Major Updates -### Added +#### Added - Add inputs: - **ElectricUtility.cambium_cef_metric** to utilize clean energy data from NREL's Cambium database - **ElectricUtility.renewable_energy_fraction_series** to supply a custom grid clean or renewable energy scalar or series diff --git a/reoptjl/test/posts/all_inputs_test.json b/reoptjl/test/posts/all_inputs_test.json index 6811af43c..78fa2a4a2 100644 --- a/reoptjl/test/posts/all_inputs_test.json +++ b/reoptjl/test/posts/all_inputs_test.json @@ -26,7 +26,9 @@ "PM25_onsite_fuelburn_cost_per_tonne": null, "NOx_cost_escalation_rate_fraction": null, "SO2_cost_escalation_rate_fraction": null, - "PM25_cost_escalation_rate_fraction": null + "PM25_cost_escalation_rate_fraction": null, + "min_initial_capital_costs_before_incentives": null, + "max_initial_capital_costs_before_incentives": null }, "ElectricLoad": { "annual_kwh": 190000.0, From 18e58c5e6ed275827b681688120f80239bf46481 Mon Sep 17 00:00:00 2001 From: Kadlec Date: Tue, 22 Apr 2025 10:45:58 -0600 Subject: [PATCH 03/24] testing ghp inputs --- ...1_ghpinputs_load_served_by_ghp_and_more.py | 29 +++++++++++++++++++ reoptjl/models.py | 26 +++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 reoptjl/migrations/0081_ghpinputs_load_served_by_ghp_and_more.py diff --git a/reoptjl/migrations/0081_ghpinputs_load_served_by_ghp_and_more.py b/reoptjl/migrations/0081_ghpinputs_load_served_by_ghp_and_more.py new file mode 100644 index 000000000..d6a2f6a59 --- /dev/null +++ b/reoptjl/migrations/0081_ghpinputs_load_served_by_ghp_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.0.7 on 2025-04-22 16:44 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0080_electricloadoutputs_annual_electric_load_with_thermal_conversions_kwh_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='ghpinputs', + name='load_served_by_ghp', + field=models.TextField(blank=True, default='nonpeak', help_text='How to split between load served by GHP and load served by backup system'), + ), + migrations.AddField( + model_name='ghpinputs', + name='max_number_of_boreholes', + field=models.FloatField(blank=True, help_text='Maximum number of boreholes for GHX', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), + ), + migrations.AddField( + model_name='ghpinputs', + name='max_ton', + field=models.FloatField(blank=True, help_text='Maximum thermal power size constraint for GHP [ton]', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 47d088f7a..a525c268e 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -8261,6 +8261,32 @@ class GHPInputs(BaseModel, models.Model): blank=True, help_text="Maximum utility rebate" ) + max_ton = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(MAX_BIG_NUMBER) + ], + null=True, + blank=True, + help_text=("Maximum thermal power size constraint for GHP [ton]") + ) + + max_number_of_boreholes = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(MAX_BIG_NUMBER) + ], + null=True, + blank=True, + help_text=("Maximum number of boreholes for GHX") + ) + + load_served_by_ghp = models.TextField( + null=False, + blank=True, + default="nonpeak", + help_text="How to split between load served by GHP and load served by backup system" + ) def clean(self): From 796ea99f258cefe72a4cba204e4eaf22ed6b0512 Mon Sep 17 00:00:00 2001 From: Kadlec Date: Tue, 22 Apr 2025 13:20:22 -0600 Subject: [PATCH 04/24] debugging test --- reoptjl/testing.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 reoptjl/testing.txt diff --git a/reoptjl/testing.txt b/reoptjl/testing.txt new file mode 100644 index 000000000..e69de29bb From e3011e1571e390f2e621fdd2ee0dc037c592ad2f Mon Sep 17 00:00:00 2001 From: Kadlec Date: Wed, 23 Apr 2025 14:42:46 -0600 Subject: [PATCH 05/24] update manifest.toml --- 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 6729da562..4d0f7a141 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 = "24f902b6f67ed1d4389d21b5d42f820036b182b4" +git-tree-sha1 = "9fe6797d461a708e7b853a7236d835b076c516b7" +repo-rev = "allow_presized_GHP_GHX" +repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.51.0" +version = "0.51.1" [[deps.Random]] deps = ["SHA"] From f523baa051bef837202f800f9910bae931b355f8 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 23 Apr 2025 15:52:51 -0600 Subject: [PATCH 06/24] Merge migration after merging develop --- reoptjl/migrations/0084_merge_20250423_2110.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 reoptjl/migrations/0084_merge_20250423_2110.py diff --git a/reoptjl/migrations/0084_merge_20250423_2110.py b/reoptjl/migrations/0084_merge_20250423_2110.py new file mode 100644 index 000000000..8ea012a9b --- /dev/null +++ b/reoptjl/migrations/0084_merge_20250423_2110.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-04-23 21:10 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0081_ghpinputs_load_served_by_ghp_and_more'), + ('reoptjl', '0083_electricutilityoutputs_peak_grid_demand_kw_and_more'), + ] + + operations = [ + ] From cc225e822f248c7bf9efb41c998de1f8ef78344d Mon Sep 17 00:00:00 2001 From: Kadlec Date: Thu, 24 Apr 2025 08:47:59 -0600 Subject: [PATCH 07/24] adding ghp outputs --- ...nnual_thermal_production_mmbtu_and_more.py | 23 +++++++++++++++++++ reoptjl/models.py | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 reoptjl/migrations/0085_ghpoutputs_annual_thermal_production_mmbtu_and_more.py diff --git a/reoptjl/migrations/0085_ghpoutputs_annual_thermal_production_mmbtu_and_more.py b/reoptjl/migrations/0085_ghpoutputs_annual_thermal_production_mmbtu_and_more.py new file mode 100644 index 000000000..fe4a5e62b --- /dev/null +++ b/reoptjl/migrations/0085_ghpoutputs_annual_thermal_production_mmbtu_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.7 on 2025-04-24 14:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0084_merge_20250423_2110'), + ] + + operations = [ + migrations.AddField( + model_name='ghpoutputs', + name='annual_thermal_production_mmbtu', + field=models.FloatField(blank=True, null=True), + ), + migrations.AddField( + model_name='ghpoutputs', + name='annual_thermal_production_tonhour', + field=models.FloatField(blank=True, null=True), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index b46237980..ddc2c0363 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -8435,6 +8435,8 @@ class GHPOutputs(BaseModel, models.Model): thermal_to_dhw_load_series_mmbtu_per_hour = ArrayField(models.FloatField(null=True, blank=True), default=list, null=True, blank=True) thermal_to_load_series_ton = ArrayField(models.FloatField(null=True, blank=True), default=list, null=True, blank=True) avoided_capex_by_ghp_present_value = models.FloatField(null=True, blank=True) + annual_thermal_production_mmbtu = models.FloatField(null=True, blank=True) + annual_thermal_production_tonhour = models.FloatField(null=True, blank=True) def get_input_dict_from_run_uuid(run_uuid:str): """ From 54f1fbc689321d7d0efdedefc0f4a7096b10674d Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 7 May 2025 22:44:21 -0600 Subject: [PATCH 08/24] point to develop --- julia_src/Manifest.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index fc3e1581e..059884dd5 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -922,7 +922,9 @@ 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 = "9946abe774e30d82f786e68296ad1fdf8bb7dba4" +git-tree-sha1 = "1592ea6abdb85725cd5504f4808575caea89727c" +repo-rev = "develop" +repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" version = "0.51.1" From 43740b3f954be988cec55ec937eb446823484527 Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 7 May 2025 22:50:07 -0600 Subject: [PATCH 09/24] Create 0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py --- ...apital_costs_before_incentives_and_more.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py diff --git a/reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py b/reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py new file mode 100644 index 000000000..340656305 --- /dev/null +++ b/reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.7 on 2025-05-08 04:49 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0084_merge_20250424_1814'), + ] + + operations = [ + migrations.AddField( + model_name='financialinputs', + name='max_initial_capital_costs_before_incentives', + field=models.FloatField(blank=True, help_text='Maximum up-front capital cost for all technologies, excluding replacement costs and incentives.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000000.0)]), + ), + migrations.AddField( + model_name='financialinputs', + name='min_initial_capital_costs_before_incentives', + field=models.FloatField(blank=True, help_text='Minimum up-front capital cost for all technologies, excluding replacement costs and incentives.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000000.0)]), + ), + ] From 4dd75106f757610855abe6dd7d74d1fb57493165 Mon Sep 17 00:00:00 2001 From: adfarth Date: Thu, 8 May 2025 12:52:50 -0600 Subject: [PATCH 10/24] add chp output --- CHANGELOG.md | 1 + .../0086_chpoutputs_initial_capital_costs.py | 18 ++++++++++++++++++ reoptjl/models.py | 4 ++++ 3 files changed, 23 insertions(+) create mode 100644 reoptjl/migrations/0086_chpoutputs_initial_capital_costs.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 2637342fd..497d194a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Classify the change according to the following categories: ### Minor Updates #### Added - Add **Financial** inputs **min_initial_capital_costs_before_incentives** and **max_initial_capital_costs_before_incentives** +- Add **CHP** output **initial_capital_costs** ## v3.12.3 ### Minor Updates diff --git a/reoptjl/migrations/0086_chpoutputs_initial_capital_costs.py b/reoptjl/migrations/0086_chpoutputs_initial_capital_costs.py new file mode 100644 index 000000000..5107d9a19 --- /dev/null +++ b/reoptjl/migrations/0086_chpoutputs_initial_capital_costs.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.7 on 2025-05-08 18:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0085_financialinputs_max_initial_capital_costs_before_incentives_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='chpoutputs', + name='initial_capital_costs', + field=models.FloatField(blank=True, help_text='Initial capital costs of the CHP system, before incentives [\\$]', null=True), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 48a758e22..94ef91791 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -4746,6 +4746,10 @@ class CHPOutputs(BaseModel, models.Model): models.FloatField(null=True, blank=True), default = list, ) + initial_capital_costs = models.FloatField( + null=True, blank=True, + help_text="Initial capital costs of the CHP system, before incentives [\$]" + ) def clean(): pass From f66cab9c9b8ddd48d7446e17e0c778ea7f17733a Mon Sep 17 00:00:00 2001 From: Zolan Date: Fri, 9 May 2025 15:31:46 -0600 Subject: [PATCH 11/24] update help text to include units for min, max capital costs --- ...ts_max_initial_capital_costs_before_incentives_and_more.py | 4 ++-- reoptjl/models.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py b/reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py index 340656305..5a02b6559 100644 --- a/reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py +++ b/reoptjl/migrations/0085_financialinputs_max_initial_capital_costs_before_incentives_and_more.py @@ -14,11 +14,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name='financialinputs', name='max_initial_capital_costs_before_incentives', - field=models.FloatField(blank=True, help_text='Maximum up-front capital cost for all technologies, excluding replacement costs and incentives.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000000.0)]), + field=models.FloatField(blank=True, help_text='Maximum up-front capital cost for all technologies, excluding replacement costs and incentives [\$].', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000000.0)]), ), migrations.AddField( model_name='financialinputs', name='min_initial_capital_costs_before_incentives', - field=models.FloatField(blank=True, help_text='Minimum up-front capital cost for all technologies, excluding replacement costs and incentives.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000000.0)]), + field=models.FloatField(blank=True, help_text='Minimum up-front capital cost for all technologies, excluding replacement costs and incentives [\$].', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000000.0)]), ), ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 94ef91791..184df44a4 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -793,7 +793,7 @@ class FinancialInputs(BaseModel, models.Model): ], blank=True, null=True, - help_text=("Minimum up-front capital cost for all technologies, excluding replacement costs and incentives.") + help_text=("Minimum up-front capital cost for all technologies, excluding replacement costs and incentives [\$].") ) max_initial_capital_costs_before_incentives = models.FloatField( validators=[ @@ -802,7 +802,7 @@ class FinancialInputs(BaseModel, models.Model): ], blank=True, null=True, - help_text=("Maximum up-front capital cost for all technologies, excluding replacement costs and incentives.") + help_text=("Maximum up-front capital cost for all technologies, excluding replacement costs and incentives [\$].") ) CO2_cost_per_tonne = models.FloatField( validators=[ From 5b1c315df90f600c69717f505cd7a63157d0a4b8 Mon Sep 17 00:00:00 2001 From: adfarth Date: Fri, 9 May 2025 15:51:25 -0600 Subject: [PATCH 12/24] updt to REopt052 --- julia_src/Manifest.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 059884dd5..03d5186ee 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -922,11 +922,9 @@ 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 = "1592ea6abdb85725cd5504f4808575caea89727c" -repo-rev = "develop" -repo-url = "https://github.com/NREL/REopt.jl.git" +git-tree-sha1 = "0790dface6f78d2cadae8020470a4e73ee531f93" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.51.1" +version = "0.52.0" [[deps.Random]] deps = ["SHA"] From e989a286ea2ac296daabae3f903073167503ecd4 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Mon, 19 May 2025 15:03:46 -0600 Subject: [PATCH 13/24] Add battery cost constant terms and use branch of REopt.jl --- julia_src/Manifest.toml | 4 ++- ...cost_constant_replacement_year_and_more.py | 29 +++++++++++++++++++ reoptjl/models.py | 27 +++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 reoptjl/migrations/0085_electricstorageinputs_cost_constant_replacement_year_and_more.py diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index fc3e1581e..ed3d95fb6 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -922,7 +922,9 @@ 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 = "9946abe774e30d82f786e68296ad1fdf8bb7dba4" +git-tree-sha1 = "6615ec48a40b3098a72a76cfe0c46095fc015ec6" +repo-rev = "storage-cost-constraints-version2" +repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" version = "0.51.1" diff --git a/reoptjl/migrations/0085_electricstorageinputs_cost_constant_replacement_year_and_more.py b/reoptjl/migrations/0085_electricstorageinputs_cost_constant_replacement_year_and_more.py new file mode 100644 index 000000000..e7ef9d064 --- /dev/null +++ b/reoptjl/migrations/0085_electricstorageinputs_cost_constant_replacement_year_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.0.7 on 2025-05-19 20:33 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0084_merge_20250424_1814'), + ] + + operations = [ + migrations.AddField( + model_name='electricstorageinputs', + name='cost_constant_replacement_year', + field=models.IntegerField(blank=True, default=10, help_text='Number of years from start of analysis period to apply replace_cost_constant.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(75)]), + ), + migrations.AddField( + model_name='electricstorageinputs', + name='installed_cost_constant', + field=models.FloatField(blank=True, default=0.0, help_text='Fixed upfront cost for battery installation, independent of size.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)]), + ), + migrations.AddField( + model_name='electricstorageinputs', + name='replace_cost_constant', + field=models.FloatField(blank=True, default=0.0, help_text='Fixed replacement cost for battery, independent of size.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)]), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index fdef159a8..00ca226bd 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -3532,6 +3532,15 @@ class ElectricStorageInputs(BaseModel, models.Model): blank=True, help_text="Total upfront battery costs" ) + installed_cost_constant = models.FloatField( + default=0.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e9) + ], + blank=True, + help_text="Fixed upfront cost for battery installation, independent of size." + ) replace_cost_per_kw = models.FloatField( default=715.0, validators=[ @@ -3550,6 +3559,15 @@ class ElectricStorageInputs(BaseModel, models.Model): blank=True, help_text="Battery energy capacity replacement cost at time of replacement year" ) + replace_cost_constant = models.FloatField( + default=0.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e9) + ], + blank=True, + help_text="Fixed replacement cost for battery, independent of size." + ) inverter_replacement_year = models.IntegerField( default=10, validators=[ @@ -3568,6 +3586,15 @@ class ElectricStorageInputs(BaseModel, models.Model): blank=True, help_text="Number of years from start of analysis period to replace battery" ) + cost_constant_replacement_year = models.IntegerField( + default=10, + validators=[ + MinValueValidator(0), + MaxValueValidator(MAX_YEARS) + ], + blank=True, + help_text="Number of years from start of analysis period to apply replace_cost_constant." + ) macrs_option_years = models.IntegerField( default=MACRS_YEARS_CHOICES.SEVEN, choices=MACRS_YEARS_CHOICES.choices, From 3a8a85f689b2f819921a53f7754886d84efb31a5 Mon Sep 17 00:00:00 2001 From: Kadlec Date: Wed, 21 May 2025 09:08:28 -0600 Subject: [PATCH 14/24] updating REopt.jl branch to develop --- julia_src/Manifest.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 4d0f7a141..3a3ad23cb 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -922,11 +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 = "9fe6797d461a708e7b853a7236d835b076c516b7" -repo-rev = "allow_presized_GHP_GHX" +git-tree-sha1 = "37371dea02a25459d46411025a82cad3a3229a3c" +repo-rev = "develop" repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.51.1" +version = "0.52.0" [[deps.Random]] deps = ["SHA"] From 47c267933f5a9a902f326c359f0ef9d6e89e355e Mon Sep 17 00:00:00 2001 From: bill-becker Date: Tue, 3 Jun 2025 21:38:44 -0600 Subject: [PATCH 15/24] Update defaults and add O&M term for ElectricStorage --- ...ost_fraction_of_installed_cost_and_more.py | 44 +++++++++++++++++++ reoptjl/models.py | 19 +++++--- 2 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 reoptjl/migrations/0086_electricstorageinputs_om_cost_fraction_of_installed_cost_and_more.py diff --git a/reoptjl/migrations/0086_electricstorageinputs_om_cost_fraction_of_installed_cost_and_more.py b/reoptjl/migrations/0086_electricstorageinputs_om_cost_fraction_of_installed_cost_and_more.py new file mode 100644 index 000000000..22718b0c6 --- /dev/null +++ b/reoptjl/migrations/0086_electricstorageinputs_om_cost_fraction_of_installed_cost_and_more.py @@ -0,0 +1,44 @@ +# Generated by Django 4.0.7 on 2025-06-04 00:05 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0085_electricstorageinputs_cost_constant_replacement_year_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='electricstorageinputs', + name='om_cost_fraction_of_installed_cost', + field=models.FloatField(blank=True, default=0.025, help_text='Annual O&M cost as a fraction of installed cost.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)]), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='installed_cost_constant', + field=models.FloatField(blank=True, default=222115.0, help_text='Fixed upfront cost for battery installation, independent of size.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)]), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='installed_cost_per_kw', + field=models.FloatField(blank=True, default=905.0, help_text='Total upfront battery power capacity costs (e.g. inverter and balance of power systems)', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='installed_cost_per_kwh', + field=models.FloatField(blank=True, default=237.0, help_text='Total upfront battery costs', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='replace_cost_per_kw', + field=models.FloatField(blank=True, default=0.0, help_text='Battery power capacity replacement cost at time of replacement year', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='replace_cost_per_kwh', + field=models.FloatField(blank=True, default=0.0, help_text='Battery energy capacity replacement cost at time of replacement year', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 00ca226bd..a1df0396a 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -3515,7 +3515,7 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Flag to set whether the battery can be charged from the grid, or just onsite generation." ) installed_cost_per_kw = models.FloatField( - default=910.0, + default=905.0, validators=[ MinValueValidator(0), MaxValueValidator(1.0e4) @@ -3524,7 +3524,7 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Total upfront battery power capacity costs (e.g. inverter and balance of power systems)" ) installed_cost_per_kwh = models.FloatField( - default=455.0, + default=237.0, validators=[ MinValueValidator(0), MaxValueValidator(1.0e4) @@ -3533,7 +3533,7 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Total upfront battery costs" ) installed_cost_constant = models.FloatField( - default=0.0, + default=222115.0, validators=[ MinValueValidator(0), MaxValueValidator(1.0e9) @@ -3542,7 +3542,7 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Fixed upfront cost for battery installation, independent of size." ) replace_cost_per_kw = models.FloatField( - default=715.0, + default=0.0, validators=[ MinValueValidator(0), MaxValueValidator(1.0e4) @@ -3551,7 +3551,7 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Battery power capacity replacement cost at time of replacement year" ) replace_cost_per_kwh = models.FloatField( - default=318.0, + default=0.0, validators=[ MinValueValidator(0), MaxValueValidator(1.0e4) @@ -3595,6 +3595,15 @@ class ElectricStorageInputs(BaseModel, models.Model): blank=True, help_text="Number of years from start of analysis period to apply replace_cost_constant." ) + om_cost_fraction_of_installed_cost = models.FloatField( + default=0.025, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0) + ], + blank=True, + help_text="Annual O&M cost as a fraction of installed cost." + ) macrs_option_years = models.IntegerField( default=MACRS_YEARS_CHOICES.SEVEN, choices=MACRS_YEARS_CHOICES.choices, From 92796f3cb79f22624ab84425bc90f1c8e0da4343 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Tue, 3 Jun 2025 21:39:09 -0600 Subject: [PATCH 16/24] Temp update to branch of REopt.jl with storage constant and O&M --- julia_src/Manifest.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index ed3d95fb6..a4ab4c461 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -922,11 +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 = "6615ec48a40b3098a72a76cfe0c46095fc015ec6" +git-tree-sha1 = "dc4aef468cfb3b14e105e3f9c7874fdad01f2e95" repo-rev = "storage-cost-constraints-version2" repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.51.1" +version = "0.52.0" [[deps.Random]] deps = ["SHA"] From 730ed25f79d1efc96d6eea1257c4f648b2773580 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Tue, 3 Jun 2025 21:39:40 -0600 Subject: [PATCH 17/24] Add new ElectricStorage inputs to all_inputs_test.json --- reoptjl/test/posts/all_inputs_test.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reoptjl/test/posts/all_inputs_test.json b/reoptjl/test/posts/all_inputs_test.json index 6811af43c..e99d72390 100644 --- a/reoptjl/test/posts/all_inputs_test.json +++ b/reoptjl/test/posts/all_inputs_test.json @@ -167,10 +167,13 @@ "can_grid_charge": true, "installed_cost_per_kw": 840.0, "installed_cost_per_kwh": 420.0, + "installed_cost_constant": 20000.0, "replace_cost_per_kw": 410.0, "replace_cost_per_kwh": 200.0, + "replace_cost_constant": 0.0, "inverter_replacement_year": 10, "battery_replacement_year": 10, + "cost_constant_replacement_year": 10, "macrs_option_years": 7, "macrs_bonus_fraction": 1.0, "macrs_itc_reduction": 0.5, From 3c950d73f515ab2dcfe0cef330872cba2601b2d4 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Tue, 3 Jun 2025 22:02:24 -0600 Subject: [PATCH 18/24] Merge migrations after merging add-capex-constraint --- reoptjl/migrations/0087_merge_20250604_0342.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 reoptjl/migrations/0087_merge_20250604_0342.py diff --git a/reoptjl/migrations/0087_merge_20250604_0342.py b/reoptjl/migrations/0087_merge_20250604_0342.py new file mode 100644 index 000000000..edafd4e60 --- /dev/null +++ b/reoptjl/migrations/0087_merge_20250604_0342.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-06-04 03:42 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0086_chpoutputs_initial_capital_costs'), + ('reoptjl', '0086_electricstorageinputs_om_cost_fraction_of_installed_cost_and_more'), + ] + + operations = [ + ] From 5cbf872d0c25d9389ee62376fe52f2d4f2bdb1e7 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Tue, 3 Jun 2025 22:03:18 -0600 Subject: [PATCH 19/24] Add new BAU CapEx outputs fields to models --- ...tal_costs_after_incentives_bau_and_more.py | 23 +++++++++++++++++++ reoptjl/models.py | 8 +++++++ 2 files changed, 31 insertions(+) create mode 100644 reoptjl/migrations/0088_financialoutputs_initial_capital_costs_after_incentives_bau_and_more.py diff --git a/reoptjl/migrations/0088_financialoutputs_initial_capital_costs_after_incentives_bau_and_more.py b/reoptjl/migrations/0088_financialoutputs_initial_capital_costs_after_incentives_bau_and_more.py new file mode 100644 index 000000000..65c442ae1 --- /dev/null +++ b/reoptjl/migrations/0088_financialoutputs_initial_capital_costs_after_incentives_bau_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.7 on 2025-06-04 04:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0087_merge_20250604_0342'), + ] + + operations = [ + migrations.AddField( + model_name='financialoutputs', + name='initial_capital_costs_after_incentives_bau', + field=models.FloatField(blank=True, help_text='Up-front capital costs for BAU technologies such as ExistingBoiler and ExistingChiller, in present value.', null=True), + ), + migrations.AddField( + model_name='financialoutputs', + name='lifecycle_capital_costs_bau', + field=models.FloatField(blank=True, help_text='Net capital costs for BAU technologies such as ExistingBoiler and ExistingChiller, in present value.', null=True), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 0e31467ce..caf75b7b4 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -982,6 +982,10 @@ class FinancialOutputs(BaseModel, models.Model): null=True, blank=True, help_text="Net capital costs for all technologies, in present value, including replacement costs and incentives." ) + lifecycle_capital_costs_bau = models.FloatField( + null=True, blank=True, + help_text="Net capital costs for BAU technologies such as ExistingBoiler and ExistingChiller, in present value." + ) microgrid_upgrade_cost = models.FloatField( null=True, blank=True, help_text=("Cost to make a distributed energy system islandable from the grid. Determined by multiplying the " @@ -996,6 +1000,10 @@ class FinancialOutputs(BaseModel, models.Model): null=True, blank=True, help_text="Up-front capital costs for all technologies, in present value, excluding replacement costs, including incentives." ) + initial_capital_costs_after_incentives_bau = models.FloatField( + null=True, blank=True, + help_text="Up-front capital costs for BAU technologies such as ExistingBoiler and ExistingChiller, in present value." + ) capital_costs_after_non_discounted_incentives_without_macrs = models.FloatField( null=True, blank=True, help_text="Capital costs for all technologies, including present value of replacement costs and incentives except for MACRS." From ddb81dc613260b8df4442eec6e40148790618d83 Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 4 Jun 2025 13:02:38 -0600 Subject: [PATCH 20/24] Update default ElectricStorage costs to be in 2024 dollars --- ...geinputs_installed_cost_per_kw_and_more.py | 24 +++++++++++++++++++ reoptjl/models.py | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 reoptjl/migrations/0089_alter_electricstorageinputs_installed_cost_per_kw_and_more.py diff --git a/reoptjl/migrations/0089_alter_electricstorageinputs_installed_cost_per_kw_and_more.py b/reoptjl/migrations/0089_alter_electricstorageinputs_installed_cost_per_kw_and_more.py new file mode 100644 index 000000000..54f0e618c --- /dev/null +++ b/reoptjl/migrations/0089_alter_electricstorageinputs_installed_cost_per_kw_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.7 on 2025-06-04 16:59 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0088_financialoutputs_initial_capital_costs_after_incentives_bau_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='electricstorageinputs', + name='installed_cost_per_kw', + field=models.FloatField(blank=True, default=968.0, help_text='Total upfront battery power capacity costs (e.g. inverter and balance of power systems)', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='installed_cost_per_kwh', + field=models.FloatField(blank=True, default=253.0, help_text='Total upfront battery costs', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index caf75b7b4..5b02a19b2 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -3541,7 +3541,7 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Flag to set whether the battery can be charged from the grid, or just onsite generation." ) installed_cost_per_kw = models.FloatField( - default=905.0, + default=968.0, validators=[ MinValueValidator(0), MaxValueValidator(1.0e4) @@ -3550,7 +3550,7 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Total upfront battery power capacity costs (e.g. inverter and balance of power systems)" ) installed_cost_per_kwh = models.FloatField( - default=237.0, + default=253.0, validators=[ MinValueValidator(0), MaxValueValidator(1.0e4) From 264b44ba4eea07fd39d94d914d4c60c6945f57ad Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 4 Jun 2025 14:20:56 -0600 Subject: [PATCH 21/24] Add new Existing Boiler/Chiller inputs and outputs --- ...rinputs_installed_cost_dollars_and_more.py | 49 +++++++++++++++++++ reoptjl/models.py | 49 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 reoptjl/migrations/0090_existingboilerinputs_installed_cost_dollars_and_more.py diff --git a/reoptjl/migrations/0090_existingboilerinputs_installed_cost_dollars_and_more.py b/reoptjl/migrations/0090_existingboilerinputs_installed_cost_dollars_and_more.py new file mode 100644 index 000000000..8d6357e79 --- /dev/null +++ b/reoptjl/migrations/0090_existingboilerinputs_installed_cost_dollars_and_more.py @@ -0,0 +1,49 @@ +# Generated by Django 4.0.7 on 2025-06-04 19:28 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0089_alter_electricstorageinputs_installed_cost_per_kw_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='existingboilerinputs', + name='installed_cost_dollars', + field=models.FloatField(blank=True, default=0.0, help_text='Cost incurred in BAU scenario, as well as Optimal if needed still, in dollars', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), + ), + migrations.AddField( + model_name='existingboilerinputs', + name='installed_cost_per_mmbtu_per_hour', + field=models.FloatField(blank=True, default=0.0, help_text="Thermal power capacity-based cost incurred in BAU and only based on what's needed in Optimal scenario", null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), + ), + migrations.AddField( + model_name='existingboileroutputs', + name='size_mmbtu_per_hour_bau', + field=models.FloatField(blank=True, null=True), + ), + migrations.AddField( + model_name='existingchillerinputs', + name='installed_cost_dollars', + field=models.FloatField(blank=True, default=0.0, help_text='Cost incurred in BAU scenario, as well as Optimal if needed still, in dollars', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), + ), + migrations.AddField( + model_name='existingchillerinputs', + name='installed_cost_per_ton', + field=models.FloatField(blank=True, default=0.0, help_text="Thermal power capacity-based cost incurred in BAU and only based on what's needed in Optimal scenario", null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000000.0)]), + ), + migrations.AddField( + model_name='existingchilleroutputs', + name='size_ton', + field=models.FloatField(blank=True, null=True), + ), + migrations.AddField( + model_name='existingchilleroutputs', + name='size_ton_bau', + field=models.FloatField(blank=True, null=True), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 5b02a19b2..71515822e 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -5053,6 +5053,28 @@ class ExistingChillerInputs(BaseModel, models.Model): help_text="Boolean indicator if the existing chiller is unavailable in the optimal case (still used in BAU)" ) + installed_cost_per_ton = models.FloatField( + default=0.0, + null=True, + blank=True, + validators=[ + MinValueValidator(0), + MaxValueValidator(MAX_BIG_NUMBER) + ], + help_text="Thermal power capacity-based cost incurred in BAU and only based on what's needed in Optimal scenario" + ) + + installed_cost_dollars = models.FloatField( + default=0.0, + null=True, + blank=True, + validators=[ + MinValueValidator(0), + MaxValueValidator(MAX_BIG_NUMBER) + ], + help_text="Cost incurred in BAU scenario, as well as Optimal if needed still, in dollars" + ) + def clean(self): pass @@ -5068,6 +5090,9 @@ class ExistingChillerOutputs(BaseModel, models.Model): primary_key=True ) + size_ton = models.FloatField(null=True, blank=True) + size_ton_bau = models.FloatField(null=True, blank=True) + thermal_to_storage_series_ton = ArrayField( models.FloatField( blank=True @@ -5268,6 +5293,29 @@ class ExistingBoilerInputs(BaseModel, models.Model): help_text="Existing boiler fuel type, one of natural_gas, landfill_bio_gas, propane, diesel_oil" ) + + installed_cost_per_mmbtu_per_hour = models.FloatField( + default=0.0, + null=True, + blank=True, + validators=[ + MinValueValidator(0), + MaxValueValidator(MAX_BIG_NUMBER) + ], + help_text="Thermal power capacity-based cost incurred in BAU and only based on what's needed in Optimal scenario" + ) + + installed_cost_dollars = models.FloatField( + default=0.0, + null=True, + blank=True, + validators=[ + MinValueValidator(0), + MaxValueValidator(MAX_BIG_NUMBER) + ], + help_text="Cost incurred in BAU scenario, as well as Optimal if needed still, in dollars" + ) + can_supply_steam_turbine = models.BooleanField( default=False, blank=True, @@ -5334,6 +5382,7 @@ class ExistingBoilerOutputs(BaseModel, models.Model): ) size_mmbtu_per_hour = models.FloatField(null=True, blank=True) + size_mmbtu_per_hour_bau = models.FloatField(null=True, blank=True) annual_fuel_consumption_mmbtu = models.FloatField(null=True, blank=True) annual_fuel_consumption_mmbtu_bau = models.FloatField(null=True, blank=True) From 73d54536fc19c67c280a015aeeb81950fc2def8c Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 4 Jun 2025 14:22:21 -0600 Subject: [PATCH 22/24] Update REopt.jl branch for latest battery C and OM costs --- 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 a4ab4c461..b6a488653 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -922,7 +922,7 @@ 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 = "dc4aef468cfb3b14e105e3f9c7874fdad01f2e95" +git-tree-sha1 = "7f41842737ce902942d5b1291f777ce55ef9adec" repo-rev = "storage-cost-constraints-version2" repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" From 5a3a21eed34f563c8932bd5ab0891750407d4c1d Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 4 Jun 2025 14:24:31 -0600 Subject: [PATCH 23/24] Merge migrations after merging add-ghp-inputs branch --- reoptjl/migrations/0091_merge_20250604_2023.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 reoptjl/migrations/0091_merge_20250604_2023.py diff --git a/reoptjl/migrations/0091_merge_20250604_2023.py b/reoptjl/migrations/0091_merge_20250604_2023.py new file mode 100644 index 000000000..8c83be0da --- /dev/null +++ b/reoptjl/migrations/0091_merge_20250604_2023.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-06-04 20:23 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0085_ghpoutputs_annual_thermal_production_mmbtu_and_more'), + ('reoptjl', '0090_existingboilerinputs_installed_cost_dollars_and_more'), + ] + + operations = [ + ] From 04ff6aa3daedbd300bdbe60ec956a91cca367b9b Mon Sep 17 00:00:00 2001 From: bill-becker Date: Wed, 4 Jun 2025 14:39:43 -0600 Subject: [PATCH 24/24] Hard-code old ElectricStorage defaults for tests with LCC/NPV checks --- reoptjl/test/posts/all_inputs_test.json | 3 ++- reoptjl/test/posts/outage.json | 5 ++++- reoptjl/test/posts/pv_batt_emissions.json | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/reoptjl/test/posts/all_inputs_test.json b/reoptjl/test/posts/all_inputs_test.json index 5fcf96406..7bfb1c979 100644 --- a/reoptjl/test/posts/all_inputs_test.json +++ b/reoptjl/test/posts/all_inputs_test.json @@ -169,13 +169,14 @@ "can_grid_charge": true, "installed_cost_per_kw": 840.0, "installed_cost_per_kwh": 420.0, - "installed_cost_constant": 20000.0, + "installed_cost_constant": 0.0, "replace_cost_per_kw": 410.0, "replace_cost_per_kwh": 200.0, "replace_cost_constant": 0.0, "inverter_replacement_year": 10, "battery_replacement_year": 10, "cost_constant_replacement_year": 10, + "om_cost_fraction_of_installed_cost": 0.0, "macrs_option_years": 7, "macrs_bonus_fraction": 1.0, "macrs_itc_reduction": 0.5, diff --git a/reoptjl/test/posts/outage.json b/reoptjl/test/posts/outage.json index 1a212b871..5658437c5 100644 --- a/reoptjl/test/posts/outage.json +++ b/reoptjl/test/posts/outage.json @@ -75,8 +75,11 @@ "macrs_bonus_fraction": 1.0, "installed_cost_per_kw": 840.0, "installed_cost_per_kwh": 420.0, + "installed_cost_constant": 0.0, "replace_cost_per_kw": 410.0, - "replace_cost_per_kwh": 200.0 + "replace_cost_per_kwh": 200.0, + "replace_cost_constant": 0.0, + "om_cost_fraction_of_installed_cost": 0.0 }, "Financial": { "value_of_lost_load_per_kwh": 100.0, diff --git a/reoptjl/test/posts/pv_batt_emissions.json b/reoptjl/test/posts/pv_batt_emissions.json index fc926b1a9..4853c5b43 100644 --- a/reoptjl/test/posts/pv_batt_emissions.json +++ b/reoptjl/test/posts/pv_batt_emissions.json @@ -35,8 +35,11 @@ "macrs_bonus_fraction": 0.4, "replace_cost_per_kw": 460.0, "replace_cost_per_kwh": 230.0, + "replace_cost_constant": 0.0, "installed_cost_per_kw": 1000.0, "installed_cost_per_kwh": 500.0, + "installed_cost_constant": 0.0, + "om_cost_fraction_of_installed_cost": 0.0, "total_itc_fraction": 0.0 }, "ElectricTariff": {