@@ -480,7 +480,7 @@ function Scenario(d::Dict; flex_hvac_from_json=false)
480480 space_heating_thermal_load_reduction_with_ghp_kw = zeros (8760 * settings. time_steps_per_hour)
481481 cooling_thermal_load_reduction_with_ghp_kw = zeros (8760 * settings. time_steps_per_hour)
482482 eval_ghp = false
483- get_ghpghx_from_input = false
483+ get_ghpghx_from_input = false
484484 if haskey (d, " GHP" ) && haskey (d[" GHP" ]," building_sqft" )
485485 eval_ghp = true
486486 if haskey (d[" GHP" ], " ghpghx_responses" ) && ! isempty (d[" GHP" ][" ghpghx_responses" ])
@@ -620,13 +620,101 @@ function Scenario(d::Dict; flex_hvac_from_json=false)
620620 end
621621
622622 ghpghx_results = Dict ()
623+
623624 try
624625 # Call GhpGhx.jl to size GHP and GHX
625626 @info " Starting GhpGhx.jl"
626627 # Call GhpGhx.jl to size GHP and GHX
628+ # If user provides undersized GHP, calculate load to send to GhpGhx.jl, and load to send to REopt for backup
629+ thermal_load_ton = ghpghx_inputs[" heating_thermal_load_mmbtu_per_hr" ] .* 1 / TONNE_PER_MMBTU_HOUR
630+ if haskey (ghpghx_inputs," cooling_thermal_load_ton" )
631+ cooling_load_ton = ghpghx_inputs[" cooling_thermal_load_ton" ]
632+ thermal_load_ton .+ = cooling_load_ton
633+ end
634+ peak_thermal_load_ton = maximum (thermal_load_ton)
635+ if haskey (d[" GHP" ]," max_ton" ) && peak_thermal_load_ton > d[" GHP" ][" max_ton" ]
636+ @info " User entered undersized GHP. Calculating load that can be served by user specified undersized GHP"
637+ # When user specifies undersized GHP, calculate the load to be served by GHP and send the rest to REopt
638+ if ! haskey (d[" GHP" ], " load_served_by_ghp" )
639+ d[" GHP" ][" load_served_by_ghp" ] = " nonpeak"
640+ end
641+ # If user choose to scale down total load (load_served_by_ghp="scaled"), calculate the ratio of the udersized GHP size and peak load
642+ if d[" GHP" ][" load_served_by_ghp" ] == " scaled"
643+ @info " GHP served scaled down of total thermal load"
644+ peak_ratio = d[" GHP" ][" max_ton" ] / peak_thermal_load_ton
645+ # Scale the total load profile down by the peak_ratio and use this scaled down load to rerun GhpGhx.jl
646+ heating_load_mmbtu = ghpghx_inputs[" heating_thermal_load_mmbtu_per_hr" ]
647+ heating_load_mmbtu = heating_load_mmbtu .* peak_ratio
648+ ghpghx_inputs[" heating_thermal_load_mmbtu_per_hr" ] = heating_load_mmbtu
649+ if haskey (ghpghx_inputs," cooling_thermal_load_ton" )
650+ ghpghx_inputs[" cooling_thermal_load_ton" ] = cooling_load_ton .* peak_ratio
651+ end
652+ elseif d[" GHP" ][" load_served_by_ghp" ] == " nonpeak"
653+ @info " GHP serves all thermal load below peak"
654+ heating_load_mmbtu = ghpghx_inputs[" heating_thermal_load_mmbtu_per_hr" ]
655+ # if cooling load is included, cut down total thermal load and send as much heating load to GhpGhx.jl as possible
656+ if haskey (ghpghx_inputs," cooling_thermal_load_ton" )
657+ # If total thermal load (heating + cooling) is more than user-defined GHP size,
658+ # first reduce heating load as much as possible while keeping cooling load the same
659+ if peak_thermal_load_ton > d[" GHP" ][" max_ton" ]
660+ thermal_load_ton[thermal_load_ton .>= d[" GHP" ][" max_ton" ]] .= d[" GHP" ][" max_ton" ]
661+ heating_load_ton = thermal_load_ton .- cooling_load_ton
662+ # Make sure that the reduced heating load is not negative
663+ heating_load_ton[heating_load_ton .< 0 ] .= 0
664+ # If the updated peak thermal load is still more than user-defined GHP size,
665+ # reduce cooling load as well
666+ updated_thermal_load_ton = heating_load_ton .+ cooling_load_ton
667+ updated_peak_thermal_load_ton = maximum (updated_thermal_load_ton)
668+ if updated_peak_thermal_load_ton > d[" GHP" ][" max_ton" ]
669+ updated_thermal_load_ton[updated_thermal_load_ton .>= d[" GHP" ][" max_ton" ]] .= d[" GHP" ][" max_ton" ]
670+ cooling_load_ton = updated_thermal_load_ton .- heating_load_ton
671+ ghpghx_inputs[" cooling_thermal_load_ton" ] = cooling_load_ton
672+ end
673+ heating_load_mmbtu = heating_load_ton .* TONNE_PER_MMBTU_HOUR
674+ ghpghx_inputs[" heating_thermal_load_mmbtu_per_hr" ] = heating_load_mmbtu
675+ end
676+ # if cooling load is not included, cut down heating load only and send to GhpGhx.jl
677+ else
678+ heating_load_mmbtu[heating_load_mmbtu .>= d[" GHP" ][" max_ton" ] * TONNE_PER_MMBTU_HOUR] .= d[" GHP" ][" max_ton" ] * TONNE_PER_MMBTU_HOUR
679+ ghpghx_inputs[" heating_thermal_load_mmbtu_per_hr" ] = heating_load_mmbtu
680+ end
681+ end
682+ end
627683 results, inputs_params = GhpGhx. ghp_model (ghpghx_inputs)
684+ # If max_number_of_boreholes is specified, check if number of boreholes sized by GhpGhx.jl greater than user-specified max_number_of_boreholes,
685+ # and if max_number_of_boreholes is less, reduce thermal load served by GHP until max_number_of_boreholes = number of boreholses sized by GhpGhx.jl
686+ if haskey (d[" GHP" ]," max_number_of_boreholes" )
687+ optimal_number_of_boreholes = GhpGhx. get_results_for_reopt (results, inputs_params)[" number_of_boreholes" ]
688+ if optimal_number_of_boreholes > d[" GHP" ][" max_number_of_boreholes" ]
689+ @info " Max number of boreholes specified is less than number of boreholes sized in GhpGhx.jl, reducing thermal load served by GHP further"
690+ max_iter = 10
691+ for iter = 1 : max_iter
692+ borehole_ratio = d[" GHP" ][" max_number_of_boreholes" ] / optimal_number_of_boreholes
693+ heating_load_mmbtu .*= borehole_ratio
694+ if haskey (ghpghx_inputs," cooling_thermal_load_ton" )
695+ cooling_load_ton .*= borehole_ratio
696+ # if cooling load is not included, cut down heating load only and send to GhpGhx.jl
697+ end
698+ ghpghx_inputs[" heating_thermal_load_mmbtu_per_hr" ] = heating_load_mmbtu
699+ ghpghx_inputs[" cooling_thermal_load_ton" ] = cooling_load_ton
700+
701+ # Rerun GhpGhx.jl
702+ results, inputs_params = GhpGhx. ghp_model (ghpghx_inputs)
703+ optimal_number_of_boreholes = GhpGhx. get_results_for_reopt (results, inputs_params)[" number_of_boreholes" ]
704+ # Solution is found if the new optimal number of boreholes sized by GhpGhx.jl = user-specified max number of boreholes,
705+ # Otherwise, continue solving until reaching max iteration
706+ if - 0.5 < optimal_number_of_boreholes - d[" GHP" ][" max_number_of_boreholes" ] < 0.5
707+ break
708+ else
709+ iter += 1
710+ end
711+ end
712+ end
713+ end
714+
628715 # Create a dictionary of the results data needed for REopt
629716 ghpghx_results = GhpGhx. get_results_for_reopt (results, inputs_params)
717+ # 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
630718 @info " GhpGhx.jl model solved" # with status $(results["status"])."
631719 catch e
632720 @info e
@@ -644,9 +732,7 @@ function Scenario(d::Dict; flex_hvac_from_json=false)
644732 end
645733 append! (ghp_option_list, [GHP (ghpghx_response, ghp_inputs_removed_ghpghx_params)])
646734 # Print out ghpghx_response for loading into a future run without running GhpGhx.jl again
647- # open("scenarios/ghpghx_response.json","w") do f
648- # JSON.print(f, ghpghx_response)
649- # end
735+ # open("scenarios/ghpghx_response.json","w") do f
650736 end
651737 # If ghpghx_responses is included in inputs, do NOT run GhpGhx.jl model and use already-run ghpghx result as input to REopt
652738 elseif eval_ghp && get_ghpghx_from_input
0 commit comments