Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d8d1813
add new inputs
adfarth Mar 20, 2025
bad79cc
changelog and all_inputs test
adfarth Apr 15, 2025
18e58c5
testing ghp inputs
Apr 22, 2025
796ea99
debugging test
Apr 22, 2025
e3011e1
update manifest.toml
Apr 23, 2025
53d3f8e
Merge develop into add-ghp-inputs april 23
Bill-Becker Apr 23, 2025
f523baa
Merge migration after merging develop
Bill-Becker Apr 23, 2025
cc225e8
adding ghp outputs
Apr 24, 2025
7e69a21
Merge branch 'develop' into add-capex-constraint
adfarth May 6, 2025
54f1fbc
point to develop
adfarth May 8, 2025
43740b3
Create 0085_financialinputs_max_initial_capital_costs_before_incentiv…
adfarth May 8, 2025
4dd7510
add chp output
adfarth May 8, 2025
f66cab9
update help text to include units for min, max capital costs
zolanaj May 9, 2025
5b1c315
updt to REopt052
adfarth May 9, 2025
40cfbfc
Temp change to REopt#pv-size-classes
Bill-Becker May 9, 2025
2d186e9
Add and modify PV cost inputs and outputs to base on size_class logic
Bill-Becker May 9, 2025
31fe2d3
Add pv_cost_defaults endpoint
Bill-Becker May 9, 2025
aa805d3
Update PVInputs db instance from REopt.jl-processed data based on siz…
Bill-Becker May 9, 2025
904be58
Merge branch 'add-capex-constraint' of https://github.com/NREL/REopt_…
zolanaj May 9, 2025
fe4bda7
Add tests for pv_cost_defaults endpoint and updating from Julia
Bill-Becker May 13, 2025
3c80282
Add post file for pv_cost_defaults updating from Julia test
Bill-Becker May 13, 2025
645ccb1
Add POSTability, size output, and new sizing inputs for pv_cost_defau…
Bill-Becker May 15, 2025
e989a28
Add battery cost constant terms and use branch of REopt.jl
Bill-Becker May 19, 2025
3a8a85f
updating REopt.jl branch to develop
May 21, 2025
47c2679
Update defaults and add O&M term for ElectricStorage
Bill-Becker Jun 4, 2025
92796f3
Temp update to branch of REopt.jl with storage constant and O&M
Bill-Becker Jun 4, 2025
730ed25
Add new ElectricStorage inputs to all_inputs_test.json
Bill-Becker Jun 4, 2025
fc14904
Merge branch 'add-capex-constraint' into battery-cost
Bill-Becker Jun 4, 2025
3c950d7
Merge migrations after merging add-capex-constraint
Bill-Becker Jun 4, 2025
5cbf872
Add new BAU CapEx outputs fields to models
Bill-Becker Jun 4, 2025
ddb81dc
Update default ElectricStorage costs to be in 2024 dollars
Bill-Becker Jun 4, 2025
264b44b
Add new Existing Boiler/Chiller inputs and outputs
Bill-Becker Jun 4, 2025
73d5453
Update REopt.jl branch for latest battery C and OM costs
Bill-Becker Jun 4, 2025
9fc06d6
Merge branch 'add-ghp-inputs' into battery-cost
Bill-Becker Jun 4, 2025
5a3a21e
Merge migrations after merging add-ghp-inputs branch
Bill-Becker Jun 4, 2025
04ff6aa
Hard-code old ElectricStorage defaults for tests with LCC/NPV checks
Bill-Becker Jun 4, 2025
d712766
Update REopt.jl#pv-size-classes version with latest and develop
Bill-Becker Jun 13, 2025
c6faea6
Merge branch 'battery-cost' into pv-cost
Bill-Becker Jun 13, 2025
b14beba
Merge migration after merging battery-cost branch
Bill-Becker Jun 13, 2025
f921bd5
Update REopt.jl to develop branch
Bill-Becker Jun 13, 2025
045f78e
Update CHANGELOG with all of the merged branch changes
Bill-Becker Jun 13, 2025
b79819a
Update REopt.jl to registered v0.53.0
Bill-Becker Jun 13, 2025
7a2f4cc
Merge branch 'develop' into pv-cost
Bill-Becker Jun 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,21 @@ Classify the change according to the following categories:
##### Removed
### Patches

## develop
## v3.13.0
### Minor Updates
TODO: aggregate CHANGELOG updates from feature branches
#### Added
- Added **Financial** inputs **min_initial_capital_costs_before_incentives** and **max_initial_capital_costs_before_incentives**
- Added **CHP** output **initial_capital_costs**
- Added new **GHPInputs** fields for advanced ground heat exchanger sizing and configuration.
- Added **hybrid_ghx_sizing_method** input to allow user selection of GHX sizing approach.
- Added new outputs to **GHPOutputs** for reporting system sizes and borehole count.
- Added tests for new GHP input and output fields.
#### Changed
- Updated **PV.installed_cost_per_kw** and **PV.om_cost_per_kw** default values to reflect latest cost data.
- Updated **ElectricStorage.installed_cost_per_kw**, **ElectricStorage.installed_cost_per_kwh**, **ElectricStorage.replace_cost_per_kw**, and **ElectricStorage.replace_cost_per_kwh** default values to reflect latest cost data.
- Updated **ElectricStorage** cost defaults in `reoptjl/models.py`
- Updated GHP input validation and defaults in `reoptjl/models.py` and `validators.py`.
- Updated `/ghpghx` endpoint to support new GHP input fields.

## v3.12.3
### Minor Updates
Expand All @@ -53,7 +65,7 @@ TODO: aggregate CHANGELOG updates from feature branches

## 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
Expand Down
4 changes: 2 additions & 2 deletions julia_src/Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -922,9 +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 = "1b2ede642ebd6b9471500fbbd0b54d806edb669a"
uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6"
version = "0.51.1"
version = "0.53.0"

[[deps.Random]]
deps = ["SHA"]
Expand Down
57 changes: 56 additions & 1 deletion julia_src/http.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ function reopt(req::HTTP.Request)
else
site_dict = Dict()
end
if haskey(d, "PV")
inputs_with_defaults_from_pv = [
:size_class, :installed_cost_per_kw, :om_cost_per_kw
]
pv_dict = Dict(key=>getfield(model_inputs.s.pvs[1], key) for key in inputs_with_defaults_from_pv)
else
pv_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_easiur),
"ElectricUtility" => Dict(key=>getfield(model_inputs.s.electric_utility, key) for key in inputs_with_defaults_from_avert_or_cambium),
Expand All @@ -153,7 +161,8 @@ function reopt(req::HTTP.Request)
"GHP" => ghp_dict,
"ExistingChiller" => chiller_dict,
"ASHPSpaceHeater" => ashp_dict,
"ASHPWaterHeater" => ashp_wh_dict
"ASHPWaterHeater" => ashp_wh_dict,
"PV" => pv_dict
)
catch e
@error "Something went wrong in REopt optimization!" exception=(e, catch_backtrace())
Expand Down Expand Up @@ -579,6 +588,51 @@ function get_ashp_defaults(req::HTTP.Request)
end
end

function pv_cost_defaults(req::HTTP.Request)
d = JSON.parse(String(req.body))
float_vals = ["electric_load_annual_kwh", "site_land_acres",
"site_roof_squarefeet", "min_kw", "max_kw",
"kw_per_square_foot", "acres_per_kw",
"capacity_factor_estimate", "fraction_of_annual_kwh_to_size_pv"]
int_vals = ["size_class", "array_type"]
string_vals = ["location"]
bool_vals = []
all_vals = vcat(int_vals, string_vals, float_vals, bool_vals)
# Process .json inputs and convert to correct type if needed
for k in all_vals
if !isnothing(get(d, k, nothing))
# TODO improve this by checking if the type is not the expected type, as opposed to just not string
if k in float_vals && typeof(d[k]) == String
d[k] = parse(Float64, d[k])
elseif k in int_vals && typeof(d[k]) == String
d[k] = parse(Int64, d[k])
elseif k in bool_vals && typeof(d[k]) == String
d[k] = parse(Bool, d[k])
end
end
end

@info "Getting PV cost defaults..."
data = Dict()
error_response = Dict()
try
data["installed_cost_per_kw"], data["om_cost_per_kw"], data["size_class"], tech_sizes_for_cost_curve, data["size_kw_for_size_class"] = reoptjl.get_pv_cost_params(;
(Symbol(k) => v for (k, v) in pairs(d))...
)
catch e
@error "Something went wrong in the pv_cost_defaults" exception=(e, catch_backtrace())
error_response["error"] = sprint(showerror, e)
end
if isempty(error_response)
@info "PV cost defaults determined."
response = data
return HTTP.Response(200, JSON.json(response))
else
@info "An error occured in the pv_cost_defaults endpoint"
return HTTP.Response(500, JSON.json(error_response))
end
end


function job_no_xpress(req::HTTP.Request)
error_response = Dict("error" => "V1 and V2 not available without Xpress installation.")
Expand Down Expand Up @@ -607,4 +661,5 @@ HTTP.register!(ROUTER, "GET", "/ground_conductivity", ground_conductivity)
HTTP.register!(ROUTER, "GET", "/health", health)
HTTP.register!(ROUTER, "GET", "/get_existing_chiller_default_cop", get_existing_chiller_default_cop)
HTTP.register!(ROUTER, "GET", "/get_ashp_defaults", get_ashp_defaults)
HTTP.register!(ROUTER, "GET", "/pv_cost_defaults", pv_cost_defaults)
HTTP.serve(ROUTER, "0.0.0.0", 8081, reuseaddr=true)
29 changes: 29 additions & 0 deletions reoptjl/migrations/0081_ghpinputs_load_served_by_ghp_and_more.py
Original file line number Diff line number Diff line change
@@ -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)]),
),
]
14 changes: 14 additions & 0 deletions reoptjl/migrations/0084_merge_20250423_2110.py
Original file line number Diff line number Diff line change
@@ -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 = [
]
Original file line number Diff line number Diff line change
@@ -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)]),
),
]
Original file line number Diff line number Diff line change
@@ -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)]),
),
]
Original file line number Diff line number Diff line change
@@ -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),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 4.0.7 on 2025-05-09 22:46

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='pvinputs',
name='size_class',
field=models.IntegerField(blank=True, help_text='PV size class. Must be an integer value between 1 and 5. Default is 2, representing commercial-scale', null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)]),
),
migrations.AddField(
model_name='pvoutputs',
name='installed_cost_per_kw',
field=models.FloatField(blank=True, null=True),
),
migrations.AddField(
model_name='pvoutputs',
name='om_cost_per_kw',
field=models.FloatField(blank=True, null=True),
),
migrations.AlterField(
model_name='pvinputs',
name='installed_cost_per_kw',
field=models.FloatField(blank=True, help_text='Installed PV cost in $/kW', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000.0)]),
),
migrations.AlterField(
model_name='pvinputs',
name='om_cost_per_kw',
field=models.FloatField(blank=True, help_text='Annual PV operations and maintenance costs in $/kW', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)]),
),
]
18 changes: 18 additions & 0 deletions reoptjl/migrations/0086_chpoutputs_initial_capital_costs.py
Original file line number Diff line number Diff line change
@@ -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),
),
]
Original file line number Diff line number Diff line change
@@ -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)]),
),
]
14 changes: 14 additions & 0 deletions reoptjl/migrations/0087_merge_20250604_0342.py
Original file line number Diff line number Diff line change
@@ -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 = [
]
Original file line number Diff line number Diff line change
@@ -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),
),
]
Loading