Skip to content

Commit 30a9538

Browse files
authored
Merge pull request #681 from NREL/anccr
ElectricTariff Outputs, Peak Load Scaling, Endpoint Updates
2 parents d6c69b9 + 85e37f6 commit 30a9538

14 files changed

+1488
-234
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ Classify the change according to the following categories:
2626
##### Removed
2727
### Patches
2828

29+
## v3.17.0
30+
### Minor Updates
31+
##### Added
32+
- `ElectricLoad` input `monthly_peaks_kw`. Can be used to scale loads_kw or doe_reference loads to monthly peaks while maintaining monthly energy.
33+
- `ElectricTariff` outputs: `demand_rate_average_series`, `energy_cost_series_before_tax`, `energy_cost_series_before_tax_bau`, `energy_rate_average_series`, `energy_rate_series`, `energy_rate_tier_limits`, `facility_demand_monthly_rate_series`, `facility_demand_monthly_rate_tier_limits`, `monthly_demand_cost_series_before_tax`, `monthly_demand_cost_series_before_tax_bau`, `monthly_energy_cost_series_before_tax`, `monthly_energy_cost_series_before_tax_bau`, `monthly_facility_demand_cost_series_before_tax`, `monthly_facility_demand_cost_series_before_tax_bau`, `monthly_fixed_cost_series_before_tax`, `monthly_fixed_cost_before_tax_bau`, `monthly_tou_demand_cost_series_before_tax`, `monthly_tou_demand_cost_series_before_tax_bau`, `tou_demand_metrics`, `tou_demand_rate_series`, `tou_demand_rate_tier_limits`.
34+
- New endpoint `/get_load_metrics` for sending a timeseries `load_profile` and getting monthly and annual energy and peak loads.
35+
- New custom table option `custom_table_rates` for endpoint `/job/generate_results_table`.
36+
##### Fixed
37+
- Avoid `CST` bypassing non-servable heating loads by going through the `HighTempThermalStorage`.
38+
39+
2940
## v3.16.2
3041
### Patches
3142
- Added `CST` and `HighTempThermalStorage` to all/superset inputs test.

julia_src/Manifest.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -948,9 +948,9 @@ version = "1.11.0"
948948

949949
[[deps.REopt]]
950950
deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"]
951-
git-tree-sha1 = "103761fa0f7447377726347af656cde6ab1160cc"
951+
git-tree-sha1 = "00bb39c8f932a3320960f01adc139229c24e12b7"
952952
uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6"
953-
version = "0.55.1"
953+
version = "0.56.2"
954954

955955
[[deps.Random]]
956956
deps = ["SHA"]

julia_src/http.jl

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ function reopt(req::HTTP.Request)
9191
# Catch handled/unhandled exceptions in data pre-processing, JuMP setup
9292
try
9393
model_inputs = reoptjl.REoptInputs(d)
94+
@info "Successfully processed REopt inputs."
9495
catch e
9596
@error "Something went wrong during REopt inputs processing!" exception=(e, catch_backtrace())
9697
error_response["error"] = sprint(showerror, e)
@@ -102,6 +103,7 @@ function reopt(req::HTTP.Request)
102103
# Catch handled/unhandled exceptions in optimization
103104
try
104105
results = reoptjl.run_reopt(ms, model_inputs)
106+
@info "Successfully ran REopt optimization."
105107
inputs_with_defaults_from_julia_financial = [
106108
:NOx_grid_cost_per_tonne, :SO2_grid_cost_per_tonne, :PM25_grid_cost_per_tonne,
107109
:NOx_onsite_fuelburn_cost_per_tonne, :SO2_onsite_fuelburn_cost_per_tonne, :PM25_onsite_fuelburn_cost_per_tonne,
@@ -235,6 +237,14 @@ function reopt(req::HTTP.Request)
235237
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)
236238
else
237239
high_temp_storage_dict = Dict()
240+
end
241+
if haskey(d, "ElectricTariff") && !isempty(model_inputs.s.electric_tariff.urdb_metadata)
242+
inputs_from_julia_electric_tariff = [
243+
:urdb_metadata
244+
]
245+
electric_tariff_dict = Dict(key=>getfield(model_inputs.s.electric_tariff, key) for key in inputs_from_julia_electric_tariff)
246+
else
247+
electric_tariff_dict = Dict()
238248
end
239249
inputs_with_defaults_set_in_julia = Dict(
240250
"Financial" => Dict(key=>getfield(model_inputs.s.financial, key) for key in inputs_with_defaults_from_julia_financial),
@@ -251,7 +261,8 @@ function reopt(req::HTTP.Request)
251261
"ElectricStorage" => electric_storage_dict,
252262
"ColdThermalStorage" => cold_storage_dict,
253263
"HotThermalStorage" => hot_storage_dict,
254-
"HighTempThermalStorage" => high_temp_storage_dict
264+
"HighTempThermalStorage" => high_temp_storage_dict,
265+
"ElectricTariff" => electric_tariff_dict
255266
)
256267
catch e
257268
@error "Something went wrong in REopt optimization!" exception=(e, catch_backtrace())
@@ -544,18 +555,18 @@ function simulated_load(req::HTTP.Request)
544555
end
545556

546557
# Convert vectors which come in as Vector{Any} to Vector{Float} (within Vector{<:Real})
547-
vector_types = ["percent_share", "cooling_pct_share", "monthly_totals_kwh", "monthly_mmbtu",
558+
vector_types = ["percent_share", "cooling_pct_share", "monthly_totals_kwh", "monthly_peaks_kw", "monthly_mmbtu",
548559
"monthly_tonhour", "monthly_fraction", "addressable_load_fraction", "load_profile"]
549560
for key in vector_types
550561
if key in keys(d) && typeof(d[key]) <: Vector{}
551-
d[key] = convert(Vector{Real}, d[key])
562+
d[key] = convert(Vector{Float64}, d[key])
552563
elseif key in keys(d) && key == "addressable_load_fraction"
553564
# Scalar version of input, convert Any to Real
554-
d[key] = convert(Real, d[key])
565+
d[key] = convert(Float64, d[key])
555566
end
556567
end
557568

558-
@info "Getting CRB Loads..."
569+
@info "Getting Loads..."
559570
data = Dict()
560571
error_response = Dict()
561572
try
@@ -574,6 +585,35 @@ function simulated_load(req::HTTP.Request)
574585
end
575586
end
576587

588+
function get_load_metrics(req::HTTP.Request)
589+
d = JSON.parse(String(req.body))
590+
591+
# Convert load_profile from Vector{Any} to Vector{Float64}
592+
if "load_profile" in keys(d) && typeof(d["load_profile"]) <: Vector{}
593+
d["load_profile"] = convert(Vector{Float64}, d["load_profile"])
594+
end
595+
596+
@info "Getting load metrics..."
597+
data = Dict()
598+
error_response = Dict()
599+
try
600+
load_profile = pop!(d, "load_profile")
601+
other_kwargs = reoptjl.dictkeys_tosymbols(d)
602+
data = reoptjl.get_load_metrics(load_profile; other_kwargs...)
603+
catch e
604+
@error "Something went wrong in the get_load_metrics" exception=(e, catch_backtrace())
605+
error_response["error"] = sprint(showerror, e)
606+
end
607+
if isempty(error_response)
608+
@info "Load metrics determined."
609+
response = data
610+
return HTTP.Response(200, JSON.json(response))
611+
else
612+
@info "An error occured in the get_load_metrics endpoint"
613+
return HTTP.Response(500, JSON.json(error_response))
614+
end
615+
end
616+
577617
function ghp_efficiency_thermal_factors(req::HTTP.Request)
578618
d = JSON.parse(String(req.body))
579619

@@ -779,4 +819,5 @@ HTTP.register!(ROUTER, "GET", "/health", health)
779819
HTTP.register!(ROUTER, "GET", "/get_existing_chiller_default_cop", get_existing_chiller_default_cop)
780820
HTTP.register!(ROUTER, "GET", "/get_ashp_defaults", get_ashp_defaults)
781821
HTTP.register!(ROUTER, "GET", "/pv_cost_defaults", pv_cost_defaults)
822+
HTTP.register!(ROUTER, "GET", "/get_load_metrics", get_load_metrics)
782823
HTTP.serve(ROUTER, "0.0.0.0", 8081, reuseaddr=true)

0 commit comments

Comments
 (0)