From 5f0a0a9c2863976f0078a084764c925617df53e2 Mon Sep 17 00:00:00 2001 From: Scott Horowitz Date: Mon, 3 Jun 2024 10:06:09 -0600 Subject: [PATCH] Squashed 'hpxml-measures/' changes from 9b7b04d981..c07b098ea1 c07b098ea1 Update changelog and bump version. 2448ab2a34 Fixes #1739. And some light refactoring. 32afb154c8 Merge pull request #1738 from NREL/msgpack_windows git-subtree-dir: hpxml-measures git-subtree-split: c07b098ea123a63849cca8e60078c96a05e536a9 --- Changelog.md | 5 ++ HPXMLtoOpenStudio/measure.xml | 8 +-- HPXMLtoOpenStudio/resources/hvac_sizing.rb | 77 +++++++++++----------- HPXMLtoOpenStudio/resources/version.rb | 2 +- 4 files changed, 50 insertions(+), 42 deletions(-) diff --git a/Changelog.md b/Changelog.md index 93c785981..5b367219f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,8 @@ +## OpenStudio-HPXML v1.8.1 + +__Bugfixes__ +- Fixes cfm/ton restriction from incorrectly applying to furnace heating airflow rate. + ## OpenStudio-HPXML v1.8.0 __New Features__ diff --git a/HPXMLtoOpenStudio/measure.xml b/HPXMLtoOpenStudio/measure.xml index e7aac3bcd..ea96f178a 100644 --- a/HPXMLtoOpenStudio/measure.xml +++ b/HPXMLtoOpenStudio/measure.xml @@ -3,8 +3,8 @@ 3.1 hpxm_lto_openstudio b1543b30-9465-45ff-ba04-1d1f85e763bc - 19f754cf-2165-45e2-9387-46f301d3d453 - 2024-05-29T18:54:28Z + 7d1883e2-86ba-4a5a-a8ab-82db02825ebb + 2024-06-03T15:59:10Z D8922A73 HPXMLtoOpenStudio HPXML to OpenStudio Translator @@ -387,7 +387,7 @@ hvac_sizing.rb rb resource - 258360CD + DF70AD3A lighting.rb @@ -597,7 +597,7 @@ version.rb rb resource - 0CAA1F93 + 29402A34 waterheater.rb diff --git a/HPXMLtoOpenStudio/resources/hvac_sizing.rb b/HPXMLtoOpenStudio/resources/hvac_sizing.rb index fcc2c3acd..978a06ad3 100644 --- a/HPXMLtoOpenStudio/resources/hvac_sizing.rb +++ b/HPXMLtoOpenStudio/resources/hvac_sizing.rb @@ -1584,7 +1584,7 @@ def self.apply_hvac_duct_loads_heating(mj, zone, hvac_loads, zone_loads, all_spa ''' return if hvac_heating.nil? || (hvac_loads.Heat_Tot <= 0) || hvac_heating.distribution_system.nil? || hvac_heating.distribution_system.ducts.empty? - supply_air_temp = hvac_heating.additional_properties.supply_air_temp + hvac_heating_ap = hvac_heating.additional_properties init_heat_load = hvac_loads.Heat_Tot @@ -1603,7 +1603,8 @@ def self.apply_hvac_duct_loads_heating(mj, zone, hvac_loads, zone_loads, all_spa heat_load_prev = heat_load_next # Calculate the new heating air flow rate - heat_cfm = calc_airflow_rate_manual_s(mj, heat_load_next, (supply_air_temp - mj.heat_setpoint), nil) + heating_delta_t = hvac_heating_ap.supply_air_temp - mj.heat_setpoint + heat_cfm = calc_airflow_rate_manual_s(mj, heat_load_next, heating_delta_t) dse_Qs, dse_Qr = calc_duct_leakages_cfm25(hvac_heating.distribution_system, heat_cfm) @@ -1644,7 +1645,7 @@ def self.apply_hvac_duct_loads_cooling(mj, zone, hvac_loads, zone_loads, all_spa return if hvac_cooling.nil? || (hvac_loads.Cool_Sens <= 0) || hvac_cooling.distribution_system.nil? || hvac_cooling.distribution_system.ducts.empty? - leaving_air_temp = hvac_cooling.additional_properties.leaving_air_temp + hvac_cooling_ap = hvac_cooling.additional_properties init_cool_load_sens = hvac_loads.Cool_Sens init_cool_load_lat = hvac_loads.Cool_Lat @@ -1661,7 +1662,8 @@ def self.apply_hvac_duct_loads_cooling(mj, zone, hvac_loads, zone_loads, all_spa delta = 1 cool_load_tot_next = init_cool_load_sens + init_cool_load_lat - cool_cfm = calc_airflow_rate_manual_s(mj, init_cool_load_sens, (mj.cool_setpoint - leaving_air_temp), nil) + cooling_delta_t = mj.cool_setpoint - hvac_cooling_ap.leaving_air_temp + cool_cfm = calc_airflow_rate_manual_s(mj, init_cool_load_sens, cooling_delta_t) _dse_Qs, dse_Qr = calc_duct_leakages_cfm25(hvac_cooling.distribution_system, cool_cfm) for _iter in 1..50 @@ -1673,11 +1675,11 @@ def self.apply_hvac_duct_loads_cooling(mj, zone, hvac_loads, zone_loads, all_spa cool_load_tot = cool_load_lat + cool_load_sens # Calculate the new cooling air flow rate - cool_cfm = calc_airflow_rate_manual_s(mj, cool_load_sens, (mj.cool_setpoint - leaving_air_temp), nil) + cool_cfm = calc_airflow_rate_manual_s(mj, cool_load_sens, cooling_delta_t) dse_Qs, dse_Qr = calc_duct_leakages_cfm25(hvac_cooling.distribution_system, cool_cfm) - dse_DE, _dse_dTe_cooling, _cool_duct_sens = calc_delivery_effectiveness_cooling(mj, dse_Qs, dse_Qr, leaving_air_temp, cool_cfm, cool_load_sens, dse_Tamb_s, dse_Tamb_r, dse_As, dse_Ar, mj.cool_setpoint, dse_Fregain_s, dse_Fregain_r, cool_load_tot, dse_h_r, supply_r, return_r) + dse_DE, _dse_dTe_cooling, _cool_duct_sens = calc_delivery_effectiveness_cooling(mj, dse_Qs, dse_Qr, hvac_cooling_ap.leaving_air_temp, cool_cfm, cool_load_sens, dse_Tamb_s, dse_Tamb_r, dse_As, dse_Ar, mj.cool_setpoint, dse_Fregain_s, dse_Fregain_r, cool_load_tot, dse_h_r, supply_r, return_r) cool_load_tot_next = (init_cool_load_sens + init_cool_load_lat) / dse_DE @@ -1759,7 +1761,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva if not cooling_type.nil? hvac_cooling_ap = hvac_cooling.additional_properties is_ducted = !hvac_cooling.distribution_system.nil? - leaving_air_temp = hvac_cooling.additional_properties.leaving_air_temp + cooling_delta_t = mj.cool_setpoint - hvac_cooling_ap.leaving_air_temp oversize_limit, oversize_delta, undersize_limit = get_hvac_size_limits(hvac_cooling) end @@ -1794,7 +1796,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva sens_cap_rated = cool_cap_rated * hvac_cooling_shr # Calculate the air flow rate required for design conditions - hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Cool_Load_Sens, (mj.cool_setpoint - leaving_air_temp), cool_cap_rated) + hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Cool_Load_Sens, cooling_delta_t, dx_capacity: cool_cap_rated) sensible_cap_curve_value = process_curve_fit(hvac_sizings.Cool_Airflow, hvac_sizings.Cool_Load_Tot, entering_temp) sens_cap_design = sens_cap_rated * sensible_cap_curve_value @@ -1823,7 +1825,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva cool_load_sens_cap_design = hvac_sizings.Cool_Load_Lat / ((total_cap_curve_value / hvac_cooling_shr - \ (b_sens + d_sens * entering_temp) / \ - (1.1 * mj.acf * (mj.cool_setpoint - leaving_air_temp))) / \ + (1.1 * mj.acf * cooling_delta_t)) / \ (a_sens + c_sens * entering_temp) - 1.0) # Ensure equipment is not being undersized @@ -1883,7 +1885,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva end # Calculate the final air flow rate using final sensible capacity at design - hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, cool_load_sens_cap_design, (mj.cool_setpoint - leaving_air_temp), hvac_sizings.Cool_Capacity) + hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, cool_load_sens_cap_design, cooling_delta_t, dx_capacity: hvac_sizings.Cool_Capacity) elsif [HPXML::HVACTypeHeatPumpMiniSplit, HPXML::HVACTypeMiniSplitAirConditioner].include?(cooling_type) && !is_ducted @@ -1958,7 +1960,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva cool_load_sens_cap_design = (hvac_sizings.Cool_Capacity_Sens * sensible_cap_curve_value / (1.0 + (1.0 - coil_bf * bypass_factor_curve_value) * - (80.0 - mj.cool_setpoint) / (mj.cool_setpoint - leaving_air_temp))) + (80.0 - mj.cool_setpoint) / cooling_delta_t)) cool_load_lat_cap_design = hvac_sizings.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. @@ -1975,16 +1977,16 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva # Recalculate the air flow rate in case the oversizing limit has been used cool_load_sens_cap_design = (hvac_sizings.Cool_Capacity_Sens * sensible_cap_curve_value / (1.0 + (1.0 - coil_bf * bypass_factor_curve_value) * - (80.0 - mj.cool_setpoint) / (mj.cool_setpoint - leaving_air_temp))) - hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, cool_load_sens_cap_design, (mj.cool_setpoint - leaving_air_temp), hvac_sizings.Cool_Capacity) + (80.0 - mj.cool_setpoint) / cooling_delta_t)) + hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, cool_load_sens_cap_design, cooling_delta_t, dx_capacity: hvac_sizings.Cool_Capacity) elsif HPXML::HVACTypeEvaporativeCooler == cooling_type hvac_sizings.Cool_Capacity = hvac_sizings.Cool_Load_Tot hvac_sizings.Cool_Capacity_Sens = hvac_sizings.Cool_Load_Sens - if mj.cool_setpoint - leaving_air_temp > 0 + if cooling_delta_t > 0 # See Manual S Section 4-4 Direct Evaporative Cooling: Blower Cfm - hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Cool_Load_Sens, (mj.cool_setpoint - leaving_air_temp), nil) + hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Cool_Load_Sens, cooling_delta_t) else hvac_sizings.Cool_Airflow = hpxml_bldg.building_construction.conditioned_floor_area * 2.0 # Use industry rule of thumb sizing method adopted by HEScore end @@ -2015,7 +2017,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva if not heating_type.nil? hvac_heating_ap = hvac_heating.additional_properties is_ducted = !hvac_heating.distribution_system.nil? - supply_air_temp = hvac_heating.additional_properties.supply_air_temp + heating_delta_t = hvac_heating_ap.supply_air_temp - mj.heat_setpoint if hvac_heating.is_a?(HPXML::HeatingSystem) && hvac_heating.is_heat_pump_backup_system # Adjust heating load using the HP backup calculation @@ -2029,7 +2031,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva hvac_sizings.Heat_Load = calculate_heat_pump_backup_load(mj, hvac_hp, hvac_sizings.Heat_Load, hp_sizing_values.Heat_Capacity, hp_heating_speed, hpxml_bldg) end elsif not hvac_cooling.nil? && hvac_cooling.has_integrated_heating - supply_air_temp = hvac_cooling.additional_properties.supply_air_temp + heating_delta_t = hvac_cooling_ap.supply_air_temp - mj.heat_setpoint end if hvac_sizings.Heat_Load <= 0 @@ -2052,7 +2054,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva hvac_sizings.Heat_Capacity_Supp = calculate_heat_pump_backup_load(mj, hvac_heating, hvac_sizings.Heat_Load_Supp, hvac_sizings.Heat_Capacity, hvac_heating_speed, hpxml_bldg) if (heating_type == HPXML::HVACTypeHeatPumpAirToAir) || (heating_type == HPXML::HVACTypeHeatPumpMiniSplit && is_ducted) - hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, (supply_air_temp - mj.heat_setpoint), hvac_sizings.Heat_Capacity, hvac_sizings.Cool_Airflow) + hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, heating_delta_t, dx_capacity: hvac_sizings.Heat_Capacity, hp_cooling_cfm: hvac_sizings.Cool_Airflow) else hvac_sizings.Heat_Airflow = calc_airflow_rate_user(hvac_sizings.Heat_Capacity, hvac_heating_ap.heat_rated_cfm_per_ton[hvac_heating_speed], hvac_heating_ap.heat_capacity_ratios[hvac_heating_speed]) end @@ -2078,27 +2080,27 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva hvac_sizings.Cool_Capacity_Sens = hvac_sizings.Cool_Capacity * hvac_cooling_shr cool_load_sens_cap_design = (hvac_sizings.Cool_Capacity_Sens * sensible_cap_curve_value / (1.0 + (1.0 - gshp_coil_bf * bypass_factor_curve_value) * - (80.0 - mj.cool_setpoint) / (mj.cool_setpoint - leaving_air_temp))) - hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, cool_load_sens_cap_design, (mj.cool_setpoint - leaving_air_temp), hvac_sizings.Cool_Capacity) + (80.0 - mj.cool_setpoint) / cooling_delta_t)) + hvac_sizings.Cool_Airflow = calc_airflow_rate_manual_s(mj, cool_load_sens_cap_design, cooling_delta_t, dx_capacity: hvac_sizings.Cool_Capacity) else hvac_sizings.Heat_Capacity = hvac_sizings.Heat_Load hvac_sizings.Heat_Capacity_Supp = hvac_sizings.Heat_Load_Supp end - hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, (supply_air_temp - mj.heat_setpoint), hvac_sizings.Heat_Capacity, hvac_sizings.Cool_Airflow) + hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, heating_delta_t, dx_capacity: hvac_sizings.Heat_Capacity, hp_cooling_cfm: hvac_sizings.Cool_Airflow) elsif [HPXML::HVACTypeHeatPumpWaterLoopToAir].include? heating_type hvac_sizings.Heat_Capacity = hvac_sizings.Heat_Load hvac_sizings.Heat_Capacity_Supp = hvac_sizings.Heat_Load_Supp - hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, (supply_air_temp - mj.heat_setpoint), hvac_sizings.Heat_Capacity) + hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, heating_delta_t, dx_capacity: hvac_sizings.Heat_Capacity) elsif (heating_type == HPXML::HVACTypeFurnace) || ((not hvac_cooling.nil?) && hvac_cooling.has_integrated_heating) hvac_sizings.Heat_Capacity = hvac_sizings.Heat_Load hvac_sizings.Heat_Capacity_Supp = 0.0 - hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, (supply_air_temp - mj.heat_setpoint), hvac_sizings.Heat_Capacity) + hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, heating_delta_t) elsif [HPXML::HVACTypeStove, HPXML::HVACTypeSpaceHeater, @@ -2114,7 +2116,7 @@ def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hva hvac_sizings.Heat_Airflow = UnitConversions.convert(hvac_sizings.Heat_Capacity, 'Btu/hr', 'ton') * hvac_heating_ap.heat_rated_cfm_per_ton[0] else # Autosized airflow rate - hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, (supply_air_temp - mj.heat_setpoint), hvac_sizings.Heat_Capacity) + hvac_sizings.Heat_Airflow = calc_airflow_rate_manual_s(mj, hvac_sizings.Heat_Capacity, heating_delta_t) end elsif [HPXML::HVACTypeBoiler, @@ -2716,34 +2718,35 @@ def self.get_ventilation_data(hpxml_bldg) return [q_unbal, q_bal, q_preheat, q_precool, q_recirc, bal_sens_eff, bal_lat_eff] end - def self.calc_airflow_rate_manual_s(mj, sens_load_or_capacity, deltaT, rated_capacity, corresponding_cooling_airflow_rate = nil) + def self.calc_airflow_rate_manual_s(mj, sens_load_or_capacity, delta_t, dx_capacity: nil, hp_cooling_cfm: nil) # Airflow sizing following Manual S based on design calculation - airflow_rate = sens_load_or_capacity / (1.1 * mj.acf * deltaT) + airflow_cfm = sens_load_or_capacity / (1.1 * mj.acf * delta_t) - if not rated_capacity.nil? + if not dx_capacity.nil? # Ensure the air flow rate is between 300 and 400 cfm/ton for typical DX equipment. # Recommendation by Hugh Henderson. - rated_capacity_tons = UnitConversions.convert(rated_capacity, 'Btu/hr', 'ton') - if airflow_rate / rated_capacity_tons > 400 - airflow_rate = 400.0 * rated_capacity_tons - elsif airflow_rate / rated_capacity_tons < 300 - airflow_rate = 300.0 * rated_capacity_tons + rated_capacity_tons = UnitConversions.convert(dx_capacity, 'Btu/hr', 'ton') + if airflow_cfm / rated_capacity_tons > 400 + airflow_cfm = 400.0 * rated_capacity_tons + elsif airflow_cfm / rated_capacity_tons < 300 + airflow_cfm = 300.0 * rated_capacity_tons end end - if corresponding_cooling_airflow_rate.to_f > 0 + if hp_cooling_cfm.to_f > 0 # For a heat pump, ensure the heating airflow rate is within 30% of the cooling airflow rate. # Recommendation by Hugh Henderson. - airflow_rate = [airflow_rate, 0.7 * corresponding_cooling_airflow_rate].max - airflow_rate = [airflow_rate, 1.3 * corresponding_cooling_airflow_rate].min + airflow_cfm = [airflow_cfm, 0.7 * hp_cooling_cfm].max + airflow_cfm = [airflow_cfm, 1.3 * hp_cooling_cfm].min end - return airflow_rate + return airflow_cfm end def self.calc_airflow_rate_user(capacity, rated_cfm_per_ton, capacity_ratio) # Airflow determined by user setting, not based on design - return rated_cfm_per_ton * capacity_ratio * UnitConversions.convert(capacity, 'Btu/hr', 'ton') # Maximum air flow under heating operation + airflow_cfm = rated_cfm_per_ton * capacity_ratio * UnitConversions.convert(capacity, 'Btu/hr', 'ton') # Maximum air flow under heating operation + return airflow_cfm end def self.calc_gshp_clg_curve_value(cool_cap_curve_spec, cool_sh_curve_spec, wb_temp, db_temp, w_temp, vfr_air, loop_flow = nil, rated_vfr_air = nil) diff --git a/HPXMLtoOpenStudio/resources/version.rb b/HPXMLtoOpenStudio/resources/version.rb index aac4a2ef8..b3064d532 100644 --- a/HPXMLtoOpenStudio/resources/version.rb +++ b/HPXMLtoOpenStudio/resources/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Version - OS_HPXML_Version = '1.8.0' # Version of the OS-HPXML workflow + OS_HPXML_Version = '1.8.1' # Version of the OS-HPXML workflow OS_Version = '3.8.0' # Required version of OpenStudio (can be 'X.X' or 'X.X.X') HPXML_Version = '4.0' # HPXML schemaVersion