From 0ce6a6aa1a82603d8e38482ab28ac96b2cc81a4d Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 21 Jun 2023 13:05:55 -0600 Subject: [PATCH 01/35] update NSRDB bounds --- src/core/production_factor.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/production_factor.jl b/src/core/production_factor.jl index dbb2c8f18..fae874615 100644 --- a/src/core/production_factor.jl +++ b/src/core/production_factor.jl @@ -35,16 +35,17 @@ function get_production_factor(pv::PV, latitude::Real, longitude::Real; timefram return pv.production_factor_series end - # Check if site is beyond the bounds of the NRSDB dataset. If so, use the international dataset. + # Check if site is beyond the bounds of the NRSDB TMY dataset. If so, use the international dataset. dataset = "nsrdb" if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 - if longitude < 81.5 || longitude > 179.5 || latitude < -43.8 || latitude > 60.0 - if longitude < 67.0 || longitude > 81.5 || latitude < -43.8 || latitude > 38.0 + if longitude < 81.5 || longitude > 179.5 || latitude < -60.0 || latitude > 60.0 + if longitude < 67.0 || latitude < -40.0 || latitude > 38.0 dataset = "intl" end end end + ## TODO: Update to v8 here url = string("https://developer.nrel.gov/api/pvwatts/v6.json", "?api_key=", nrel_developer_key, "&lat=", latitude , "&lon=", longitude, "&tilt=", pv.tilt, "&system_capacity=1", "&azimuth=", pv.azimuth, "&module_type=", pv.module_type, From a4bf6ea76be474385508d4a7e59ff43b0020c08b Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 21 Jun 2023 13:38:48 -0600 Subject: [PATCH 02/35] add descriptions to PV inputs --- src/core/pv.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/pv.jl b/src/core/pv.jl index 358077b59..df6d69085 100644 --- a/src/core/pv.jl +++ b/src/core/pv.jl @@ -33,12 +33,12 @@ array_type::Int=1, # PV Watts array type (0: Ground Mount Fixed (Open Rack); 1: Rooftop, Fixed; 2: Ground Mount 1-Axis Tracking; 3 : 1-Axis Backtracking; 4: Ground Mount, 2-Axis Tracking) tilt::Real= array_type == 1 ? 10 : abs(latitude), # tilt = 10 deg for rooftop systems, abs(lat) for ground-mount module_type::Int=0, # PV module type (0: Standard; 1: Premium; 2: Thin Film) - losses::Real=0.14, + losses::Real=0.14, # System losses azimuth::Real = latitude≥0 ? 180 : 0, # set azimuth to zero for southern hemisphere - gcr::Real=0.4, - radius::Int=0, - name::String="PV", - location::String="both", + gcr::Real=0.4, # Ground coverage ratio + radius::Int=0, # Radius, in miles, to use when searching for the closest climate data station. Use zero to use the closest station regardless of the distance + name::String="PV", # for use with multiple pvs + location::String="both", # one of ["roof", "ground", "both"] existing_kw::Real=0, min_kw::Real=0, max_kw::Real=1.0e9, From e7409e5341497b3ed2f7defc345be26f2c56062a Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 21 Jun 2023 13:53:03 -0600 Subject: [PATCH 03/35] update to PVWatts v8 --- CHANGELOG.md | 5 +++++ src/core/production_factor.jl | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c4b2bed9..3726695b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,11 @@ Classify the change according to the following categories: ### Deprecated ### Removed + +## Develop - 2023-06-21 +### Changed +- In `src/core/production_factor.jl`, updated NSRDB bounds used in PVWatts query (now includes southern New Zealand) +- Updated PV Watts version from v6 to v8. PVWatts V8 updates the weather data to 2020 TMY data from the NREL NSRDB for locations covered by the database. (The NSRDB weather data used in PVWatts V6 is from around 2015.) See other differences at https://developer.nrel.gov/docs/solar/pvwatts/. ## v0.32.3 ### Fixed - Calculate **num_battery_bins** default in `backup_reliability.jl` based on battery duration to prevent significant discretization error (and add test) diff --git a/src/core/production_factor.jl b/src/core/production_factor.jl index fae874615..beba394ff 100644 --- a/src/core/production_factor.jl +++ b/src/core/production_factor.jl @@ -45,8 +45,7 @@ function get_production_factor(pv::PV, latitude::Real, longitude::Real; timefram end end - ## TODO: Update to v8 here - url = string("https://developer.nrel.gov/api/pvwatts/v6.json", "?api_key=", nrel_developer_key, + url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, "&lat=", latitude , "&lon=", longitude, "&tilt=", pv.tilt, "&system_capacity=1", "&azimuth=", pv.azimuth, "&module_type=", pv.module_type, "&array_type=", pv.array_type, "&losses=", round(pv.losses*100, digits=3), "&dc_ac_ratio=", pv.dc_ac_ratio, From 009e032149accc30619ebe506ce261337dd5287b Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 21 Jun 2023 14:39:06 -0600 Subject: [PATCH 04/35] Update runtests.jl PV size changed by 2% which aligns with change in PV output with update to v8 --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 43040028f..447263af5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -77,8 +77,8 @@ else # run HiGHS tests inputs = REoptInputs(s) results = run_reopt(model, inputs) - @test results["PV"]["size_kw"] ≈ 70.3084 atol=0.01 - @test results["Financial"]["lcc"] ≈ 430747.0 rtol=1e-5 # with levelization_factor hack the LCC is within 5e-5 of REopt API LCC + @test results["PV"]["size_kw"] ≈ 68.9323 atol=0.01 + @test results["Financial"]["lcc"] ≈ 432672.0 rtol=1e-5 # with levelization_factor hack the LCC is within 5e-5 of REopt API LCC @test all(x == 0.0 for x in results["PV"]["electric_to_load_series_kw"][1:744]) end From 59ed07c5c775db1357fb9f4a4ca5198bf603481c Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 21 Jun 2023 14:54:59 -0600 Subject: [PATCH 05/35] update to v8 in utils.jl --- src/core/utils.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/utils.jl b/src/core/utils.jl index 067cd9852..f511c3f79 100644 --- a/src/core/utils.jl +++ b/src/core/utils.jl @@ -378,7 +378,7 @@ end function get_ambient_temperature(latitude::Real, longitude::Real; timeframe="hourly") - url = string("https://developer.nrel.gov/api/pvwatts/v6.json", "?api_key=", nrel_developer_key, + url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, "&lat=", latitude , "&lon=", longitude, "&tilt=", latitude, "&system_capacity=1", "&azimuth=", 180, "&module_type=", 0, "&array_type=", 0, "&losses=", 14, @@ -405,7 +405,7 @@ end function get_pvwatts_prodfactor(latitude::Real, longitude::Real; timeframe="hourly") - url = string("https://developer.nrel.gov/api/pvwatts/v6.json", "?api_key=", nrel_developer_key, + url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, "&lat=", latitude , "&lon=", longitude, "&tilt=", latitude, "&system_capacity=1", "&azimuth=", 180, "&module_type=", 0, "&array_type=", 0, "&losses=", 14, From e20f2afba4e3d793a94de68aa33b44fe10d1f105 Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 21 Jun 2023 15:57:37 -0600 Subject: [PATCH 06/35] update other pvwatts calls and some tests --- CHANGELOG.md | 3 ++- src/core/scenario.jl | 12 ++++++++++-- src/core/utils.jl | 32 +++++++++++++++++++++++++------- test/runtests.jl | 6 +++--- test/test_with_cplex.jl | 6 +++--- test/test_with_xpress.jl | 12 ++++++------ 6 files changed, 49 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3726695b1..2186d986b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,8 @@ Classify the change according to the following categories: ## Develop - 2023-06-21 ### Changed - In `src/core/production_factor.jl`, updated NSRDB bounds used in PVWatts query (now includes southern New Zealand) -- Updated PV Watts version from v6 to v8. PVWatts V8 updates the weather data to 2020 TMY data from the NREL NSRDB for locations covered by the database. (The NSRDB weather data used in PVWatts V6 is from around 2015.) See other differences at https://developer.nrel.gov/docs/solar/pvwatts/. +- Updated PV Watts version from v6 to v8. PVWatts V8 updates the weather data to 2020 TMY data from the NREL NSRDB for locations covered by the database. (The NSRDB weather data used in PVWatts V6 is from around 2015.) See other differences at https://developer.nrel.gov/docs/solar/pvwatts/. +- Updated PVwatts calls in `src/core/utils.jl` (`get_ambient_temperature` and `get_pvwatts_prodfactor`) and `scenario.jl` (used for GHP) to use v8 and to determine dataset based on lat long. ## v0.32.3 ### Fixed - Calculate **num_battery_bins** default in `backup_reliability.jl` based on battery duration to prevent significant discretization error (and add test) diff --git a/src/core/scenario.jl b/src/core/scenario.jl index 07e95a6da..0f5202053 100644 --- a/src/core/scenario.jl +++ b/src/core/scenario.jl @@ -456,11 +456,19 @@ function Scenario(d::Dict; flex_hvac_from_json=false) # Call PVWatts for hourly dry-bulb outdoor air temperature ambient_temperature_f = [] if !haskey(d["GHP"]["ghpghx_inputs"][1], "ambient_temperature_f") || isempty(d["GHP"]["ghpghx_inputs"][1]["ambient_temperature_f"]) - url = string("https://developer.nrel.gov/api/pvwatts/v6.json", "?api_key=", nrel_developer_key, + dataset = "nsrdb" + if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 + if longitude < 81.5 || longitude > 179.5 || latitude < -60.0 || latitude > 60.0 + if longitude < 67.0 || latitude < -40.0 || latitude > 38.0 + dataset = "intl" + end + end + end + url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, "&lat=", d["Site"]["latitude"] , "&lon=", d["Site"]["longitude"], "&tilt=", d["Site"]["latitude"], "&system_capacity=1", "&azimuth=", 180, "&module_type=", 0, "&array_type=", 0, "&losses=", 0.14, "&dc_ac_ratio=", 1.1, - "&gcr=", 0.4, "&inv_eff=", 99, "&timeframe=", "hourly", "&dataset=nsrdb", + "&gcr=", 0.4, "&inv_eff=", 99, "&timeframe=", "hourly", "&dataset=", dataset, "&radius=", 100) try @info "Querying PVWatts for ambient temperature" diff --git a/src/core/utils.jl b/src/core/utils.jl index f511c3f79..ac3a2077d 100644 --- a/src/core/utils.jl +++ b/src/core/utils.jl @@ -377,12 +377,21 @@ function generate_year_profile_hourly(year::Int64, consecutive_periods::Abstract end -function get_ambient_temperature(latitude::Real, longitude::Real; timeframe="hourly") +function get_ambient_temperature(latitude::Real, longitude::Real) + dataset = "nsrdb" + if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 + if longitude < 81.5 || longitude > 179.5 || latitude < -60.0 || latitude > 60.0 + if longitude < 67.0 || latitude < -40.0 || latitude > 38.0 + dataset = "intl" + end + end + end url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, "&lat=", latitude , "&lon=", longitude, "&tilt=", latitude, "&system_capacity=1", "&azimuth=", 180, "&module_type=", 0, "&array_type=", 0, "&losses=", 14, - "&timeframe=", timeframe, "&dataset=nsrdb" + "&timeframe=hourly", # can only get tamb when timeframe=houly according to PVWatts documentation + "&dataset=", dataset ) try @@ -404,12 +413,21 @@ function get_ambient_temperature(latitude::Real, longitude::Real; timeframe="hou end -function get_pvwatts_prodfactor(latitude::Real, longitude::Real; timeframe="hourly") +function get_pvwatts_prodfactor(latitude::Real, longitude::Real; timeframe="hourly", azimuth=180, module_type=0, array_type=1, tilt=latitude) + # Check if site is beyond the bounds of the NRSDB TMY dataset. If so, use the international dataset. + dataset = "nsrdb" + if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 + if longitude < 81.5 || longitude > 179.5 || latitude < -60.0 || latitude > 60.0 + if longitude < 67.0 || latitude < -40.0 || latitude > 38.0 + dataset = "intl" + end + end + end url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, - "&lat=", latitude , "&lon=", longitude, "&tilt=", latitude, - "&system_capacity=1", "&azimuth=", 180, "&module_type=", 0, - "&array_type=", 0, "&losses=", 14, - "&timeframe=", timeframe, "&dataset=nsrdb" + "&lat=", latitude , "&lon=", longitude, "&tilt=", tilt, + "&system_capacity=1", "&azimuth=", azimuth, "&module_type=", module_type, + "&array_type=", array_type, "&losses=", 14, + "&timeframe=", timeframe, "&dataset=", dataset ) try diff --git a/test/runtests.jl b/test/runtests.jl index 447263af5..fa66a39bc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -98,9 +98,9 @@ else # run HiGHS tests r = run_reopt(model, "./scenarios/pv_storage.json") @test r["PV"]["size_kw"] ≈ 216.6667 atol=0.01 - @test r["Financial"]["lcc"] ≈ 1.240037e7 rtol=1e-5 - @test r["ElectricStorage"]["size_kw"] ≈ 55.9 atol=0.1 - @test r["ElectricStorage"]["size_kwh"] ≈ 78.9 atol=0.1 + @test r["Financial"]["lcc"] ≈ 1.239151e7 rtol=1e-5 + @test r["ElectricStorage"]["size_kw"] ≈ 49.0 atol=0.1 + @test r["ElectricStorage"]["size_kwh"] ≈ 83.3 atol=0.1 end @testset "Outage with Generator" begin diff --git a/test/test_with_cplex.jl b/test/test_with_cplex.jl index fd3c2f658..ca7fee696 100644 --- a/test/test_with_cplex.jl +++ b/test/test_with_cplex.jl @@ -59,9 +59,9 @@ end results = run_reopt(model, "./scenarios/pv_storage.json") @test results["PV"]["size_kw"] ≈ 217 atol=1 - @test results["Financial"]["lcc"] ≈ 1.240037e7 rtol=1e-5 - @test results["ElectricStorage"]["size_kw"] ≈ 56 atol=1 - @test results["ElectricStorage"]["size_kwh"] ≈ 79 atol=1 + @test results["Financial"]["lcc"] ≈ 1.239151e7 rtol=1e-5 + @test results["ElectricStorage"]["size_kw"] ≈ 49 atol=1 + @test results["ElectricStorage"]["size_kwh"] ≈ 83 atol=1 end diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index 3189e795c..260c30ab5 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -428,11 +428,11 @@ end results = run_reopt([m1,m2], d) @test results["PV"]["size_kw"] ≈ 216.6667 atol=0.01 - @test results["PV"]["lcoe_per_kwh"] ≈ 0.0483 atol = 0.001 - @test results["Financial"]["lcc"] ≈ 1.240037e7 rtol=1e-5 + @test results["PV"]["lcoe_per_kwh"] ≈ 0.0468 atol = 0.001 + @test results["Financial"]["lcc"] ≈ 1.239151e7rtol=1e-5 @test results["Financial"]["lcc_bau"] ≈ 12766397 rtol=1e-5 - @test results["ElectricStorage"]["size_kw"] ≈ 55.9 atol=0.1 - @test results["ElectricStorage"]["size_kwh"] ≈ 78.9 atol=0.1 + @test results["ElectricStorage"]["size_kw"] ≈ 49.02 atol=0.1 + @test results["ElectricStorage"]["size_kwh"] ≈ 83.3 atol=0.1 proforma_npv = REopt.npv(results["Financial"]["offtaker_annual_free_cashflows"] - results["Financial"]["offtaker_annual_free_cashflows_bau"], 0.081) @test results["Financial"]["npv"] ≈ proforma_npv rtol=0.0001 @@ -456,8 +456,8 @@ end # @test r["ElectricStorage"]["maintenance_cost"] ≈ 2972.66 atol=0.01 # the maintenance_cost comes out to 3004.39 on Actions, so we test the LCC since it should match @test r["Financial"]["lcc"] ≈ 1.240096e7 rtol=0.01 - @test last(value.(m[:SOH])) ≈ 63.129 rtol=0.01 - @test r["ElectricStorage"]["size_kwh"] ≈ 78.91 rtol=0.01 + @test last(value.(m[:SOH])) ≈ 66.633 rtol=0.01 + @test r["ElectricStorage"]["size_kwh"] ≈ 83.29 rtol=0.01 # test minimum_avg_soc_fraction d["ElectricStorage"]["minimum_avg_soc_fraction"] = 0.72 From 909cbb2cc386c87d03f09876be6655eb55e57841 Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 21 Jun 2023 17:09:02 -0600 Subject: [PATCH 07/35] update tests --- test/runtests.jl | 2 +- test/test_with_cplex.jl | 2 +- test/test_with_xpress.jl | 92 ++++++++++++++++++++-------------------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index fa66a39bc..26d132d98 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -108,7 +108,7 @@ else # run HiGHS tests "output_flag" => false, "log_to_console" => false) ) results = run_reopt(model, "./scenarios/generator.json") - @test results["Generator"]["size_kw"] ≈ 8.13 atol=0.01 + @test results["Generator"]["size_kw"] ≈ 9.53 atol=0.01 @test (sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 1:9) + sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 13:8760)) == 0 p = REoptInputs("./scenarios/generator.json") diff --git a/test/test_with_cplex.jl b/test/test_with_cplex.jl index ca7fee696..f48b5b7fa 100644 --- a/test/test_with_cplex.jl +++ b/test/test_with_cplex.jl @@ -74,7 +74,7 @@ end @test value(m[:binMGTechUsed]["Generator"]) == 1 @test value(m[:binMGTechUsed]["PV"]) == 1 @test value(m[:binMGStorageUsed]) == 1 - @test results["Financial"]["lcc"] ≈ 7.19753998668e7 atol=5e4 + @test results["Financial"]["lcc"] ≈ 6.82164056207e7 atol=5e4 #= Scenario with $0/kWh value_of_lost_load_per_kwh, 12x169 hour outages, 1kW load/hour, and min_resil_time_steps = 168 diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index 260c30ab5..db4f54587 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -429,7 +429,7 @@ end @test results["PV"]["size_kw"] ≈ 216.6667 atol=0.01 @test results["PV"]["lcoe_per_kwh"] ≈ 0.0468 atol = 0.001 - @test results["Financial"]["lcc"] ≈ 1.239151e7rtol=1e-5 + @test results["Financial"]["lcc"] ≈ 1.239151e7 rtol=1e-5 @test results["Financial"]["lcc_bau"] ≈ 12766397 rtol=1e-5 @test results["ElectricStorage"]["size_kw"] ≈ 49.02 atol=0.1 @test results["ElectricStorage"]["size_kwh"] ≈ 83.3 atol=0.1 @@ -472,7 +472,7 @@ end m2 = Model(optimizer_with_attributes(Xpress.Optimizer, "OUTPUTLOG" => 0)) p = REoptInputs("./scenarios/generator.json") results = run_reopt([m1,m2], p) - @test results["Generator"]["size_kw"] ≈ 8.13 atol=0.01 + @test results["Generator"]["size_kw"] ≈ 9.53 atol=0.01 @test (sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 1:9) + sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 13:8760)) == 0 @test results["ElectricLoad"]["bau_critical_load_met"] == false @@ -493,7 +493,7 @@ end @test value(m[:binMGTechUsed]["CHP"]) ≈ 1 @test value(m[:binMGTechUsed]["PV"]) ≈ 1 @test value(m[:binMGStorageUsed]) ≈ 1 - @test results["Financial"]["lcc"] ≈ 7.0176719775e7 atol=5e4 + @test results["Financial"]["lcc"] ≈ 6.82164056207e7 atol=5e4 #= Scenario with $0.001/kWh value_of_lost_load_per_kwh, 12x169 hour outages, 1kW load/hour, and min_resil_time_steps = 168 @@ -513,8 +513,8 @@ end # Scenario with generator, PV, electric storage m = Model(optimizer_with_attributes(Xpress.Optimizer, "OUTPUTLOG" => 0)) results = run_reopt(m, "./scenarios/outages_gen_pv_stor.json") - @test results["Outages"]["expected_outage_cost"] ≈ 4.800393567995261e6 atol=10 - @test results["Financial"]["lcc"] ≈ 8.9857671584e7 atol=100 + @test results["Outages"]["expected_outage_cost"] ≈ 3.5478948132891157e6 atol=10 + @test results["Financial"]["lcc"] ≈ 8.64478971865e7 atol=100 # Scenario with generator, PV, wind, electric storage m = Model(optimizer_with_attributes(Xpress.Optimizer, "OUTPUTLOG" => 0)) @@ -522,8 +522,8 @@ end @test value(m[:binMGTechUsed]["Generator"]) ≈ 1 @test value(m[:binMGTechUsed]["PV"]) ≈ 1 @test value(m[:binMGTechUsed]["Wind"]) ≈ 1 - @test results["Outages"]["expected_outage_cost"] ≈ 50147.6 atol=1.0 - @test results["Financial"]["lcc"] ≈ 6.84048993e7 rtol=0.001 + @test results["Outages"]["expected_outage_cost"] ≈ 430157.43 atol=1.0 + @test results["Financial"]["lcc"] ≈ 6.71661825335e7 rtol=0.001 end @testset "Multiple Sites" begin @@ -533,7 +533,7 @@ end REoptInputs("./scenarios/monthly_rate.json"), ]; results = run_reopt(m, ps) - @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.240037e7 + 437169.0 rtol=1e-5 + @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.2830591384e7 rtol=1e-5 end @testset "MPC" begin @@ -708,10 +708,10 @@ end @test ground_pv["lifecycle_om_cost_after_tax_bau"] ≈ 782.0 atol=0.1 @test roof_west["lifecycle_om_cost_after_tax_bau"] ≈ 782.0 atol=0.1 @test ground_pv["annual_energy_produced_kwh_bau"] ≈ 8844.19 atol=0.1 - @test roof_west["annual_energy_produced_kwh_bau"] ≈ 7440.1 atol=0.1 - @test ground_pv["annual_energy_produced_kwh"] ≈ 26533.54 atol=0.1 - @test roof_west["annual_energy_produced_kwh"] ≈ 10416.52 atol=0.1 - @test roof_east["annual_energy_produced_kwh"] ≈ 6482.37 atol=0.1 + @test roof_west["annual_energy_produced_kwh_bau"] ≈ 7656.11 atol=0.1 + @test ground_pv["annual_energy_produced_kwh"] ≈ 26735.22 atol=0.1 + @test roof_west["annual_energy_produced_kwh"] ≈ 10719.51 atol=0.1 + @test roof_east["annual_energy_produced_kwh"] ≈ 6685.95 atol=0.1 end @testset "Thermal Energy Storage + Absorption Chiller" begin @@ -1305,67 +1305,67 @@ end end if i == 1 - @test results["PV"]["size_kw"] ≈ 61.16 atol=1e-1 + @test results["PV"]["size_kw"] ≈ 60.12 atol=1e-1 @test results["ElectricStorage"]["size_kw"] ≈ 0.0 atol=1e-1 @test results["ElectricStorage"]["size_kwh"] ≈ 0.0 atol=1e-1 @test results["Generator"]["size_kw"] ≈ 21.52 atol=1e-1 - expected_npv = -70908 + expected_npv = -70009 @test (expected_npv - results["Financial"]["npv"])/expected_npv ≈ 0.0 atol=1e-2 @test results["Site"]["annual_renewable_electricity_kwh"] ≈ 76412.02 @test results["Site"]["renewable_electricity_fraction"] ≈ 0.8 - @test results["Site"]["renewable_electricity_fraction_bau"] ≈ 0.14495 atol=1e-4 + @test results["Site"]["renewable_electricity_fraction_bau"] ≈ 0.147698 atol=1e-4 @test results["Site"]["total_renewable_energy_fraction"] ≈ 0.8 - @test results["Site"]["total_renewable_energy_fraction_bau"] ≈ 0.14495 atol=1e-4 - @test results["Site"]["lifecycle_emissions_reduction_CO2_fraction"] ≈ 0.61865 atol=1e-4 - @test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] ≈ 283.5 atol=1 - @test results["Site"]["annual_emissions_tonnes_CO2"] ≈ 11.36 atol=1e-2 - @test results["Site"]["annual_emissions_tonnes_CO2_bau"] ≈ 32.16 atol=1e-2 - @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2"] ≈ 6.96 + @test results["Site"]["total_renewable_energy_fraction_bau"] ≈ 0.147698 atol=1e-4 + @test results["Site"]["lifecycle_emissions_reduction_CO2_fraction"] ≈ 0.616639 atol=1e-4 + @test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] ≈ 281.6 atol=1 + @test results["Site"]["annual_emissions_tonnes_CO2"] ≈ 11.38 atol=1e-2 + @test results["Site"]["annual_emissions_tonnes_CO2_bau"] ≈ 32.06 atol=1e-2 + @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2"] ≈ 7.04 @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 - @test results["Financial"]["lifecycle_emissions_cost_climate"] ≈ 7752.46 atol=1 - @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 20514.15 atol=1e-1 - @test results["Site"]["lifecycle_emissions_tonnes_CO2"] ≈ 217.19 - @test results["Site"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 569.53 - @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2"] ≈ 139.18 + @test results["Financial"]["lifecycle_emissions_cost_climate"] ≈ 7767.6 atol=1 + @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 20447.72 atol=1e-1 + @test results["Site"]["lifecycle_emissions_tonnes_CO2"] ≈ 217.63 + @test results["Site"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 567.69 + @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2"] ≈ 140.75 @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 - @test results["ElectricUtility"]["annual_emissions_tonnes_CO2"] ≈ 4.41 + @test results["ElectricUtility"]["annual_emissions_tonnes_CO2"] ≈ 4.34 @test results["ElectricUtility"]["annual_emissions_tonnes_CO2_bau"] ≈ 32.16 - @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2"] ≈ 78.01 - @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 569.53 + @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2"] ≈ 76.88 + @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 567.69 elseif i == 2 #commented out values are results using same levelization factor as API - @test results["PV"]["size_kw"] ≈ 97.52 atol=1 - @test results["ElectricStorage"]["size_kw"] ≈ 20.27 atol=1 # 20.29 - @test results["ElectricStorage"]["size_kwh"] ≈ 159.05 atol=1 + @test results["PV"]["size_kw"] ≈ 106.13 atol=1 + @test results["ElectricStorage"]["size_kw"] ≈ 21.58 atol=1 # 20.29 + @test results["ElectricStorage"]["size_kwh"] ≈ 165.27 atol=1 @test !haskey(results, "Generator") # NPV @info results["Financial"]["npv"] - expected_npv = -249474.49 + expected_npv = -267404.54 @test (expected_npv - results["Financial"]["npv"])/expected_npv ≈ 0.0 atol=1e-3 # Renewable energy - @test results["Site"]["renewable_electricity_fraction"] ≈ 0.786193 atol=1e-3 - @test results["Site"]["annual_renewable_electricity_kwh"] ≈ 78619.3 atol=10 - @test results["Site"]["renewable_electricity_fraction_bau"] ≈ 0.1365 atol=1e-3 #0.1354 atol=1e-3 - @test results["Site"]["annual_renewable_electricity_kwh_bau"] ≈ 13650.39 atol=10 # 13542.62 atol=10 - @test results["Site"]["total_renewable_energy_fraction"] ≈ 0.786193 atol=1e-3 - @test results["Site"]["total_renewable_energy_fraction_bau"] ≈ 0.1365 atol=1e-3 # 0.1354 atol=1e-3 + @test results["Site"]["renewable_electricity_fraction"] ≈ 0.783298 atol=1e-3 + @test results["Site"]["annual_renewable_electricity_kwh"] ≈ 78329.85 atol=10 + @test results["Site"]["renewable_electricity_fraction_bau"] ≈ 0.132118 atol=1e-3 #0.1354 atol=1e-3 + @test results["Site"]["annual_renewable_electricity_kwh_bau"] ≈ 13211.78 atol=10 # 13542.62 atol=10 + @test results["Site"]["total_renewable_energy_fraction"] ≈ 0.783298 atol=1e-3 + @test results["Site"]["total_renewable_energy_fraction_bau"] ≈ 0.132118 atol=1e-3 # 0.1354 atol=1e-3 # CO2 emissions - totals ≈ from grid, from fuelburn, ER, $/tCO2 breakeven @test results["Site"]["lifecycle_emissions_reduction_CO2_fraction"] ≈ 0.8 atol=1e-3 # 0.8 - @test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] ≈ 351.24 atol=1e-1 + @test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] ≈ 374.242 atol=1e-1 @test results["Site"]["annual_emissions_tonnes_CO2"] ≈ 14.2 atol=1 @test results["Site"]["annual_emissions_tonnes_CO2_bau"] ≈ 70.99 atol=1 @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2"] ≈ 0.0 atol=1 # 0.0 @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 atol=1 # 0.0 - @test results["Financial"]["lifecycle_emissions_cost_climate"] ≈ 9056.43 atol=1 - @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 45282.17 atol=1 - @test results["Site"]["lifecycle_emissions_tonnes_CO2"] ≈ 251.43 atol=1 - @test results["Site"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 1257.16 atol=1 + @test results["Financial"]["lifecycle_emissions_cost_climate"] ≈ 9110.21 atol=1 + @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 45551.06 atol=1 + @test results["Site"]["lifecycle_emissions_tonnes_CO2"] ≈ 252.92 atol=1 + @test results["Site"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 1264.62 atol=1 @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2"] ≈ 0.0 atol=1 # 0.0 @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 atol=1 # 0.0 @test results["ElectricUtility"]["annual_emissions_tonnes_CO2"] ≈ 14.2 atol=1 @test results["ElectricUtility"]["annual_emissions_tonnes_CO2_bau"] ≈ 70.99 atol=1 - @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2"] ≈ 251.43 atol=1 - @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 1257.16 atol=1 + @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2"] ≈ 252.92 atol=1 + @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 1264.62 atol=1 #also test CO2 breakeven cost inputs["PV"]["min_kw"] = results["PV"]["size_kw"] - inputs["PV"]["existing_kw"] From d79b1e3d4d2afff21d87c9d22a409cd9c471e415 Mon Sep 17 00:00:00 2001 From: adfarth Date: Thu, 22 Jun 2023 08:38:29 -0600 Subject: [PATCH 08/35] Update Tests --- test/runtests.jl | 2 +- test/test_with_cplex.jl | 2 +- test/test_with_xpress.jl | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 26d132d98..9a3ae7983 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -464,7 +464,7 @@ else # run HiGHS tests @test reliability_results["unlimited_fuel_cumulative_survival_final_time_step"][1] ≈ 0.802997 atol=0.0001 @test reliability_results["cumulative_survival_final_time_step"][1] ≈ 0.802997 atol=0.0001 - @test reliability_results["mean_cumulative_survival_final_time_step"] ≈ 0.817088 atol=0.0001 + @test reliability_results["mean_cumulative_survival_final_time_step"] ≈ 0.817586 atol=0.0001 end # removed Wind test for two reasons diff --git a/test/test_with_cplex.jl b/test/test_with_cplex.jl index f48b5b7fa..c8d359e89 100644 --- a/test/test_with_cplex.jl +++ b/test/test_with_cplex.jl @@ -98,7 +98,7 @@ end REoptInputs("./scenarios/monthly_rate.json"), ]; results = run_reopt(m, ps) - @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.23887e7 + 437169.0 rtol=1e-5 + @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.2830591384e7 rtol=1e-5 end diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index db4f54587..68a322101 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -707,7 +707,7 @@ end @test roof_east["size_kw"] ≈ 4 atol=0.1 @test ground_pv["lifecycle_om_cost_after_tax_bau"] ≈ 782.0 atol=0.1 @test roof_west["lifecycle_om_cost_after_tax_bau"] ≈ 782.0 atol=0.1 - @test ground_pv["annual_energy_produced_kwh_bau"] ≈ 8844.19 atol=0.1 + @test ground_pv["annual_energy_produced_kwh_bau"] ≈ 8912.06 atol=0.1 @test roof_west["annual_energy_produced_kwh_bau"] ≈ 7656.11 atol=0.1 @test ground_pv["annual_energy_produced_kwh"] ≈ 26735.22 atol=0.1 @test roof_west["annual_energy_produced_kwh"] ≈ 10719.51 atol=0.1 @@ -1329,7 +1329,7 @@ end @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2"] ≈ 140.75 @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 @test results["ElectricUtility"]["annual_emissions_tonnes_CO2"] ≈ 4.34 - @test results["ElectricUtility"]["annual_emissions_tonnes_CO2_bau"] ≈ 32.16 + @test results["ElectricUtility"]["annual_emissions_tonnes_CO2_bau"] ≈ 32.06 @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2"] ≈ 76.88 @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 567.69 elseif i == 2 From 5ac532aa8cb2c3b6e948c59796c0b80a82e831a9 Mon Sep 17 00:00:00 2001 From: adfarth Date: Thu, 29 Jun 2023 17:01:08 -0600 Subject: [PATCH 09/35] Update urdb.jl --- src/core/urdb.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/urdb.jl b/src/core/urdb.jl index 41cbbefe5..f90d19ea5 100644 --- a/src/core/urdb.jl +++ b/src/core/urdb.jl @@ -99,7 +99,7 @@ function URDBrate(urdb_response::Dict, year::Int; time_steps_per_hour=1) n_monthly_demand_tiers, monthly_demand_tier_limits, monthly_demand_rates, n_tou_demand_tiers, tou_demand_tier_limits, tou_demand_rates, tou_demand_ratchet_time_steps = parse_demand_rates(urdb_response, year, time_steps_per_hour=time_steps_per_hour) - + energy_rates, energy_tier_limits, n_energy_tiers, sell_rates = parse_urdb_energy_costs(urdb_response, year; time_steps_per_hour=time_steps_per_hour) @@ -292,10 +292,12 @@ function parse_urdb_energy_costs(d::Dict, year::Int; time_steps_per_hour=1, bigM end if non_kwh_units rate = rate_average + total_rate = rate else rate = get(d["energyratestructure"][period][tier_use], "rate", 0) + total_rate = rate + get(d["energyratestructure"][period][tier_use], "adj", 0) end - total_rate = rate + get(d["energyratestructure"][period][tier_use], "adj", 0) + sell = get(d["energyratestructure"][period][tier_use], "sell", 0) for step in range(1, stop=time_steps_per_hour) # repeat hourly rates intrahour From 847e23b67a93a71c374c604468b2c65abcfb9080 Mon Sep 17 00:00:00 2001 From: adfarth Date: Fri, 30 Jun 2023 07:37:40 -0600 Subject: [PATCH 10/35] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c4b2bed9..1728e5a7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ Classify the change according to the following categories: ### Deprecated ### Removed +## Develop +### Fixed +- Don't double add adjustments to urdb rates with non-standard units ## v0.32.3 ### Fixed - Calculate **num_battery_bins** default in `backup_reliability.jl` based on battery duration to prevent significant discretization error (and add test) From 25fb1fc626cb37cb51ee9b62212dc89582e9bb38 Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Sun, 2 Jul 2023 15:24:20 -0600 Subject: [PATCH 11/35] Update single PVWatts API function For both production factor (PV) and ambient air temperature data (GHP) --- src/core/utils.jl | 69 +++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/src/core/utils.jl b/src/core/utils.jl index ac3a2077d..705f69dac 100644 --- a/src/core/utils.jl +++ b/src/core/utils.jl @@ -377,43 +377,15 @@ function generate_year_profile_hourly(year::Int64, consecutive_periods::Abstract end -function get_ambient_temperature(latitude::Real, longitude::Real) - dataset = "nsrdb" - if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 - if longitude < 81.5 || longitude > 179.5 || latitude < -60.0 || latitude > 60.0 - if longitude < 67.0 || latitude < -40.0 || latitude > 38.0 - dataset = "intl" - end - end - end - url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, - "&lat=", latitude , "&lon=", longitude, "&tilt=", latitude, - "&system_capacity=1", "&azimuth=", 180, "&module_type=", 0, - "&array_type=", 0, "&losses=", 14, - "&timeframe=hourly", # can only get tamb when timeframe=houly according to PVWatts documentation - "&dataset=", dataset - ) - - try - @info "Querying PVWatts for ambient temperature... " - r = HTTP.get(url) - response = JSON.parse(String(r.body)) - if r.status != 200 - throw(@error("Bad response from PVWatts: $(response["errors"])")) - end - @info "PVWatts success." - tamb = collect(get(response["outputs"], "tamb", [])) # Celcius - if length(tamb) != 8760 - throw(@error("PVWatts did not return a valid temperature. Got $tamb")) - end - return tamb - catch e - throw(@error("Error occurred when calling PVWatts: $e")) - end -end - +""" + call_pvwatts_api(latitude::Real, longitude::Real; timeframe="hourly", azimuth=180, module_type=0, array_type=1, tilt=latitude, time_steps_per_hour=1) -function get_pvwatts_prodfactor(latitude::Real, longitude::Real; timeframe="hourly", azimuth=180, module_type=0, array_type=1, tilt=latitude) +This calls the PVWatts API and returns both: + - PV production factor + - Ambient outdoor air dry bulb temperature profile [Celcius] +""" +function call_pvwatts_api(latitude::Real, longitude::Real; tilt=latitude, azimuth=180, module_type=1, array_type=1, + losses=14, dc_ac_ratio=1.2, gcr=0.4, inv_eff=96, timeframe="hourly", radius=0, time_steps_per_hour=1) # Check if site is beyond the bounds of the NRSDB TMY dataset. If so, use the international dataset. dataset = "nsrdb" if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 @@ -426,23 +398,36 @@ function get_pvwatts_prodfactor(latitude::Real, longitude::Real; timeframe="hour url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, "&lat=", latitude , "&lon=", longitude, "&tilt=", tilt, "&system_capacity=1", "&azimuth=", azimuth, "&module_type=", module_type, - "&array_type=", array_type, "&losses=", 14, - "&timeframe=", timeframe, "&dataset=", dataset - ) + "&array_type=", array_type, "&losses=", losses, "&dc_ac_ratio=", dc_ac_ratio, + "&gcr=", gcr, "&inv_eff=", inv_eff, "&timeframe=", timeframe, "&dataset=", dataset, + "&radius=", radius + ) try - @info "Querying PVWatts for production factor of 1 kW system with tilt set to latitude... " - r = HTTP.get(url) + @info "Querying PVWatts for production factor and ambient air temperature... " + r = HTTP.get(url, keepalive=true, readtimeout=10) response = JSON.parse(String(r.body)) if r.status != 200 throw(@error("Bad response from PVWatts: $(response["errors"])")) end @info "PVWatts success." + # Get both possible data of interest watts = collect(get(response["outputs"], "ac", []) / 1000) # scale to 1 kW system (* 1 kW / 1000 W) + tamb_celcius = collect(get(response["outputs"], "tamb", [])) # Celcius + # Validate outputs if length(watts) != 8760 throw(@error("PVWatts did not return a valid prodfactor. Got $watts")) end - return watts + # Validate tamb_celcius + if length(tamb_celcius) != 8760 + throw(@error("PVWatts did not return a valid temperature. Got $tamb_celcius")) + end + # Upsample or downsample based on model time_steps_per_hour + if time_steps_per_hour > 1 + watts = repeat(watts, inner=time_steps_per_hour) + tamb_celcius = repeat(tamb_celcius, inner=time_steps_per_hour) + end + return watts, tamb_celcius catch e throw(@error("Error occurred when calling PVWatts: $e")) end From b9be3daaf570cc257cc1d64505939d992083c834 Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Sun, 2 Jul 2023 15:25:03 -0600 Subject: [PATCH 12/35] Use call_pvwatts_api() for get_production_factor(PV) --- src/core/production_factor.jl | 42 +++++------------------------------ 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/src/core/production_factor.jl b/src/core/production_factor.jl index beba394ff..12786c438 100644 --- a/src/core/production_factor.jl +++ b/src/core/production_factor.jl @@ -35,44 +35,14 @@ function get_production_factor(pv::PV, latitude::Real, longitude::Real; timefram return pv.production_factor_series end - # Check if site is beyond the bounds of the NRSDB TMY dataset. If so, use the international dataset. - dataset = "nsrdb" - if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 - if longitude < 81.5 || longitude > 179.5 || latitude < -60.0 || latitude > 60.0 - if longitude < 67.0 || latitude < -40.0 || latitude > 38.0 - dataset = "intl" - end - end - end + # TODO need to add all of these parameters defined above into the call_pvwatts_api function arguments + watts, ambient_temp_celcius = call_pvwatts_api(latitude, longitude; tilt=pv.tilt, azimuth=pv.azimuth, module_type=pv.module_type, + array_type=pv.array_type, losses=round(pv.losses*100, digits=3), dc_ac_ratio=pv.dc_ac_ratio, + gcr=pv.gcr, inv_eff=pv.inv_eff*100, timeframe=timeframe, radius=pv.radius, + time_steps_per_hour=time_steps_per_hour) - url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, - "&lat=", latitude , "&lon=", longitude, "&tilt=", pv.tilt, - "&system_capacity=1", "&azimuth=", pv.azimuth, "&module_type=", pv.module_type, - "&array_type=", pv.array_type, "&losses=", round(pv.losses*100, digits=3), "&dc_ac_ratio=", pv.dc_ac_ratio, - "&gcr=", pv.gcr, "&inv_eff=", pv.inv_eff*100, "&timeframe=", timeframe, "&dataset=", dataset, - "&radius=", pv.radius - ) + return watts - try - @info "Querying PVWatts for production_factor with " pv.name - r = HTTP.get(url, keepalive=true, readtimeout=10) - @info "Response received from PVWatts" - response = JSON.parse(String(r.body)) - if r.status != 200 - throw(@error("Bad response from PVWatts: $(response["errors"])")) - end - @info "PVWatts success." - watts = collect(get(response["outputs"], "ac", []) / 1000) # scale to 1 kW system (* 1 kW / 1000 W) - if length(watts) != 8760 - throw(@error("PVWatts did not return a valid production factor. Got $watts")) - end - if time_steps_per_hour > 1 - watts = repeat(watts, inner=time_steps_per_hour) - end - return watts - catch e - throw(@error("Error occurred when calling PVWatts: $e")) - end end From 5e7887bc1d6253d69b3ce902c3057db7a1e71bd3 Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Sun, 2 Jul 2023 15:26:22 -0600 Subject: [PATCH 13/35] Use call_pvwatts_api for GHP ambient temp, and assign PV production_factor at the same time This avoids an extra call of PVWatts with GHP and PV --- src/core/scenario.jl | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/src/core/scenario.jl b/src/core/scenario.jl index 0f5202053..904e07855 100644 --- a/src/core/scenario.jl +++ b/src/core/scenario.jl @@ -454,45 +454,27 @@ function Scenario(d::Dict; flex_hvac_from_json=false) number_of_ghpghx = length(d["GHP"]["ghpghx_inputs"]) end # Call PVWatts for hourly dry-bulb outdoor air temperature - ambient_temperature_f = [] + ambient_temp_degF = [] if !haskey(d["GHP"]["ghpghx_inputs"][1], "ambient_temperature_f") || isempty(d["GHP"]["ghpghx_inputs"][1]["ambient_temperature_f"]) - dataset = "nsrdb" - if longitude < -179.5 || longitude > -21.0 || latitude < -21.5 || latitude > 60.0 - if longitude < 81.5 || longitude > 179.5 || latitude < -60.0 || latitude > 60.0 - if longitude < 67.0 || latitude < -40.0 || latitude > 38.0 - dataset = "intl" - end - end - end - url = string("https://developer.nrel.gov/api/pvwatts/v8.json", "?api_key=", nrel_developer_key, - "&lat=", d["Site"]["latitude"] , "&lon=", d["Site"]["longitude"], "&tilt=", d["Site"]["latitude"], - "&system_capacity=1", "&azimuth=", 180, "&module_type=", 0, - "&array_type=", 0, "&losses=", 0.14, "&dc_ac_ratio=", 1.1, - "&gcr=", 0.4, "&inv_eff=", 99, "&timeframe=", "hourly", "&dataset=", dataset, - "&radius=", 100) - try - @info "Querying PVWatts for ambient temperature" - r = HTTP.get(url) - response = JSON.parse(String(r.body)) - if r.status != 200 - throw(@error("Bad response from PVWatts: $(response["errors"])")) + # If PV is evaluated and we need to call PVWatts for ambient temperature, assign PV production factor here too with the same call + # By assigning pv.production_factor_series here, it will skip the PVWatts call in get_production_factor(PV) call from reopt_input.jl + if !isempty(pvs) + for pv in pvs + pv.production_factor_series, ambient_temp_celcius = call_pvwatts_api(site.latitude, site.longitude; tilt=pv.tilt, azimuth=pv.azimuth, module_type=pv.module_type, + array_type=pv.array_type, losses=round(pv.losses*100, digits=3), dc_ac_ratio=pv.dc_ac_ratio, + gcr=pv.gcr, inv_eff=pv.inv_eff*100, timeframe="hourly", radius=pv.radius, time_steps_per_hour=settings.time_steps_per_hour) end - @info "PVWatts success." - temp_c = get(response["outputs"], "tamb", []) - if length(temp_c) != 8760 || isempty(temp_c) - throw(@error("PVWatts did not return a valid temperature profile. Got $temp_c")) - end - ambient_temperature_f = temp_c * 1.8 .+ 32.0 - catch e - throw(@error("Error occurred when calling PVWatts: $e")) + else + pv_prodfactor, ambient_temp_celcius = call_pvwatts_api(site.latitude, site.longitude; time_steps_per_hour=settings.time_steps_per_hour) end + ambient_temp_degF = ambient_temp_celcius * 1.8 .+ 32.0 else - ambient_temperature_f = d["GHP"]["ghpghx_inputs"][1]["ambient_temperature_f"] + ambient_temp_degF = d["GHP"]["ghpghx_inputs"][1]["ambient_temperature_f"] end for i in 1:number_of_ghpghx ghpghx_inputs = d["GHP"]["ghpghx_inputs"][i] - d["GHP"]["ghpghx_inputs"][i]["ambient_temperature_f"] = ambient_temperature_f + d["GHP"]["ghpghx_inputs"][i]["ambient_temperature_f"] = ambient_temp_degF # Only SpaceHeating portion of Heating Load gets served by GHP, unless allowed by can_serve_dhw if get(ghpghx_inputs, "heating_thermal_load_mmbtu_per_hr", []) in [nothing, []] if haskey(d["GHP"], "can_serve_dhw") && d["GHP"]["can_serve_dhw"] From d6d1d48a9935ec53d66bbac3ca64571181039f52 Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Sun, 2 Jul 2023 15:27:46 -0600 Subject: [PATCH 14/35] Make PV struct mutable This allows for assigning pv.production_factor_series when calling PVWatts for GHP, to avoid a extra PVWatts calls later --- src/core/pv.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/pv.jl b/src/core/pv.jl index df6d69085..9a071e6a5 100644 --- a/src/core/pv.jl +++ b/src/core/pv.jl @@ -82,7 +82,7 @@ If `azimuth` is not provided, then it is set to 180 if the site is in the northern hemisphere and 0 if in the southern hemisphere. """ -struct PV <: AbstractTech +mutable struct PV <: AbstractTech tilt array_type module_type @@ -151,7 +151,7 @@ struct PV <: AbstractTech acres_per_kw::Real=6e-3, inv_eff::Real=0.96, dc_ac_ratio::Real=1.2, - production_factor_series::Union{Nothing, Array{Real,1}} = nothing, + production_factor_series::Union{Nothing, Array{<:Real,1}} = nothing, federal_itc_fraction::Real = 0.3, federal_rebate_per_kw::Real = 0.0, state_ibi_fraction::Real = 0.0, From d910720274836ef4e9341af1b0f23712a97b660d Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Sun, 2 Jul 2023 17:14:41 -0600 Subject: [PATCH 15/35] Update function call to call_pvwatts_api() The get_ambient_temperature() function is now combined into that call. --- test/test_with_xpress.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index 68a322101..e40fd3e71 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -256,7 +256,7 @@ end =# # Austin, TX -> existing_chiller and existing_boiler added with FlexibleHVAC - tamb = REopt.get_ambient_temperature(30.2672, -97.7431); + pf, tamb = REopt.call_pvwatts_api(30.2672, -97.7431); R = 0.00025 # K/kW C = 1e5 # kJ/K # the starting scenario has flat fuel and electricty costs From 80ebfd4f8f658631e495fbe03754e35cb4cfd4d2 Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:25:32 -0700 Subject: [PATCH 16/35] update generator capx default --- src/core/generator.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/generator.jl b/src/core/generator.jl index 31a9b7969..c07c783f8 100644 --- a/src/core/generator.jl +++ b/src/core/generator.jl @@ -33,7 +33,7 @@ existing_kw::Real = 0, min_kw::Real = 0, max_kw::Real = 1.0e6, - installed_cost_per_kw::Real = 500.0, + installed_cost_per_kw::Real = 650.0, om_cost_per_kw::Real = off_grid_flag ? 20.0 : 10.0, om_cost_per_kwh::Real = 0.0, fuel_cost_per_gallon::Real = 3.0, @@ -128,7 +128,7 @@ struct Generator <: AbstractGenerator existing_kw::Real = 0, min_kw::Real = 0, max_kw::Real = 1.0e6, - installed_cost_per_kw::Real = 500.0, + installed_cost_per_kw::Real = 650.0, om_cost_per_kw::Real= off_grid_flag ? 20.0 : 10.0, om_cost_per_kwh::Real = 0.0, fuel_cost_per_gallon::Real = 3.0, From e052a74db3f5eeb6c71fc85096eda30d32d3ba2a Mon Sep 17 00:00:00 2001 From: adfarth Date: Wed, 5 Jul 2023 11:02:21 -0600 Subject: [PATCH 17/35] update changelog, module_type=0, remove todo --- CHANGELOG.md | 5 +++-- src/core/production_factor.jl | 1 - src/core/site.jl | 2 +- src/core/utils.jl | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2186d986b..2bdc75c65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,9 +26,10 @@ Classify the change according to the following categories: ## Develop - 2023-06-21 ### Changed -- In `src/core/production_factor.jl`, updated NSRDB bounds used in PVWatts query (now includes southern New Zealand) +- Consolidated PVWatts API calls to 1 call (previously 3 separate calls existed). API call occurs in `src/core/utils.jl/call_pvwatts_api()`. This function is called for PV in `src/core/production_factor.jl/get_production_factor(PV)` and for GHP in `src/core/scenario.jl`. If GHP and PV are evaluated together, the GHP PVWatts call for ambient temperature is also used to assign the pv.production_factor_series in Scenario.jl so that the PVWatts API does not get called again downstream in `get_production_factor(PV)`. +- In `src/core/utils.jl/call_pvwatts_api()`, updated NSRDB bounds used in PVWatts query (now includes southern New Zealand) - Updated PV Watts version from v6 to v8. PVWatts V8 updates the weather data to 2020 TMY data from the NREL NSRDB for locations covered by the database. (The NSRDB weather data used in PVWatts V6 is from around 2015.) See other differences at https://developer.nrel.gov/docs/solar/pvwatts/. -- Updated PVwatts calls in `src/core/utils.jl` (`get_ambient_temperature` and `get_pvwatts_prodfactor`) and `scenario.jl` (used for GHP) to use v8 and to determine dataset based on lat long. +- Made PV struct mutable: This allows for assigning pv.production_factor_series when calling PVWatts for GHP, to avoid a extra PVWatts calls later. ## v0.32.3 ### Fixed - Calculate **num_battery_bins** default in `backup_reliability.jl` based on battery duration to prevent significant discretization error (and add test) diff --git a/src/core/production_factor.jl b/src/core/production_factor.jl index 12786c438..d1b0eedcc 100644 --- a/src/core/production_factor.jl +++ b/src/core/production_factor.jl @@ -35,7 +35,6 @@ function get_production_factor(pv::PV, latitude::Real, longitude::Real; timefram return pv.production_factor_series end - # TODO need to add all of these parameters defined above into the call_pvwatts_api function arguments watts, ambient_temp_celcius = call_pvwatts_api(latitude, longitude; tilt=pv.tilt, azimuth=pv.azimuth, module_type=pv.module_type, array_type=pv.array_type, losses=round(pv.losses*100, digits=3), dc_ac_ratio=pv.dc_ac_ratio, gcr=pv.gcr, inv_eff=pv.inv_eff*100, timeframe=timeframe, radius=pv.radius, diff --git a/src/core/site.jl b/src/core/site.jl index 2907ae879..6b42c2608 100644 --- a/src/core/site.jl +++ b/src/core/site.jl @@ -36,7 +36,7 @@ Inputs related to the physical location: longitude::Real, land_acres::Union{Real, Nothing} = nothing, # acres of land available for PV panels and/or Wind turbines. Constraint applied separately to PV and Wind, meaning the two technologies are assumed to be able to be co-located. roof_squarefeet::Union{Real, Nothing} = nothing, - min_resil_time_steps::Int=0, + min_resil_time_steps::Int=0, # The minimum number consecutive timesteps that load must be fully met once an outage begins. Only applies to multiple outage modeling using inputs outage_start_time_steps and outage_durations. mg_tech_sizes_equal_grid_sizes::Bool = true, node::Int = 1, CO2_emissions_reduction_min_fraction::Union{Float64, Nothing} = nothing, diff --git a/src/core/utils.jl b/src/core/utils.jl index 705f69dac..650af9446 100644 --- a/src/core/utils.jl +++ b/src/core/utils.jl @@ -378,13 +378,13 @@ end """ - call_pvwatts_api(latitude::Real, longitude::Real; timeframe="hourly", azimuth=180, module_type=0, array_type=1, tilt=latitude, time_steps_per_hour=1) - + call_pvwatts_api(latitude::Real, longitude::Real; tilt=latitude, azimuth=180, module_type=0, array_type=1, + losses=14, dc_ac_ratio=1.2, gcr=0.4, inv_eff=96, timeframe="hourly", radius=0, time_steps_per_hour=1) This calls the PVWatts API and returns both: - PV production factor - Ambient outdoor air dry bulb temperature profile [Celcius] """ -function call_pvwatts_api(latitude::Real, longitude::Real; tilt=latitude, azimuth=180, module_type=1, array_type=1, +function call_pvwatts_api(latitude::Real, longitude::Real; tilt=latitude, azimuth=180, module_type=0, array_type=1, losses=14, dc_ac_ratio=1.2, gcr=0.4, inv_eff=96, timeframe="hourly", radius=0, time_steps_per_hour=1) # Check if site is beyond the bounds of the NRSDB TMY dataset. If so, use the international dataset. dataset = "nsrdb" From 5ed0b2de3c152a6e233b25a0474d079faac7c41d Mon Sep 17 00:00:00 2001 From: Bill Becker Date: Wed, 5 Jul 2023 12:53:19 -0600 Subject: [PATCH 18/35] Fix leap year issue when using URDB rate The energy_rates array was 8784 instead of skipping the leap year day like the rest of the code does This was throwing errors when checking the length of the input like wholesale_rate (8760) with energy_rate from URDB (8784 in this case) --- src/core/urdb.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/urdb.jl b/src/core/urdb.jl index 41cbbefe5..80c204d8a 100644 --- a/src/core/urdb.jl +++ b/src/core/urdb.jl @@ -270,6 +270,9 @@ function parse_urdb_energy_costs(d::Dict, year::Int; time_steps_per_hour=1, bigM for month in range(1, stop=12) n_days = daysinmonth(Date(string(year) * "-" * string(month))) + if month == 2 && isleapyear(year) + n_days -= 1 + end for day in range(1, stop=n_days) From 3ab6e5fcab58eaacf9639dd57b56402fd43f5e34 Mon Sep 17 00:00:00 2001 From: Bill Becker <42586683+Bill-Becker@users.noreply.github.com> Date: Wed, 5 Jul 2023 12:58:32 -0600 Subject: [PATCH 19/35] Add bug fix to CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bdc75c65..ea047ce89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,9 @@ Classify the change according to the following categories: - In `src/core/utils.jl/call_pvwatts_api()`, updated NSRDB bounds used in PVWatts query (now includes southern New Zealand) - Updated PV Watts version from v6 to v8. PVWatts V8 updates the weather data to 2020 TMY data from the NREL NSRDB for locations covered by the database. (The NSRDB weather data used in PVWatts V6 is from around 2015.) See other differences at https://developer.nrel.gov/docs/solar/pvwatts/. - Made PV struct mutable: This allows for assigning pv.production_factor_series when calling PVWatts for GHP, to avoid a extra PVWatts calls later. +### Fixed +- Issue with using a leap year with a URDB rate - the URDB rate was creating energy_rate of length 8784 instead of intended 8760 + ## v0.32.3 ### Fixed - Calculate **num_battery_bins** default in `backup_reliability.jl` based on battery duration to prevent significant discretization error (and add test) From dc865dbaf93b59f25537a2d1a942a98185759bf3 Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:45:58 -0700 Subject: [PATCH 20/35] depend gen installed_cost_per_kw on only_runs_during_grid_outage --- src/core/generator.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/generator.jl b/src/core/generator.jl index c07c783f8..13ca98f99 100644 --- a/src/core/generator.jl +++ b/src/core/generator.jl @@ -30,10 +30,11 @@ """ `Generator` is an optional REopt input with the following keys and default values: ```julia + only_runs_during_grid_outage::Bool = true, existing_kw::Real = 0, min_kw::Real = 0, max_kw::Real = 1.0e6, - installed_cost_per_kw::Real = 650.0, + installed_cost_per_kw::Real = only_runs_during_grid_outage ? 650.0 : 800.0, om_cost_per_kw::Real = off_grid_flag ? 20.0 : 10.0, om_cost_per_kwh::Real = 0.0, fuel_cost_per_gallon::Real = 3.0, @@ -42,7 +43,6 @@ fuel_avail_gal::Real = off_grid_flag ? 1.0e9 : 660.0, fuel_higher_heating_value_kwh_per_gal::Real = 40.7, min_turn_down_fraction::Real = off_grid_flag ? 0.15 : 0.0, - only_runs_during_grid_outage::Bool = true, sells_energy_back_to_grid::Bool = false, can_net_meter::Bool = false, can_wholesale::Bool = false, @@ -125,10 +125,11 @@ struct Generator <: AbstractGenerator function Generator(; off_grid_flag::Bool = false, analysis_years::Int = 25, + only_runs_during_grid_outage::Bool = true, existing_kw::Real = 0, min_kw::Real = 0, max_kw::Real = 1.0e6, - installed_cost_per_kw::Real = 650.0, + installed_cost_per_kw::Real = only_runs_during_grid_outage ? 650.0 : 800.0, om_cost_per_kw::Real= off_grid_flag ? 20.0 : 10.0, om_cost_per_kwh::Real = 0.0, fuel_cost_per_gallon::Real = 3.0, @@ -137,7 +138,6 @@ struct Generator <: AbstractGenerator fuel_avail_gal::Real = off_grid_flag ? 1.0e9 : 660.0, fuel_higher_heating_value_kwh_per_gal::Real = KWH_PER_GAL_DIESEL, min_turn_down_fraction::Real = off_grid_flag ? 0.15 : 0.0, - only_runs_during_grid_outage::Bool = true, sells_energy_back_to_grid::Bool = false, can_net_meter::Bool = false, can_wholesale::Bool = false, From 82cba1f6e5c879b00d83cf9a5fcc853df5b0351d Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Tue, 11 Jul 2023 10:56:33 -0700 Subject: [PATCH 21/35] provide installed_cost_per_kw in tests b/c default changed --- test/scenarios/backup_reliability_reopt_inputs.json | 1 + test/scenarios/emissions.json | 1 + test/scenarios/generator.json | 1 + test/scenarios/mpc.json | 1 + test/scenarios/nogridcost_minresilhours.json | 1 + test/scenarios/nogridcost_multiscenario.json | 1 + test/scenarios/outage.json | 1 + 7 files changed, 7 insertions(+) diff --git a/test/scenarios/backup_reliability_reopt_inputs.json b/test/scenarios/backup_reliability_reopt_inputs.json index 8184026b6..5e761afb3 100644 --- a/test/scenarios/backup_reliability_reopt_inputs.json +++ b/test/scenarios/backup_reliability_reopt_inputs.json @@ -21,6 +21,7 @@ "federal_rebate_per_kw": 350.0 }, "Generator": { + "installed_cost_per_kw": 500.0, "min_kw": 200, "max_kw": 200 }, diff --git a/test/scenarios/emissions.json b/test/scenarios/emissions.json index ff85084ce..8534728ca 100644 --- a/test/scenarios/emissions.json +++ b/test/scenarios/emissions.json @@ -41,6 +41,7 @@ "outage_durations": [10] }, "Generator": { + "installed_cost_per_kw": 500.0, "max_kw": 500.0, "fuel_avail_gal": 125.0, "min_turn_down_fraction": 0.0, diff --git a/test/scenarios/generator.json b/test/scenarios/generator.json index fe658e749..b6de9eddf 100644 --- a/test/scenarios/generator.json +++ b/test/scenarios/generator.json @@ -10,6 +10,7 @@ "outage_end_time_step": 12 }, "Generator": { + "installed_cost_per_kw": 500.0, "max_kw": 500.0, "fuel_avail_gal": 125.0, "min_turn_down_fraction": 0.0, diff --git a/test/scenarios/mpc.json b/test/scenarios/mpc.json index 2a69e5988..89b775759 100644 --- a/test/scenarios/mpc.json +++ b/test/scenarios/mpc.json @@ -101,6 +101,7 @@ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05] }, "Generator": { + "installed_cost_per_kw": 500.0, "size_kw": 30, "only_runs_during_grid_outage": false }, diff --git a/test/scenarios/nogridcost_minresilhours.json b/test/scenarios/nogridcost_minresilhours.json index 34b2feb50..dde3851f9 100644 --- a/test/scenarios/nogridcost_minresilhours.json +++ b/test/scenarios/nogridcost_minresilhours.json @@ -60,6 +60,7 @@ "critical_load_fraction": 1 }, "Generator": { + "installed_cost_per_kw": 500.0 }, "Financial": { "value_of_lost_load_per_kwh": 0.001, diff --git a/test/scenarios/nogridcost_multiscenario.json b/test/scenarios/nogridcost_multiscenario.json index 90d312b05..e6ee92ca8 100644 --- a/test/scenarios/nogridcost_multiscenario.json +++ b/test/scenarios/nogridcost_multiscenario.json @@ -53,6 +53,7 @@ "critical_load_fraction": 0.1 }, "Generator": { + "installed_cost_per_kw": 500.0, "max_kw": 0.0 }, "Financial": { diff --git a/test/scenarios/outage.json b/test/scenarios/outage.json index 64adb56de..1cd720372 100644 --- a/test/scenarios/outage.json +++ b/test/scenarios/outage.json @@ -8,6 +8,7 @@ "outage_durations": [10] }, "Generator": { + "installed_cost_per_kw": 500.0, "existing_kw": 0.0, "min_turn_down_fraction": 0.0, "only_runs_during_grid_outage": true, From de17aafd75dc2a1a78361fe6c2bb6eab1735bb95 Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:07:03 -0700 Subject: [PATCH 22/35] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea047ce89..c0fb780aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Classify the change according to the following categories: - Made PV struct mutable: This allows for assigning pv.production_factor_series when calling PVWatts for GHP, to avoid a extra PVWatts calls later. ### Fixed - Issue with using a leap year with a URDB rate - the URDB rate was creating energy_rate of length 8784 instead of intended 8760 +- Corrected `Generator` **installed_cost_per_kw** from 500 to 650 if **only_runs_during_grid_outage** is _true_ or 800 if _false_ ## v0.32.3 ### Fixed From 270d9bee1524f47ad2f93426c01c1146dfca5456 Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:31:14 -0700 Subject: [PATCH 23/35] remove installed_cost_per_kw from MPC test post --- test/scenarios/mpc.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test/scenarios/mpc.json b/test/scenarios/mpc.json index 89b775759..2a69e5988 100644 --- a/test/scenarios/mpc.json +++ b/test/scenarios/mpc.json @@ -101,7 +101,6 @@ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05] }, "Generator": { - "installed_cost_per_kw": 500.0, "size_kw": 30, "only_runs_during_grid_outage": false }, From c52f3c8c966b776b2cddedfeb572141359a966e0 Mon Sep 17 00:00:00 2001 From: adfarth Date: Mon, 17 Jul 2023 13:01:40 -0600 Subject: [PATCH 24/35] Update CHANGELOG.md --- CHANGELOG.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8260de238..395944dd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,11 +23,7 @@ Classify the change according to the following categories: ### Deprecated ### Removed -## Develop -### Fixed -- Don't double add adjustments to urdb rates with non-standard units - -## Develop - 2023-06-21 +## v0.32.4 ### Changed - Consolidated PVWatts API calls to 1 call (previously 3 separate calls existed). API call occurs in `src/core/utils.jl/call_pvwatts_api()`. This function is called for PV in `src/core/production_factor.jl/get_production_factor(PV)` and for GHP in `src/core/scenario.jl`. If GHP and PV are evaluated together, the GHP PVWatts call for ambient temperature is also used to assign the pv.production_factor_series in Scenario.jl so that the PVWatts API does not get called again downstream in `get_production_factor(PV)`. - In `src/core/utils.jl/call_pvwatts_api()`, updated NSRDB bounds used in PVWatts query (now includes southern New Zealand) @@ -35,6 +31,7 @@ Classify the change according to the following categories: - Made PV struct mutable: This allows for assigning pv.production_factor_series when calling PVWatts for GHP, to avoid a extra PVWatts calls later. ### Fixed - Issue with using a leap year with a URDB rate - the URDB rate was creating energy_rate of length 8784 instead of intended 8760 +- Don't double add adjustments to urdb rates with non-standard units ## v0.32.3 ### Fixed From 83164100e70310b4e53406b4e122db5d6a3e7b78 Mon Sep 17 00:00:00 2001 From: adfarth Date: Mon, 17 Jul 2023 13:04:55 -0600 Subject: [PATCH 25/35] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 156e8992a..2365fef8b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "REopt" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" authors = ["Nick Laws", "Hallie Dunham ", "Bill Becker ", "Bhavesh Rathod ", "Alex Zolan ", "Amanda Farthing "] -version = "0.32.3" +version = "0.32.4" [deps] ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3" From a79612bc49ec083cc5a69a57f10e2e863a4b0f2d Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Fri, 21 Jul 2023 12:28:27 -0600 Subject: [PATCH 26/35] update fuel_avail_gal default to always 1e9 --- src/core/generator.jl | 4 ++-- src/mpc/structs.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/generator.jl b/src/core/generator.jl index 13ca98f99..228febf06 100644 --- a/src/core/generator.jl +++ b/src/core/generator.jl @@ -40,7 +40,7 @@ fuel_cost_per_gallon::Real = 3.0, electric_efficiency_full_load::Real = 0.3233, electric_efficiency_half_load::Real = electric_efficiency_full_load, - fuel_avail_gal::Real = off_grid_flag ? 1.0e9 : 660.0, + fuel_avail_gal::Real = 1.0e9, fuel_higher_heating_value_kwh_per_gal::Real = 40.7, min_turn_down_fraction::Real = off_grid_flag ? 0.15 : 0.0, sells_energy_back_to_grid::Bool = false, @@ -135,7 +135,7 @@ struct Generator <: AbstractGenerator fuel_cost_per_gallon::Real = 3.0, electric_efficiency_full_load::Real = 0.3233, electric_efficiency_half_load::Real = electric_efficiency_full_load, - fuel_avail_gal::Real = off_grid_flag ? 1.0e9 : 660.0, + fuel_avail_gal::Real = 1.0e9, fuel_higher_heating_value_kwh_per_gal::Real = KWH_PER_GAL_DIESEL, min_turn_down_fraction::Real = off_grid_flag ? 0.15 : 0.0, sells_energy_back_to_grid::Bool = false, diff --git a/src/mpc/structs.jl b/src/mpc/structs.jl index c2a66e087..86450478e 100644 --- a/src/mpc/structs.jl +++ b/src/mpc/structs.jl @@ -283,7 +283,7 @@ function MPCGenerator(; fuel_cost_per_gallon::Real = 3.0, electric_efficiency_full_load::Real = 0.3233, electric_efficiency_half_load::Real = electric_efficiency_full_load, - fuel_avail_gal::Real = 660.0, + fuel_avail_gal::Real = 1.0e9, fuel_higher_heating_value_kwh_per_gal::Real = KWH_PER_GAL_DIESEL, min_turn_down_fraction::Real = 0.0, # TODO change this to non-zero value only_runs_during_grid_outage::Bool = true, @@ -310,7 +310,7 @@ struct MPCGenerator <: AbstractGenerator fuel_cost_per_gallon::Real = 3.0, electric_efficiency_full_load::Real = 0.3233, electric_efficiency_half_load::Real = electric_efficiency_full_load, - fuel_avail_gal::Real = 660.0, + fuel_avail_gal::Real = 1.0e9, fuel_higher_heating_value_kwh_per_gal::Real = KWH_PER_GAL_DIESEL, min_turn_down_fraction::Real = 0.0, # TODO change this to non-zero value only_runs_during_grid_outage::Bool = true, From 0b12c3422d1dcf7e8d782ab0632af564712c377b Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Fri, 21 Jul 2023 12:31:30 -0600 Subject: [PATCH 27/35] fix fuel_avail_gal in tests --- test/scenarios/backup_reliability_reopt_inputs.json | 1 + test/scenarios/mpc.json | 1 + test/scenarios/nogridcost_minresilhours.json | 1 + test/scenarios/nogridcost_multiscenario.json | 1 + test/scenarios/outage.json | 1 + 5 files changed, 5 insertions(+) diff --git a/test/scenarios/backup_reliability_reopt_inputs.json b/test/scenarios/backup_reliability_reopt_inputs.json index 5e761afb3..2b1739d40 100644 --- a/test/scenarios/backup_reliability_reopt_inputs.json +++ b/test/scenarios/backup_reliability_reopt_inputs.json @@ -22,6 +22,7 @@ }, "Generator": { "installed_cost_per_kw": 500.0, + "fuel_avail_gal": 660, "min_kw": 200, "max_kw": 200 }, diff --git a/test/scenarios/mpc.json b/test/scenarios/mpc.json index 2a69e5988..988a3d9b8 100644 --- a/test/scenarios/mpc.json +++ b/test/scenarios/mpc.json @@ -101,6 +101,7 @@ 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05] }, "Generator": { + "fuel_avail_gal": 660, "size_kw": 30, "only_runs_during_grid_outage": false }, diff --git a/test/scenarios/nogridcost_minresilhours.json b/test/scenarios/nogridcost_minresilhours.json index dde3851f9..ba787ebaf 100644 --- a/test/scenarios/nogridcost_minresilhours.json +++ b/test/scenarios/nogridcost_minresilhours.json @@ -60,6 +60,7 @@ "critical_load_fraction": 1 }, "Generator": { + "fuel_avail_gal": 660, "installed_cost_per_kw": 500.0 }, "Financial": { diff --git a/test/scenarios/nogridcost_multiscenario.json b/test/scenarios/nogridcost_multiscenario.json index e6ee92ca8..01ec7ccad 100644 --- a/test/scenarios/nogridcost_multiscenario.json +++ b/test/scenarios/nogridcost_multiscenario.json @@ -53,6 +53,7 @@ "critical_load_fraction": 0.1 }, "Generator": { + "fuel_avail_gal": 660, "installed_cost_per_kw": 500.0, "max_kw": 0.0 }, diff --git a/test/scenarios/outage.json b/test/scenarios/outage.json index 1cd720372..9e655c1bf 100644 --- a/test/scenarios/outage.json +++ b/test/scenarios/outage.json @@ -8,6 +8,7 @@ "outage_durations": [10] }, "Generator": { + "fuel_avail_gal": 660, "installed_cost_per_kw": 500.0, "existing_kw": 0.0, "min_turn_down_fraction": 0.0, From 0dc79b87c7f4488c40fe5b447fd1604a04be4379 Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Fri, 21 Jul 2023 13:10:16 -0600 Subject: [PATCH 28/35] trigger tests --- test/test_with_xpress.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index e40fd3e71..db4120f87 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -1674,4 +1674,4 @@ end @test "warnings" ∈ keys(r["Messages"]) @test length(r["Messages"]["errors"]) > 0 @test length(r["Messages"]["warnings"]) > 0 -end +end \ No newline at end of file From 765d729d343a766dd9d1910fc49a14325102403a Mon Sep 17 00:00:00 2001 From: adfarth Date: Fri, 21 Jul 2023 15:22:40 -0600 Subject: [PATCH 29/35] update unit test values --- test/runtests.jl | 2 +- test/test_with_cplex.jl | 2 +- test/test_with_xpress.jl | 34 +++++++++++++++++----------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 9a3ae7983..8ef4b05d9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -78,7 +78,7 @@ else # run HiGHS tests results = run_reopt(model, inputs) @test results["PV"]["size_kw"] ≈ 68.9323 atol=0.01 - @test results["Financial"]["lcc"] ≈ 432672.0 rtol=1e-5 # with levelization_factor hack the LCC is within 5e-5 of REopt API LCC + @test results["Financial"]["lcc"] ≈ 432681.26 rtol=1e-5 # with levelization_factor hack the LCC is within 5e-5 of REopt API LCC @test all(x == 0.0 for x in results["PV"]["electric_to_load_series_kw"][1:744]) end diff --git a/test/test_with_cplex.jl b/test/test_with_cplex.jl index c8d359e89..50ffbf813 100644 --- a/test/test_with_cplex.jl +++ b/test/test_with_cplex.jl @@ -98,7 +98,7 @@ end REoptInputs("./scenarios/monthly_rate.json"), ]; results = run_reopt(m, ps) - @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.2830591384e7 rtol=1e-5 + @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.2830872235e7 rtol=1e-5 end diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index db4120f87..7aaf7b9ad 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -429,7 +429,7 @@ end @test results["PV"]["size_kw"] ≈ 216.6667 atol=0.01 @test results["PV"]["lcoe_per_kwh"] ≈ 0.0468 atol = 0.001 - @test results["Financial"]["lcc"] ≈ 1.239151e7 rtol=1e-5 + @test results["Financial"]["lcc"] ≈ 1.239179e7 rtol=1e-5 @test results["Financial"]["lcc_bau"] ≈ 12766397 rtol=1e-5 @test results["ElectricStorage"]["size_kw"] ≈ 49.02 atol=0.1 @test results["ElectricStorage"]["size_kwh"] ≈ 83.3 atol=0.1 @@ -472,7 +472,7 @@ end m2 = Model(optimizer_with_attributes(Xpress.Optimizer, "OUTPUTLOG" => 0)) p = REoptInputs("./scenarios/generator.json") results = run_reopt([m1,m2], p) - @test results["Generator"]["size_kw"] ≈ 9.53 atol=0.01 + @test results["Generator"]["size_kw"] ≈ 9.55 atol=0.01 @test (sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 1:9) + sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 13:8760)) == 0 @test results["ElectricLoad"]["bau_critical_load_met"] == false @@ -513,8 +513,8 @@ end # Scenario with generator, PV, electric storage m = Model(optimizer_with_attributes(Xpress.Optimizer, "OUTPUTLOG" => 0)) results = run_reopt(m, "./scenarios/outages_gen_pv_stor.json") - @test results["Outages"]["expected_outage_cost"] ≈ 3.5478948132891157e6 atol=10 - @test results["Financial"]["lcc"] ≈ 8.64478971865e7 atol=100 + @test results["Outages"]["expected_outage_cost"] ≈ 3.54476923e6 atol=10 + @test results["Financial"]["lcc"] ≈ 8.6413594727e7 atol=100 # Scenario with generator, PV, wind, electric storage m = Model(optimizer_with_attributes(Xpress.Optimizer, "OUTPUTLOG" => 0)) @@ -522,7 +522,7 @@ end @test value(m[:binMGTechUsed]["Generator"]) ≈ 1 @test value(m[:binMGTechUsed]["PV"]) ≈ 1 @test value(m[:binMGTechUsed]["Wind"]) ≈ 1 - @test results["Outages"]["expected_outage_cost"] ≈ 430157.43 atol=1.0 + @test results["Outages"]["expected_outage_cost"] ≈ 446899.75 atol=1.0 @test results["Financial"]["lcc"] ≈ 6.71661825335e7 rtol=0.001 end @@ -533,7 +533,7 @@ end REoptInputs("./scenarios/monthly_rate.json"), ]; results = run_reopt(m, ps) - @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.2830591384e7 rtol=1e-5 + @test results[3]["Financial"]["lcc"] + results[10]["Financial"]["lcc"] ≈ 1.2830872235e7 rtol=1e-5 end @testset "MPC" begin @@ -707,9 +707,9 @@ end @test roof_east["size_kw"] ≈ 4 atol=0.1 @test ground_pv["lifecycle_om_cost_after_tax_bau"] ≈ 782.0 atol=0.1 @test roof_west["lifecycle_om_cost_after_tax_bau"] ≈ 782.0 atol=0.1 - @test ground_pv["annual_energy_produced_kwh_bau"] ≈ 8912.06 atol=0.1 + @test ground_pv["annual_energy_produced_kwh_bau"] ≈ 8933.09 atol=0.1 @test roof_west["annual_energy_produced_kwh_bau"] ≈ 7656.11 atol=0.1 - @test ground_pv["annual_energy_produced_kwh"] ≈ 26735.22 atol=0.1 + @test ground_pv["annual_energy_produced_kwh"] ≈ 26799.26 atol=0.1 @test roof_west["annual_energy_produced_kwh"] ≈ 10719.51 atol=0.1 @test roof_east["annual_energy_produced_kwh"] ≈ 6685.95 atol=0.1 end @@ -1313,9 +1313,9 @@ end @test (expected_npv - results["Financial"]["npv"])/expected_npv ≈ 0.0 atol=1e-2 @test results["Site"]["annual_renewable_electricity_kwh"] ≈ 76412.02 @test results["Site"]["renewable_electricity_fraction"] ≈ 0.8 - @test results["Site"]["renewable_electricity_fraction_bau"] ≈ 0.147698 atol=1e-4 + @test results["Site"]["renewable_electricity_fraction_bau"] ≈ 0.147576 atol=1e-4 @test results["Site"]["total_renewable_energy_fraction"] ≈ 0.8 - @test results["Site"]["total_renewable_energy_fraction_bau"] ≈ 0.147698 atol=1e-4 + @test results["Site"]["total_renewable_energy_fraction_bau"] ≈ 0.147576 atol=1e-4 @test results["Site"]["lifecycle_emissions_reduction_CO2_fraction"] ≈ 0.616639 atol=1e-4 @test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] ≈ 281.6 atol=1 @test results["Site"]["annual_emissions_tonnes_CO2"] ≈ 11.38 atol=1e-2 @@ -1323,15 +1323,15 @@ end @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2"] ≈ 7.04 @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 @test results["Financial"]["lifecycle_emissions_cost_climate"] ≈ 7767.6 atol=1 - @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 20447.72 atol=1e-1 + @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 20450.62 atol=1e-1 @test results["Site"]["lifecycle_emissions_tonnes_CO2"] ≈ 217.63 - @test results["Site"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 567.69 - @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2"] ≈ 140.75 + @test results["Site"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 567.77 + @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2"] ≈ 140.78 @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 @test results["ElectricUtility"]["annual_emissions_tonnes_CO2"] ≈ 4.34 @test results["ElectricUtility"]["annual_emissions_tonnes_CO2_bau"] ≈ 32.06 - @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2"] ≈ 76.88 - @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 567.69 + @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2"] ≈ 76.86 + @test results["ElectricUtility"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 567.77 elseif i == 2 #commented out values are results using same levelization factor as API @test results["PV"]["size_kw"] ≈ 106.13 atol=1 @@ -1351,13 +1351,13 @@ end @test results["Site"]["total_renewable_energy_fraction_bau"] ≈ 0.132118 atol=1e-3 # 0.1354 atol=1e-3 # CO2 emissions - totals ≈ from grid, from fuelburn, ER, $/tCO2 breakeven @test results["Site"]["lifecycle_emissions_reduction_CO2_fraction"] ≈ 0.8 atol=1e-3 # 0.8 - @test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] ≈ 374.242 atol=1e-1 + @test results["Financial"]["breakeven_cost_of_emissions_reduction_per_tonne_CO2"] ≈ 374.02125 atol=1e-1 @test results["Site"]["annual_emissions_tonnes_CO2"] ≈ 14.2 atol=1 @test results["Site"]["annual_emissions_tonnes_CO2_bau"] ≈ 70.99 atol=1 @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2"] ≈ 0.0 atol=1 # 0.0 @test results["Site"]["annual_emissions_from_fuelburn_tonnes_CO2_bau"] ≈ 0.0 atol=1 # 0.0 @test results["Financial"]["lifecycle_emissions_cost_climate"] ≈ 9110.21 atol=1 - @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 45551.06 atol=1 + @test results["Financial"]["lifecycle_emissions_cost_climate_bau"] ≈ 45546.55 atol=1 @test results["Site"]["lifecycle_emissions_tonnes_CO2"] ≈ 252.92 atol=1 @test results["Site"]["lifecycle_emissions_tonnes_CO2_bau"] ≈ 1264.62 atol=1 @test results["Site"]["lifecycle_emissions_from_fuelburn_tonnes_CO2"] ≈ 0.0 atol=1 # 0.0 From cd909b2402dcf5672ea70f84c2c737fa2ca04721 Mon Sep 17 00:00:00 2001 From: adfarth Date: Fri, 21 Jul 2023 15:45:49 -0600 Subject: [PATCH 30/35] Update runtests.jl --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 8ef4b05d9..d392974c6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -98,7 +98,7 @@ else # run HiGHS tests r = run_reopt(model, "./scenarios/pv_storage.json") @test r["PV"]["size_kw"] ≈ 216.6667 atol=0.01 - @test r["Financial"]["lcc"] ≈ 1.239151e7 rtol=1e-5 + @test r["Financial"]["lcc"] ≈ 1.2391786e7 rtol=1e-5 @test r["ElectricStorage"]["size_kw"] ≈ 49.0 atol=0.1 @test r["ElectricStorage"]["size_kwh"] ≈ 83.3 atol=0.1 end From 5be4a5f1b2a35b842e7bd1c038284c5bc86a690c Mon Sep 17 00:00:00 2001 From: adfarth Date: Fri, 21 Jul 2023 15:47:17 -0600 Subject: [PATCH 31/35] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 395944dd6..dfbdfe987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ Classify the change according to the following categories: ### Deprecated ### Removed +## Develop +### Changed +- Changed unit test expected values due to update to PVWatts v8, which slightly changed expected PV production factors. ## v0.32.4 ### Changed - Consolidated PVWatts API calls to 1 call (previously 3 separate calls existed). API call occurs in `src/core/utils.jl/call_pvwatts_api()`. This function is called for PV in `src/core/production_factor.jl/get_production_factor(PV)` and for GHP in `src/core/scenario.jl`. If GHP and PV are evaluated together, the GHP PVWatts call for ambient temperature is also used to assign the pv.production_factor_series in Scenario.jl so that the PVWatts API does not get called again downstream in `get_production_factor(PV)`. From 63ce90add63e3b168cf22fe1741ed5deba747cc8 Mon Sep 17 00:00:00 2001 From: adfarth Date: Fri, 21 Jul 2023 16:10:28 -0600 Subject: [PATCH 32/35] Update runtests.jl --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index d392974c6..ff2829d2c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -108,7 +108,7 @@ else # run HiGHS tests "output_flag" => false, "log_to_console" => false) ) results = run_reopt(model, "./scenarios/generator.json") - @test results["Generator"]["size_kw"] ≈ 9.53 atol=0.01 + @test results["Generator"]["size_kw"] ≈ 9.55 atol=0.01 @test (sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 1:9) + sum(results["Generator"]["electric_to_load_series_kw"][i] for i in 13:8760)) == 0 p = REoptInputs("./scenarios/generator.json") From 9c232e086d4899ba0276fae4ebb8674cb49ba554 Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:12:09 -0600 Subject: [PATCH 33/35] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b274611f..1d3458933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Classify the change according to the following categories: ## Develop ### Changed - Changed unit test expected values due to update to PVWatts v8, which slightly changed expected PV production factors. +- Changed **fuel_avail_gal** default to 1e9 for on-grid scenarios (same as off-grid) ### Fixed - Corrected `Generator` **installed_cost_per_kw** from 500 to 650 if **only_runs_during_grid_outage** is _true_ or 800 if _false_ From b2c675eef0f0d460b6108995722a969bb3f5ee54 Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:44:50 -0600 Subject: [PATCH 34/35] Update CHANGELOG.md --- CHANGELOG.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d3458933..ebcda882c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,22 +23,18 @@ Classify the change according to the following categories: ### Deprecated ### Removed -## Develop -### Changed -- Changed unit test expected values due to update to PVWatts v8, which slightly changed expected PV production factors. -- Changed **fuel_avail_gal** default to 1e9 for on-grid scenarios (same as off-grid) -### Fixed -- Corrected `Generator` **installed_cost_per_kw** from 500 to 650 if **only_runs_during_grid_outage** is _true_ or 800 if _false_ - ## v0.32.4 ### Changed - Consolidated PVWatts API calls to 1 call (previously 3 separate calls existed). API call occurs in `src/core/utils.jl/call_pvwatts_api()`. This function is called for PV in `src/core/production_factor.jl/get_production_factor(PV)` and for GHP in `src/core/scenario.jl`. If GHP and PV are evaluated together, the GHP PVWatts call for ambient temperature is also used to assign the pv.production_factor_series in Scenario.jl so that the PVWatts API does not get called again downstream in `get_production_factor(PV)`. - In `src/core/utils.jl/call_pvwatts_api()`, updated NSRDB bounds used in PVWatts query (now includes southern New Zealand) - Updated PV Watts version from v6 to v8. PVWatts V8 updates the weather data to 2020 TMY data from the NREL NSRDB for locations covered by the database. (The NSRDB weather data used in PVWatts V6 is from around 2015.) See other differences at https://developer.nrel.gov/docs/solar/pvwatts/. - Made PV struct mutable: This allows for assigning pv.production_factor_series when calling PVWatts for GHP, to avoid a extra PVWatts calls later. +- Changed unit test expected values due to update to PVWatts v8, which slightly changed expected PV production factors. +- Changed **fuel_avail_gal** default to 1e9 for on-grid scenarios (same as off-grid) ### Fixed - Issue with using a leap year with a URDB rate - the URDB rate was creating energy_rate of length 8784 instead of intended 8760 -- Don't double add adjustments to urdb rates with non-standard units +- Don't double add adjustments to urdb rates with non-standard units +- Corrected `Generator` **installed_cost_per_kw** from 500 to 650 if **only_runs_during_grid_outage** is _true_ or 800 if _false_ ## v0.32.3 ### Fixed From 83c0aecb9eddf0b7c2ed26e41ea6d8f58be1b4aa Mon Sep 17 00:00:00 2001 From: hdunham <70401017+hdunham@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:51:04 -0600 Subject: [PATCH 35/35] readability --- src/core/urdb.jl | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/core/urdb.jl b/src/core/urdb.jl index 9f3bae6cd..4c7c2a724 100644 --- a/src/core/urdb.jl +++ b/src/core/urdb.jl @@ -293,14 +293,10 @@ function parse_urdb_energy_costs(d::Dict, year::Int; time_steps_per_hour=1, bigM else tier_use = tier end - if non_kwh_units - rate = rate_average - total_rate = rate - else - rate = get(d["energyratestructure"][period][tier_use], "rate", 0) - total_rate = rate + get(d["energyratestructure"][period][tier_use], "adj", 0) - end - + total_rate = non_kwh_units ? + rate_average : + (get(d["energyratestructure"][period][tier_use], "rate", 0) + + get(d["energyratestructure"][period][tier_use], "adj", 0)) sell = get(d["energyratestructure"][period][tier_use], "sell", 0) for step in range(1, stop=time_steps_per_hour) # repeat hourly rates intrahour