From e9497d913d7ca3b74827904b8b0f760c117bd5a6 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 76ba2e6f93bfc0d8ba754681953edf69fc60ddbc 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 f1350ed1c45756af24650e937629cbf29da9ca52 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 6cda39322ae0049993c4ae15e470483408ec97c8 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 d09d6a5e747e0c11f790ee466315af9142923867 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 5ae8af12760110a6b19284d68515ebdac4d87211 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 479cb4a0d885ce9da4f68bd90d1d64d020849473 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 c5e6a372f77c018547cfcf12143e362ca7121bc9 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 f73d97ebd2957457714505094de852906702c67e 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 3ba16e225586451bdf8934016b608d48899f7337 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 86c1814e8ee718ee35ca65e314137282a322da17 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 6fffde44604dbefb2f3ad8277f7e0cf6a0ef7d53 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 59356c69732120991cbbac9d4f274dc0ea0cf440 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 d5089977b43c7b5aa35caae570bcb520eae80952 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 04569dbb8391073f4abbc6e757e16a7002bd0f3b 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 9537f7f6e90ededef750b2af42717d5b71e80fa5 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 98bc8b4172923484a0b5c48c521650ed011b9ba3 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 303865b2c549519c126fd8938b15368ffa77e298 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 8b35e5e349c59b3d06eb84c04949f4a8c26f70c5 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 42f637d32e347d3b62e47b1878193391b0a52e1a 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 c5db3bc3aace22a50504216673fe694e5913acad 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 b830482bca47c747f77e8b9223dac4cd8f8c5238 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 753c1d590832e785bfc285d677661405d9a9b93f 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 f145b29731a25c6119a49d60cde07b14b1b1e67f 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 087cea21011a023fb17c6e75740cad4864bed77a 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 9e218e93bd41300aa7e7318a502e9bb643c17dc3 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 ca97bb08a3330ea0644acc0eec5ef0fd690cb46e 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 fea0d7d90f22dabd93a5f436b274ac52842ae7a5 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 dfcf5c846d0e956aaaca829eda2a8ddce31c1ac0 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 3ee3efb0f5f1a8fa4ab1f72374f8b83f7c27780c 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 935615c9538b462eae7368234a3a72cae89519ed 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 490af1eb50ebda2da82c215cec9a9ffbe2d6a99b 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 94c3a0ff51e15cddeb0308f3e93f7cea2daa9a83 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 b1376bf1223d66dd4c1850b9c9b7a05e205b520c 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 38c4227ee3efe9ed3fef24e46a4c044ad29830c4 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