Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow presized ghp/ghx #466

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Classify the change according to the following categories:

## v0.48.2
### Added
- Add new optional parameter **max_ton** to GHP module to allow user to size GHP smaller than peak load
- Battery residual value if choosing replacement strategy for degradation
- Add new **ElectricStorage** parameters **max_duration_hours** and **min_duration_hours** to bound the energy duration of battery storage
### Changed
Expand Down
14 changes: 9 additions & 5 deletions src/core/ghp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ struct with outer constructor:
installed_cost_ghx_per_ft::Float64 = 14.0
installed_cost_building_hydronic_loop_per_sqft = 1.70
om_cost_per_sqft_year::Float64 = -0.51
building_sqft::Float64 # Required input
building_sqft::Float64 # Required input
space_heating_efficiency_thermal_factor::Float64 = NaN # Default depends on building and location
cooling_efficiency_thermal_factor::Float64 = NaN # Default depends on building and location
cooling_efficiency_thermal_factor::Float64 = NaN # Default depends on building and location
ghpghx_response::Dict = Dict()
can_serve_dhw::Bool = false
max_ton::Real # Maxium heat pump capacity size. Default at a big number
load_served_by_ghp::String # "scaled" or "nonpeak"

macrs_option_years::Int = 5
macrs_bonus_fraction::Float64 = 0.6
Expand Down Expand Up @@ -80,6 +82,8 @@ Base.@kwdef mutable struct GHP <: AbstractGHP
can_serve_space_heating::Bool = true
can_serve_process_heat::Bool = false
can_supply_steam_turbine::Bool = false
max_ton::Real = BIG_NUMBER
load_served_by_ghp::String = "nonpeak"

aux_heater_type::String = "electric"
is_ghx_hybrid::Bool = false
Expand Down Expand Up @@ -157,7 +161,7 @@ function GHP(response::Dict, d::Dict)
end
# incentives = IncentivesNoProdBased(**d_mod)

setup_installed_cost_curve!(ghp, response)
setup_installed_cost_curve!(d, ghp, response)

setup_om_cost!(ghp)

Expand All @@ -171,10 +175,10 @@ function GHP(response::Dict, d::Dict)
end

"""
setup_installed_cost_curve!(response::Dict, ghp::GHP)
setup_installed_cost_curve!(d::Dict, response::Dict, ghp::GHP)

"""
function setup_installed_cost_curve!(ghp::GHP, response::Dict)
function setup_installed_cost_curve!(d::Dict, ghp::GHP, response::Dict)
big_number = 1.0e10
# GHX and GHP sizing metrics for cost calculations
total_ghx_ft = response["outputs"]["number_of_boreholes"] * response["outputs"]["length_boreholes_ft"]
Expand Down
35 changes: 31 additions & 4 deletions src/core/scenario.jl
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ function Scenario(d::Dict; flex_hvac_from_json=false)
space_heating_thermal_load_reduction_with_ghp_kw = zeros(8760 * settings.time_steps_per_hour)
cooling_thermal_load_reduction_with_ghp_kw = zeros(8760 * settings.time_steps_per_hour)
eval_ghp = false
get_ghpghx_from_input = false
get_ghpghx_from_input = false
if haskey(d, "GHP") && haskey(d["GHP"],"building_sqft")
eval_ghp = true
if haskey(d["GHP"], "ghpghx_responses") && !isempty(d["GHP"]["ghpghx_responses"])
Expand Down Expand Up @@ -618,9 +618,38 @@ function Scenario(d::Dict; flex_hvac_from_json=false)
# Call GhpGhx.jl to size GHP and GHX
@info "Starting GhpGhx.jl"
# Call GhpGhx.jl to size GHP and GHX
# If user provides udersized GHP, calculate load to send to GhpGhx.jl, and load to send to REopt for backup
heating_load_ton = ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"]*1000000/12000
thermal_load_ton = heating_load_ton
if get(ghpghx_inputs, "cooling_thermal_load_ton", []) in [nothing, []]
cooling_load_ton = ghpghx_inputs["cooling_thermal_load_ton"]
thermal_load_ton = heating_load_ton + cooling_load_ton
end
peak_thermal_load = maximum(thermal_load_ton)
if haskey(d["GHP"],"max_ton") && peak_thermal_load > d["GHP"]["max_ton"]
@info "User entered undersized GHP. Calculating load that can be served by user specified undersized GHP"
# When user specifies undersized GHP, calculate the load to be served by GHP and send the rest to REopt
# If user choose to scale down total load (load_served_by_ghp="scaled"), calculate the ratio of the udersized GHP size and peak load
if d["GHP"]["load_served_by_ghp"] == "scaled"
@info "GHP served scaled down of total thermal load"
peak_ratio = d["GHP"]["max_ton"]/peak_thermal_load
# Scale down the total load profile by the peak ratio and use this scaled down load to rerun GhpGhx.jl
ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"] = ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"]*peak_ratio
if get(ghpghx_inputs, "cooling_thermal_load_ton", []) in [nothing, []]
ghpghx_inputs["cooling_thermal_load_ton"] = cooling_load_ton*peak_ratio
end
elseif d["GHP"]["load_served_by_ghp"] == "nonpeak"
@info "GHP serves all thermal load below thermal peak load"
heating_load_mmbtu = ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"]
#ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"][ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"] .>= d["GHP"]["max_ton"]*12000/1000000] .= d["GHP"]["max_ton"]*12000/1000000
heating_load_mmbtu[heating_load_mmbtu .>=d["GHP"]["max_ton"]*12000/1000000] .= d["GHP"]["max_ton"]*12000/1000000
ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"] = heating_load_mmbtu
end
end
results, inputs_params = GhpGhx.ghp_model(ghpghx_inputs)
# Create a dictionary of the results data needed for REopt
ghpghx_results = GhpGhx.get_results_for_reopt(results, inputs_params)
# Return results from GhpGhx.jl without load scaling if user does not provide GHP size or if user entered GHP size is greater than GHP size output
@info "GhpGhx.jl model solved" #with status $(results["status"])."
catch e
@info e
Expand All @@ -638,9 +667,7 @@ function Scenario(d::Dict; flex_hvac_from_json=false)
end
append!(ghp_option_list, [GHP(ghpghx_response, ghp_inputs_removed_ghpghx_params)])
# Print out ghpghx_response for loading into a future run without running GhpGhx.jl again
#open("scenarios/ghpghx_response.json","w") do f
# JSON.print(f, ghpghx_response)
#end
# open("scenarios/ghpghx_response.json","w") do f
end
# If ghpghx_responses is included in inputs, do NOT run GhpGhx.jl model and use already-run ghpghx result as input to REopt
elseif eval_ghp && get_ghpghx_from_input
Expand Down
5 changes: 5 additions & 0 deletions src/results/ghp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ function add_ghp_results(m::JuMP.AbstractModel, p::REoptInputs, d::Dict; _n="")
# r["size_heat_pump_ton"] = 0.0
# r["size_wwhp_heating_pump_ton"] = 0.0
# r["size_wwhp_cooling_pump_ton"] = 0.0

# Set sizing factor = 1 if user inputs their own GHP size
if haskey(d, "GHP") && haskey(d["GHP"],"max_ton")
p.s.ghp_option_list[ghp_option_chosen].heatpump_capacity_sizing_factor_on_peak_load = 1.0
end
if ghp_option_chosen >= 1
r["ghpghx_chosen_outputs"] = p.s.ghp_option_list[ghp_option_chosen].ghpghx_response["outputs"]

Expand Down
Loading