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 12 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 @@ -37,6 +37,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
13 changes: 10 additions & 3 deletions src/core/ghp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct with outer constructor:
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

macrs_option_years::Int = 5
macrs_bonus_fraction::Float64 = 0.6
Expand Down Expand Up @@ -80,6 +81,7 @@ 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

aux_heater_type::String = "electric"
is_ghx_hybrid::Bool = false
Expand Down Expand Up @@ -157,7 +159,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 +173,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 Expand Up @@ -213,6 +215,11 @@ function setup_installed_cost_curve!(ghp::GHP, response::Dict)
# the initial slope is based on the heat pump size (e.g. $/ton) of the cost curve for
# building a rebate-based cost curve if there are less-than big_number maximum incentives
ghp.tech_sizes_for_cost_curve = [0.0, big_number]

# Set sizing factor = 1 if user inputs their own GHP size
if haskey(d, "GHP") && haskey(d["GHP"],"max_ton")
ghp.heatpump_capacity_sizing_factor_on_peak_load = 1.0
end

if ghp.heat_pump_configuration == "WSHP"
# Use this with the cost curve to determine absolute cost
Expand Down
34 changes: 30 additions & 4 deletions src/core/scenario.jl
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,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 @@ -615,10 +615,35 @@ 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 ratio of the udersized GHP size and peak 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
#remaining_heating_thermal_load_mmbtu_per_hr = ghpghx_inputs["heating_thermal_load_mmbtu_per_hr"]*(1-peak_ratio)
if get(ghpghx_inputs, "cooling_thermal_load_ton", []) in [nothing, []]
ghpghx_inputs["cooling_thermal_load_ton"] = cooling_load_ton*peak_ratio
#remaining_cooling_thermal_load_ton = cooling_load_ton*(1-peak_ratio)
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"])."
# Existing boiler and/or chiller are added to serve remaining thermal load not served by the undersized GHP
#if get(ghpghx_inputs, "heating_thermal_load_mmbtu_per_hr", []) in [nothing, []]
# existing_boiler_inputs = Dict{Symbol, Any}()
#end
catch e
@info e
throw(@error("The GhpGhx package was not added (add https://github.com/NREL/GhpGhx.jl) or
Expand All @@ -635,9 +660,10 @@ 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
open("/Users/apham/Documents/Projects/REopt_Projects/FY25/GHP Development/Test_Model_Presized_GHP/data/ghpghx_response.json","w") do f
JSON.print(f, ghpghx_response)
end
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
Loading