From 86cad8aaf03013062502b45a2d9843aad23177bd Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 24 Oct 2023 11:41:24 -0700 Subject: [PATCH] Manually copy changes from hvac_sizing_bugfixes branch. --- measures/UpgradeCosts/measure.xml | 46 +---- .../HPXMLtoOpenStudio/resources/hpxml.rb | 16 +- .../resources/hvac_sizing.rb | 160 ++++++++++-------- 3 files changed, 104 insertions(+), 118 deletions(-) diff --git a/measures/UpgradeCosts/measure.xml b/measures/UpgradeCosts/measure.xml index 3a3b95b2ee..aed62a5b6d 100644 --- a/measures/UpgradeCosts/measure.xml +++ b/measures/UpgradeCosts/measure.xml @@ -3,8 +3,8 @@ 3.1 upgrade_costs ef51212c-acc4-48d7-9b29-cf2a5c6c4449 - c1701f5c-37ad-4148-aff8-70f5e42e8a60 - 2023-08-21T22:09:39Z + 740cc631-b3c7-49f7-9976-669dda637ef4 + 2023-10-24T18:40:48Z 9BF1E6AC UpgradeCosts Upgrade Costs @@ -119,12 +119,6 @@ test B9183037 - - SFD_1story_FB_UA_GRG_MSHP_FuelTanklessWH.xml - xml - test - 65449877 - SFD_1story_FB_UA_GRG_RoomAC_ElecBoiler_FuelTanklessWH.osw osw @@ -149,24 +143,12 @@ test ABFCA3DB - - SFD_1story_UB_UA_GRG_ACV_FuelFurnace_PortableHeater_HPWH.xml - xml - test - 076668CA - SFD_2story_CS_UA_AC2_FuelBoiler_FuelTankWH.osw osw test B57303D3 - - SFD_2story_CS_UA_AC2_FuelBoiler_FuelTankWH.xml - xml - test - 451F9215 - SFD_2story_CS_UA_GRG_ASHPV_FuelTanklessWH.osw osw @@ -179,12 +161,6 @@ test 986E1AAD - - SFD_2story_FB_UA_GRG_AC1_ElecBaseboard_FuelTankWH.xml - xml - test - DDDC28CD - SFD_2story_FB_UA_GRG_AC1_UnitHeater_FuelTankWH.osw osw @@ -221,24 +197,6 @@ test B165DD4B - - in.epw - epw - test - E23378AA - - - in.osm - osm - test - 06875597 - - - in.xml - xml - test - BD7C5A72 - upgrade_costs_test.rb rb diff --git a/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml.rb b/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml.rb index 9d966fb95e..0a2ea7e7c4 100644 --- a/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml.rb +++ b/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml.rb @@ -4059,11 +4059,17 @@ def distribution_system end def is_dual_fuel - if @backup_heating_fuel.nil? - return false - end - if @backup_heating_fuel.to_s == @heat_pump_fuel.to_s - return false + if backup_system.nil? + if @backup_heating_fuel.nil? + return false + end + if @backup_heating_fuel.to_s == @heat_pump_fuel.to_s + return false + end + else + if backup_system.heating_system_fuel.to_s == @heat_pump_fuel.to_s + return false + end end return true diff --git a/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac_sizing.rb b/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac_sizing.rb index d956ca66ba..f23d765da6 100644 --- a/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac_sizing.rb +++ b/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hvac_sizing.rb @@ -1134,22 +1134,18 @@ def self.apply_hvac_size_limits(hvac_cooling) end def self.apply_hvac_heat_pump_logic(hvac_sizing_values, hvac_cooling) - # If HERS/MaxLoad methodology, uses at least the larger of heating and cooling loads for heat pump sizing (required for ERI). return unless hvac_cooling.is_a? HPXML::HeatPump return if @fraction_cool_load_served == 0 return if @fraction_heat_load_served == 0 - if (@hpxml.header.heat_pump_sizing_methodology != HPXML::HeatPumpSizingACCA) + if @hpxml.header.heat_pump_sizing_methodology != HPXML::HeatPumpSizingACCA + # If HERS/MaxLoad methodology, use at least the larger of heating/cooling loads for heat pump sizing. # Note: Heat_Load_Supp should NOT be adjusted; we only want to adjust the HP capacity, not the HP backup heating capacity. max_load = [hvac_sizing_values.Heat_Load, hvac_sizing_values.Cool_Load_Tot].max hvac_sizing_values.Heat_Load = max_load hvac_sizing_values.Cool_Load_Sens *= max_load / hvac_sizing_values.Cool_Load_Tot hvac_sizing_values.Cool_Load_Lat *= max_load / hvac_sizing_values.Cool_Load_Tot hvac_sizing_values.Cool_Load_Tot = max_load - - # Override Manual S oversize allowances: - @oversize_limit = 1.0 - @oversize_delta = 0.0 end end @@ -1339,9 +1335,6 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat hvac_cooling_ap = hvac_cooling.additional_properties end - # Calculate the air flow rate required for design conditions - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Cool_Load_Sens, (@cool_setpoint - @leaving_air_temp)) - if hvac_sizing_values.Cool_Load_Tot <= 0 hvac_sizing_values.Cool_Capacity = 0.0 @@ -1361,6 +1354,9 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat hvac_cooling_shr = hvac_cooling_ap.cool_rated_shrs_gross[hvac_cooling_speed] sens_cap_rated = cool_cap_rated * hvac_cooling_shr + # Calculate the air flow rate required for design conditions + hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Cool_Load_Sens, (@cool_setpoint - @leaving_air_temp), cool_cap_rated) + sensible_cap_curve_value = process_curve_fit(hvac_sizing_values.Cool_Airflow, hvac_sizing_values.Cool_Load_Tot, entering_temp) sens_cap_design = sens_cap_rated * sensible_cap_curve_value lat_cap_design = [hvac_sizing_values.Cool_Load_Tot - sens_cap_design, 1.0].max @@ -1372,7 +1368,13 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat d_sens = shr_biquadratic[5] # Adjust Sizing - if lat_cap_design < hvac_sizing_values.Cool_Load_Lat + if hvac_cooling.is_a?(HPXML::HeatPump) && (@hpxml.header.heat_pump_sizing_methodology == HPXML::HeatPumpSizingHERS) + hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot + hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + + cool_load_sens_cap_design = hvac_sizing_values.Cool_Capacity_Sens * sensible_cap_curve_value + + elsif lat_cap_design < hvac_sizing_values.Cool_Load_Lat # Size by MJ8 Latent load, return to rated conditions # Solve for the new sensible and total capacity at design conditions: @@ -1381,10 +1383,13 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat # substituting in CFM = cool_load_sens_cap_design / (1.1 * ACF * (cool_setpoint - LAT)) cool_load_sens_cap_design = hvac_sizing_values.Cool_Load_Lat / ((total_cap_curve_value / hvac_cooling_shr - \ - (UnitConversions.convert(b_sens, 'ton', 'Btu/hr') + UnitConversions.convert(d_sens, 'ton', 'Btu/hr') * entering_temp) / \ + (b_sens + d_sens * entering_temp) / \ (1.1 * @acf * (@cool_setpoint - @leaving_air_temp))) / \ (a_sens + c_sens * entering_temp) - 1.0) + # Ensure equipment is not being undersized + cool_load_sens_cap_design = [cool_load_sens_cap_design, @undersize_limit * hvac_sizing_values.Cool_Load_Sens].max + cool_cap_design = cool_load_sens_cap_design + hvac_sizing_values.Cool_Load_Lat # The SHR of the equipment at the design condition @@ -1399,16 +1404,13 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat # Limit total capacity to oversize limit cool_cap_design = [cool_cap_design, @oversize_limit * hvac_sizing_values.Cool_Load_Tot].min - # Determine the final sensible capacity at design using the SHR - cool_load_sens_cap_design = shr_design * cool_cap_design - - # Calculate the final air flow rate using final sensible capacity at design - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp)) - # Determine rated capacities hvac_sizing_values.Cool_Capacity = cool_cap_design / total_cap_curve_value hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + # Determine the final sensible capacity at design using the SHR + cool_load_sens_cap_design = shr_design * cool_cap_design + elsif sens_cap_design < @undersize_limit * hvac_sizing_values.Cool_Load_Sens # Size by MJ8 Sensible load, return to rated conditions, find Sens with SHRRated. Limit total # capacity to oversizing limit @@ -1433,57 +1435,50 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat # Recalculate the air flow rate in case the oversizing limit has been used cool_load_sens_cap_design = hvac_sizing_values.Cool_Capacity_Sens * sensible_cap_curve_value - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp)) else hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot / total_cap_curve_value hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr cool_load_sens_cap_design = hvac_sizing_values.Cool_Capacity_Sens * sensible_cap_curve_value - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp)) end - # Ensure the air flow rate is in between 200 and 500 cfm/ton. - # Reset the air flow rate (with a safety margin), if required. - if hvac_sizing_values.Cool_Airflow / UnitConversions.convert(hvac_sizing_values.Cool_Capacity, 'Btu/hr', 'ton') > 500 - hvac_sizing_values.Cool_Airflow = 499.0 * UnitConversions.convert(hvac_sizing_values.Cool_Capacity, 'Btu/hr', 'ton') # CFM - elsif hvac_sizing_values.Cool_Airflow / UnitConversions.convert(hvac_sizing_values.Cool_Capacity, 'Btu/hr', 'ton') < 200 - hvac_sizing_values.Cool_Airflow = 201.0 * UnitConversions.convert(hvac_sizing_values.Cool_Capacity, 'Btu/hr', 'ton') # CFM - end + # Calculate the final air flow rate using final sensible capacity at design + hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp), hvac_sizing_values.Cool_Capacity) elsif [HPXML::HVACTypeHeatPumpMiniSplit, - HPXML::HVACTypeMiniSplitAirConditioner].include? @cooling_type - - entering_temp = @hpxml.header.manualj_cooling_design_temp - hvac_cooling_speed = get_sizing_speed(hvac_cooling_ap) - coefficients = hvac_cooling_ap.cool_cap_ft_spec[hvac_cooling_speed] - - total_cap_curve_value = MathTools.biquadratic(@wetbulb_indoor_cooling, entering_temp, coefficients) - hvac_cooling_shr = hvac_cooling_ap.cool_rated_shrs_gross[hvac_cooling_speed] - - hvac_sizing_values.Cool_Capacity = (hvac_sizing_values.Cool_Load_Tot / total_cap_curve_value) - hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_user(hvac_sizing_values.Cool_Capacity, hvac_cooling_ap.cool_rated_cfm_per_ton[-1], hvac_cooling_ap.cool_capacity_ratios[-1]) - - elsif [HPXML::HVACTypeRoomAirConditioner, + HPXML::HVACTypeMiniSplitAirConditioner, + HPXML::HVACTypeRoomAirConditioner, HPXML::HVACTypePTAC, HPXML::HVACTypeHeatPumpPTHP, HPXML::HVACTypeHeatPumpRoom].include? @cooling_type - entering_temp = @hpxml.header.manualj_cooling_design_temp hvac_cooling_speed = get_sizing_speed(hvac_cooling_ap) - total_cap_curve_value = MathTools.biquadratic(@wetbulb_indoor_cooling, entering_temp, hvac_cooling_ap.cool_cap_ft_spec[hvac_cooling_speed]) hvac_cooling_shr = hvac_cooling_ap.cool_rated_shrs_gross[hvac_cooling_speed] - hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot / total_cap_curve_value - hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_user(hvac_sizing_values.Cool_Capacity, hvac_cooling_ap.cool_rated_cfm_per_ton[hvac_cooling_speed], 1.0) + if hvac_cooling.is_a?(HPXML::HeatPump) && (@hpxml.header.heat_pump_sizing_methodology == HPXML::HeatPumpSizingHERS) + hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot + hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + else + entering_temp = @hpxml.header.manualj_cooling_design_temp + coefficients = hvac_cooling_ap.cool_cap_ft_spec[hvac_cooling_speed] + total_cap_curve_value = MathTools.biquadratic(@wetbulb_indoor_cooling, entering_temp, coefficients) + + hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot / total_cap_curve_value + hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + end + + hvac_sizing_values.Cool_Airflow = calc_airflow_rate_user(hvac_sizing_values.Cool_Capacity, hvac_cooling_ap.cool_rated_cfm_per_ton[-1], hvac_cooling_ap.cool_capacity_ratios[-1]) elsif HPXML::HVACTypeHeatPumpGroundToAir == @cooling_type + coil_bf = gshp_coil_bf entering_temp = hvac_cooling_ap.design_chw hvac_cooling_speed = get_sizing_speed(hvac_cooling_ap) + # Calculate the air flow rate required for design conditions + hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Cool_Load_Sens, (@cool_setpoint - @leaving_air_temp)) + # Neglecting the water flow rate for now because it's not available yet. Air flow rate is pre-adjusted values. design_wb_temp = UnitConversions.convert(@wetbulb_indoor_cooling, 'f', 'k') design_db_temp = UnitConversions.convert(@cool_setpoint, 'f', 'k') @@ -1497,29 +1492,34 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat bypass_factor_curve_value = MathTools.biquadratic(@wetbulb_indoor_cooling, @cool_setpoint, gshp_coil_bf_ft_spec) hvac_cooling_shr = hvac_cooling_ap.cool_rated_shrs_gross[hvac_cooling_speed] - hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot / total_cap_curve_value # Note: cool_cap_design = hvac_sizing_values.Cool_Load_Tot - hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + if @hpxml.header.heat_pump_sizing_methodology == HPXML::HeatPumpSizingHERS + hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot + hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + else + hvac_sizing_values.Cool_Capacity = hvac_sizing_values.Cool_Load_Tot / total_cap_curve_value # Note: cool_cap_design = hvac_sizing_values.Cool_Load_Tot + hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr - cool_load_sens_cap_design = (hvac_sizing_values.Cool_Capacity_Sens * sensible_cap_curve_value / - (1.0 + (1.0 - coil_bf * bypass_factor_curve_value) * - (80.0 - @cool_setpoint) / (@cool_setpoint - @leaving_air_temp))) - cool_load_lat_cap_design = hvac_sizing_values.Cool_Load_Tot - cool_load_sens_cap_design + cool_load_sens_cap_design = (hvac_sizing_values.Cool_Capacity_Sens * sensible_cap_curve_value / + (1.0 + (1.0 - coil_bf * bypass_factor_curve_value) * + (80.0 - @cool_setpoint) / (@cool_setpoint - @leaving_air_temp))) + cool_load_lat_cap_design = hvac_sizing_values.Cool_Load_Tot - cool_load_sens_cap_design - # Adjust Sizing so that coil sensible at design >= CoolingLoad_Sens, and coil latent at design >= CoolingLoad_Lat, and equipment SHRRated is maintained. - cool_load_sens_cap_design = [cool_load_sens_cap_design, hvac_sizing_values.Cool_Load_Sens].max - cool_load_lat_cap_design = [cool_load_lat_cap_design, hvac_sizing_values.Cool_Load_Lat].max - cool_cap_design = cool_load_sens_cap_design + cool_load_lat_cap_design + # Adjust Sizing so that coil sensible at design >= CoolingLoad_Sens, and coil latent at design >= CoolingLoad_Lat, and equipment SHRRated is maintained. + cool_load_sens_cap_design = [cool_load_sens_cap_design, hvac_sizing_values.Cool_Load_Sens].max + cool_load_lat_cap_design = [cool_load_lat_cap_design, hvac_sizing_values.Cool_Load_Lat].max + cool_cap_design = cool_load_sens_cap_design + cool_load_lat_cap_design - # Limit total capacity via oversizing limit - cool_cap_design = [cool_cap_design, @oversize_limit * hvac_sizing_values.Cool_Load_Tot].min - hvac_sizing_values.Cool_Capacity = cool_cap_design / total_cap_curve_value - hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + # Limit total capacity via oversizing limit + cool_cap_design = [cool_cap_design, @oversize_limit * hvac_sizing_values.Cool_Load_Tot].min + hvac_sizing_values.Cool_Capacity = cool_cap_design / total_cap_curve_value + hvac_sizing_values.Cool_Capacity_Sens = hvac_sizing_values.Cool_Capacity * hvac_cooling_shr + end # Recalculate the air flow rate in case the oversizing limit has been used cool_load_sens_cap_design = (hvac_sizing_values.Cool_Capacity_Sens * sensible_cap_curve_value / (1.0 + (1.0 - coil_bf * bypass_factor_curve_value) * (80.0 - @cool_setpoint) / (@cool_setpoint - @leaving_air_temp))) - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp)) + hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp), hvac_sizing_values.Cool_Capacity) elsif HPXML::HVACTypeEvaporativeCooler == @cooling_type @@ -1567,10 +1567,16 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat HPXML::HVACTypeHeatPumpMiniSplit, HPXML::HVACTypeHeatPumpPTHP, HPXML::HVACTypeHeatPumpRoom].include? @heating_type - process_heat_pump_adjustment(hvac_sizing_values, weather, hvac_heating, total_cap_curve_value, hvac_system) + + if hvac_heating.is_a?(HPXML::HeatPump) && (@hpxml.header.heat_pump_sizing_methodology == HPXML::HeatPumpSizingHERS) + hvac_sizing_values.Heat_Capacity = hvac_sizing_values.Heat_Load + else + process_heat_pump_adjustment(hvac_sizing_values, weather, hvac_heating, total_cap_curve_value, hvac_system) + end + hvac_sizing_values.Heat_Capacity_Supp = hvac_sizing_values.Heat_Load_Supp if @heating_type == HPXML::HVACTypeHeatPumpAirToAir - hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint)) + hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint), hvac_sizing_values.Heat_Capacity) else hvac_sizing_values.Heat_Airflow = calc_airflow_rate_user(hvac_sizing_values.Heat_Capacity, hvac_heating_ap.heat_rated_cfm_per_ton[-1], hvac_heating_ap.heat_capacity_ratios[-1]) end @@ -1578,7 +1584,10 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat elsif [HPXML::HVACTypeHeatPumpGroundToAir].include? @heating_type - if hvac_sizing_values.Cool_Capacity > 0 + if @hpxml.header.heat_pump_sizing_methodology == HPXML::HeatPumpSizingHERS + hvac_sizing_values.Heat_Capacity = hvac_sizing_values.Heat_Load + hvac_sizing_values.Heat_Capacity_Supp = hvac_sizing_values.Heat_Load_Supp + elsif hvac_sizing_values.Cool_Capacity > 0 hvac_sizing_values.Heat_Capacity = hvac_sizing_values.Heat_Load hvac_sizing_values.Heat_Capacity_Supp = hvac_sizing_values.Heat_Load_Supp @@ -1595,7 +1604,7 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat cool_load_sens_cap_design = (hvac_sizing_values.Cool_Capacity_Sens * sensible_cap_curve_value / (1.0 + (1.0 - gshp_coil_bf * bypass_factor_curve_value) * (80.0 - @cool_setpoint) / (@cool_setpoint - @leaving_air_temp))) - hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp)) + hvac_sizing_values.Cool_Airflow = calc_airflow_rate_manual_s(cool_load_sens_cap_design, (@cool_setpoint - @leaving_air_temp), hvac_sizing_values.Cool_Capacity) else hvac_sizing_values.Heat_Capacity = hvac_sizing_values.Heat_Load hvac_sizing_values.Heat_Capacity_Supp = hvac_sizing_values.Heat_Load_Supp @@ -1608,7 +1617,7 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat hvac_sizing_values.Heat_Capacity = hvac_sizing_values.Heat_Load hvac_sizing_values.Heat_Capacity_Supp = hvac_sizing_values.Heat_Load_Supp - hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint)) + hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint), hvac_sizing_values.Heat_Capacity) hvac_sizing_values.Heat_Airflow_Supp = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity_Supp, (@backup_supply_air_temp - @heat_setpoint)) elsif (@heating_type == HPXML::HVACTypeFurnace) || ((not hvac_cooling.nil?) && hvac_cooling.has_integrated_heating) @@ -1616,7 +1625,7 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat hvac_sizing_values.Heat_Capacity = hvac_sizing_values.Heat_Load hvac_sizing_values.Heat_Capacity_Supp = 0.0 - hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint)) + hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint), hvac_sizing_values.Heat_Capacity) hvac_sizing_values.Heat_Airflow_Supp = 0.0 elsif [HPXML::HVACTypeStove, @@ -1633,7 +1642,7 @@ def self.apply_hvac_equipment_adjustments(hvac_sizing_values, weather, hvac_heat hvac_sizing_values.Heat_Airflow = UnitConversions.convert(hvac_sizing_values.Heat_Capacity, 'Btu/hr', 'ton') * hvac_heating_ap.heat_rated_cfm_per_ton[0] else # Autosized airflow rate - hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint)) + hvac_sizing_values.Heat_Airflow = calc_airflow_rate_manual_s(hvac_sizing_values.Heat_Capacity, (@supply_air_temp - @heat_setpoint), hvac_sizing_values.Heat_Capacity) end hvac_sizing_values.Heat_Airflow_Supp = 0.0 @@ -2111,9 +2120,22 @@ def self.get_ventilation_rates() return [tot_unbal_cfm, oa_cfm_preheat, oa_cfm_precool, recirc_cfm_shared, tot_bal_cfm_sens, tot_bal_cfm_lat] end - def self.calc_airflow_rate_manual_s(sens_load_or_capacity, deltaT) + def self.calc_airflow_rate_manual_s(sens_load_or_capacity, deltaT, rated_capacity_for_cfm_per_ton_limits = nil) # Airflow sizing following Manual S based on design calculation - return sens_load_or_capacity / (1.1 * @acf * deltaT) + airflow_rate = sens_load_or_capacity / (1.1 * @acf * deltaT) + + if not rated_capacity_for_cfm_per_ton_limits.nil? + rated_capacity_tons = UnitConversions.convert(rated_capacity_for_cfm_per_ton_limits, 'Btu/hr', 'ton') + # Ensure the air flow rate is in between 200 and 500 cfm/ton. + # Reset the air flow rate (with a safety margin), if required. + if airflow_rate / rated_capacity_tons > 500 + airflow_rate = 499.0 * rated_capacity_tons + elsif airflow_rate / rated_capacity_tons < 200 + airflow_rate = 201.0 * rated_capacity_tons + end + end + + return airflow_rate end def self.calc_airflow_rate_user(capacity, rated_cfm_per_ton, capacity_ratio)