From 48cefd673d2a9252d0efc8b7c3b7dafd471de309 Mon Sep 17 00:00:00 2001 From: Zolan Date: Wed, 8 May 2024 14:04:50 -0600 Subject: [PATCH 1/8] include GHP in dvProductionToStorage and dvHeatToStorage, fix to zero --- src/constraints/storage_constraints.jl | 24 ++++++++++++++++++++++++ src/core/reopt.jl | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/constraints/storage_constraints.jl b/src/constraints/storage_constraints.jl index 12af6c5ef..fcd20b8d0 100644 --- a/src/constraints/storage_constraints.jl +++ b/src/constraints/storage_constraints.jl @@ -181,6 +181,19 @@ function add_hot_thermal_storage_dispatch_constraints(m, p, b; _n="") sum(m[Symbol("dvHeatFromStorage"*_n)][b,q,ts] for q in p.heating_loads) ) + #Do not allow GHP to charge storage + if !isempty(p.techs.ghp) + for b in p.s.storage.types.hot + for t in p.techs.ghp + for q in p.heating_loads + for ts in p.time_steps + fix(m[Symbol("dvHeatToStorage"*_n)][b,t,q,ts], 0.0, force=true) + end + end + end + end + end + end function add_cold_thermal_storage_dispatch_constraints(m, p, b; _n="") @@ -207,6 +220,17 @@ function add_cold_thermal_storage_dispatch_constraints(m, p, b; _n="") m[Symbol("dvStoragePower"*_n)][b] >= m[Symbol("dvDischargeFromStorage"*_n)][b,ts] + sum(m[Symbol("dvProductionToStorage"*_n)][b,t,ts] for t in p.techs.cooling) ) + + #Do not allow GHP to charge storage + if !isempty(p.techs.ghp) + for b in p.s.storage.types.cold + for t in p.techs.ghp + for ts in p.time_steps + fix(m[Symbol("dvProductionToStorage"*_n)][b,t,ts], 0.0, force=true) + end + end + end + end end function add_storage_sum_constraints(m, p; _n="") diff --git a/src/core/reopt.jl b/src/core/reopt.jl index 7baefaed3..4963e462d 100644 --- a/src/core/reopt.jl +++ b/src/core/reopt.jl @@ -584,7 +584,7 @@ function add_variables!(m::JuMP.AbstractModel, p::REoptInputs) dvGridPurchase[p.time_steps, 1:p.s.electric_tariff.n_energy_tiers] >= 0 # Power from grid dispatched to meet electrical load [kW] dvRatedProduction[p.techs.all, p.time_steps] >= 0 # Rated production of technology t [kW] dvCurtail[p.techs.all, p.time_steps] >= 0 # [kW] - dvProductionToStorage[p.s.storage.types.all, p.techs.all, p.time_steps] >= 0 # Power from technology t used to charge storage system b [kW] + dvProductionToStorage[p.s.storage.types.all, union(p.techs.ghp,p.techs.all), p.time_steps] >= 0 # Power from technology t used to charge storage system b [kW] dvDischargeFromStorage[p.s.storage.types.all, p.time_steps] >= 0 # Power discharged from storage system b [kW] dvGridToStorage[p.s.storage.types.elec, p.time_steps] >= 0 # Electrical power delivered to storage by the grid [kW] dvStoredEnergy[p.s.storage.types.all, 0:p.time_steps[end]] >= 0 # State of charge of storage system b From b7486e4f501f052f613c417e4ac32c2cbcd805af Mon Sep 17 00:00:00 2001 From: Zolan Date: Wed, 8 May 2024 20:54:14 -0600 Subject: [PATCH 2/8] add storage techs to GHP test set --- test/scenarios/ghp_inputs.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/scenarios/ghp_inputs.json b/test/scenarios/ghp_inputs.json index 46dfdd472..43b816527 100644 --- a/test/scenarios/ghp_inputs.json +++ b/test/scenarios/ghp_inputs.json @@ -55,5 +55,15 @@ "ElectricStorage": { "max_kw": 0.0, "max_kwh": 0.0 + }, + "ColdThermalStorage": { + "min_gal": 10, + "max_gal": 10, + "thermal_decay_rate_fraction": 0.0 + }, + "HotThermalStorage": { + "min_gal": 10, + "max_gal": 10, + "thermal_decay_rate_fraction": 0.0 } } \ No newline at end of file From d567502a115e3f29be1733c1e0ce0f456dbe0b56 Mon Sep 17 00:00:00 2001 From: Alex Zolan Date: Thu, 9 May 2024 08:41:57 -0600 Subject: [PATCH 3/8] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2ccab445..61bfef7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,12 @@ Classify the change according to the following categories: ### Deprecated ### Removed +## Develop 2024-05-09 +### Changed +- Updated the GHP testset .json `./test/scenarios/ghp_inputs.json` to include a nominal HotThermalStorage and ColdThermalStorage system. +### Fixed +- Fixed a bug in which the model fails to build when both GHP and either Hot or Cold Thermal Storage are present. + ## v. 0.46.0 ### Added - In `src/core/absorption_chiller.jl` struct, added field **heating_load_input** to the AbsorptionChiller struct From 78e42b0d82aa57c610c2aaeea1f791035ff22bfa Mon Sep 17 00:00:00 2001 From: Zolan Date: Thu, 9 May 2024 12:38:04 -0600 Subject: [PATCH 4/8] docs update for steam turbine --- src/core/steam_turbine.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/steam_turbine.jl b/src/core/steam_turbine.jl index fc7b951de..ca114888f 100644 --- a/src/core/steam_turbine.jl +++ b/src/core/steam_turbine.jl @@ -25,6 +25,9 @@ can_wholesale::Bool = false can_export_beyond_nem_limit::Bool = false can_curtail::Bool = false + can_serve_dhw::Bool = true + can_serve_space_heating::Bool = true + can_serve_process_heat::Bool = true macrs_option_years::Int = 0 macrs_bonus_fraction::Float64 = 0.0 From 2228b394f823e8c8ce2f76c3ef52477054bac302 Mon Sep 17 00:00:00 2001 From: Zolan Date: Thu, 9 May 2024 12:44:09 -0600 Subject: [PATCH 5/8] simplify nested sets --- src/constraints/storage_constraints.jl | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/constraints/storage_constraints.jl b/src/constraints/storage_constraints.jl index fcd20b8d0..d5daa9801 100644 --- a/src/constraints/storage_constraints.jl +++ b/src/constraints/storage_constraints.jl @@ -183,14 +183,8 @@ function add_hot_thermal_storage_dispatch_constraints(m, p, b; _n="") #Do not allow GHP to charge storage if !isempty(p.techs.ghp) - for b in p.s.storage.types.hot - for t in p.techs.ghp - for q in p.heating_loads - for ts in p.time_steps - fix(m[Symbol("dvHeatToStorage"*_n)][b,t,q,ts], 0.0, force=true) - end - end - end + for b in p.s.storage.types.hot, t in p.techs.ghp, q in p.heating_loads, ts in p.time_steps + fix(m[Symbol("dvHeatToStorage"*_n)][b,t,q,ts], 0.0, force=true) end end @@ -223,12 +217,8 @@ function add_cold_thermal_storage_dispatch_constraints(m, p, b; _n="") #Do not allow GHP to charge storage if !isempty(p.techs.ghp) - for b in p.s.storage.types.cold - for t in p.techs.ghp - for ts in p.time_steps + for b in p.s.storage.types.cold, t in p.techs.ghp, ts in p.time_steps fix(m[Symbol("dvProductionToStorage"*_n)][b,t,ts], 0.0, force=true) - end - end end end end From 428379489e9a007cf7e4c32c593c231a2135cfce Mon Sep 17 00:00:00 2001 From: Zolan Date: Thu, 9 May 2024 12:56:50 -0600 Subject: [PATCH 6/8] fix dvHeatToStorage sets --- src/constraints/storage_constraints.jl | 2 +- src/core/reopt.jl | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/constraints/storage_constraints.jl b/src/constraints/storage_constraints.jl index d5daa9801..782076dd4 100644 --- a/src/constraints/storage_constraints.jl +++ b/src/constraints/storage_constraints.jl @@ -146,7 +146,7 @@ function add_hot_thermal_storage_dispatch_constraints(m, p, b; _n="") if !isempty(p.techs.chp) if !isempty(p.techs.steam_turbine) && p.s.chp.can_supply_steam_turbine @constraint(m, CHPTechProductionFlowCon[b in p.s.storage.types.hot, t in p.techs.chp, q in p.heating_loads, ts in p.time_steps], - m[Symbol("dvHeatToStorage"*_n)][b,tq,ts] + m[Symbol("dvProductionToWaste"*_n)][t,q,ts] + m[Symbol("dvThermalToSteamTurbine"*_n)][t,q,ts] <= + m[Symbol("dvHeatToStorage"*_n)][b,t,q,ts] + m[Symbol("dvProductionToWaste"*_n)][t,q,ts] + m[Symbol("dvThermalToSteamTurbine"*_n)][t,q,ts] <= m[Symbol("dvHeatingProduction"*_n)][t,q,ts] ) else diff --git a/src/core/reopt.jl b/src/core/reopt.jl index 4963e462d..e3a821a46 100644 --- a/src/core/reopt.jl +++ b/src/core/reopt.jl @@ -216,19 +216,19 @@ function build_reopt!(m::JuMP.AbstractModel, p::REoptInputs) elseif b in p.s.storage.types.hot @constraint(m, [q in q in setdiff(p.heating_loads, p.heating_loads_served_by_tes[b]), ts in p.time_steps], m[:dvHeatFromStorage][b,q,ts] == 0) if "DomesticHotWater" in p.heating_loads_served_by_tes[b] - @constraint(m, [t in setdiff(p.heating_techs, p.techs_can_serve_dhw), ts in p.time_steps], m[:dvHeatToStorage][b,"DomesticHotWater",ts] == 0) + @constraint(m, [t in setdiff(p.heating_techs, p.techs_can_serve_dhw), ts in p.time_steps], m[:dvHeatToStorage][b,t,"DomesticHotWater",ts] == 0) else - @constraint(m, [t in p.heating_techs, ts in p.time_steps], m[:dvHeatToStorage][b,"DomesticHotWater",ts] == 0) + @constraint(m, [t in p.heating_techs, ts in p.time_steps], m[:dvHeatToStorage][b,t,"DomesticHotWater",ts] == 0) end if "SpaceHeating" in p.heating_loads_served_by_tes[b] - @constraint(m, [t in setdiff(p.heating_techs, p.techs_can_serve_space_heating), ts in p.time_steps], m[:dvHeatToStorage][b,"SpaceHeating",ts] == 0) + @constraint(m, [t in setdiff(p.heating_techs, p.techs_can_serve_space_heating), ts in p.time_steps], m[:dvHeatToStorage][b,t,"SpaceHeating",ts] == 0) else - @constraint(m, [t in p.heating_techs, ts in p.time_steps], m[:dvHeatToStorage][b,"SpaceHeating",ts] == 0) + @constraint(m, [t in p.heating_techs, ts in p.time_steps], m[:dvHeatToStorage][b,t,"SpaceHeating",ts] == 0) end if "ProcessHeat" in p.heating_loads_served_by_tes[b] - @constraint(m, [t in setdiff(p.heating_techs, p.techs_can_serve_process_heat), ts in p.time_steps], m[:dvHeatToStorage][b,"ProcessHeat",ts] == 0) + @constraint(m, [t in setdiff(p.heating_techs, p.techs_can_serve_process_heat), ts in p.time_steps], m[:dvHeatToStorage][b,t,"ProcessHeat",ts] == 0) else - @constraint(m, [t in p.heating_techs, ts in p.time_steps], m[:dvHeatToStorage][b,"ProcessHeat",ts] == 0) + @constraint(m, [t in p.heating_techs, ts in p.time_steps], m[:dvHeatToStorage][b,t,"ProcessHeat",ts] == 0) end end else From 73b35715abb1406c87d29523ef7f0fba3cc40f66 Mon Sep 17 00:00:00 2001 From: Alex Zolan Date: Thu, 9 May 2024 16:06:49 -0600 Subject: [PATCH 7/8] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index cdf6edfce..ae911db36 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.46.0" +version = "0.46.1" [deps] ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3" From ab53b8aa75f5a542cc86a21c33c500af1d8d0f54 Mon Sep 17 00:00:00 2001 From: Alex Zolan Date: Thu, 9 May 2024 16:07:51 -0600 Subject: [PATCH 8/8] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61bfef7b5..f5e43a24e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,13 +23,13 @@ Classify the change according to the following categories: ### Deprecated ### Removed -## Develop 2024-05-09 +## v0.46.1 ### Changed - Updated the GHP testset .json `./test/scenarios/ghp_inputs.json` to include a nominal HotThermalStorage and ColdThermalStorage system. ### Fixed - Fixed a bug in which the model fails to build when both GHP and either Hot or Cold Thermal Storage are present. -## v. 0.46.0 +## v.0.46.0 ### Added - In `src/core/absorption_chiller.jl` struct, added field **heating_load_input** to the AbsorptionChiller struct - Added new variables **dvHeatToStorage** and **dvHeatFromStorage** which are indexed on `p.heating_loads` and added reconciliation constraints so that **dvProductionToStorage** and **dvDischargeFromStorage** maintain their relationship to state of charge for Hot thermal energy storage.