Skip to content

Commit

Permalink
Merge pull request #1712 from NREL/mj8_ventilation
Browse files Browse the repository at this point in the history
MJ8 infiltration/ventilation
  • Loading branch information
shorowit committed May 18, 2024
2 parents d22f6ef + a195724 commit f5b5c0e
Show file tree
Hide file tree
Showing 12 changed files with 1,353 additions and 1,303 deletions.
10 changes: 5 additions & 5 deletions HPXMLtoOpenStudio/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.1</schema_version>
<name>hpxm_lto_openstudio</name>
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
<version_id>235ba31f-08b7-42da-9524-674d6b212611</version_id>
<version_modified>2024-05-18T14:58:34Z</version_modified>
<version_id>a3010ed3-bfec-4d89-b425-0ec627863167</version_id>
<version_modified>2024-05-18T15:40:55Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -387,7 +387,7 @@
<filename>hvac_sizing.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>828250E9</checksum>
<checksum>8526074F</checksum>
</file>
<file>
<filename>lighting.rb</filename>
Expand Down Expand Up @@ -639,7 +639,7 @@
<filename>test_defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>8EEC2D8E</checksum>
<checksum>A84FE910</checksum>
</file>
<file>
<filename>test_enclosure.rb</filename>
Expand Down Expand Up @@ -669,7 +669,7 @@
<filename>test_hvac_sizing.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>D5AC9590</checksum>
<checksum>BA43A919</checksum>
</file>
<file>
<filename>test_lighting.rb</filename>
Expand Down
93 changes: 77 additions & 16 deletions HPXMLtoOpenStudio/resources/hvac_sizing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def self.calculate(runner, weather, hpxml_bldg, hvac_systems, update_hpxml: true
apply_fractions_load_served(hvac_heating, hvac_loads, frac_zone_heat_load_served, frac_zone_cool_load_served)
apply_hvac_duct_loads_heating(mj, zone, hvac_loads, all_zone_loads[zone], all_space_loads, hvac_heating, hpxml_bldg)
apply_hvac_duct_loads_cooling(mj, zone, hvac_loads, all_zone_loads[zone], all_space_loads, hvac_cooling, hpxml_bldg, weather)
apply_hvac_cfis_loads(mj, hvac_loads, all_zone_loads[zone], hvac_heating, hvac_cooling, hpxml_bldg)

# Calculate HVAC equipment sizes
hvac_sizings = HVACSizingValues.new
Expand Down Expand Up @@ -1268,29 +1269,51 @@ def self.process_load_infiltration_ventilation(mj, hpxml_bldg, all_zone_loads, a
# Calculate ventilation airflow rates
q_unb_cfm, q_bal_cfm, q_preheat, q_precool, q_recirc, bal_sens_eff, bal_lat_eff = get_ventilation_data(hpxml_bldg)

# Calculate adjusted infiltration cfm (combined with ventilation)
infil_cfm_heat = (icfm_heat**1.5 + q_unb_cfm**1.5)**0.67 - q_unb_cfm
infil_cfm_cool = (icfm_cool**1.5 + q_unb_cfm**1.5)**0.67 - q_unb_cfm
# Calculate net infiltration cfm (NCFM; infiltration combined with unbalanced ventilation)
if q_unb_cfm == 0
# Neutral pressure, so NCFM = ICFM
infil_ncfm_heat = icfm_heat
infil_ncfm_cool = icfm_cool
elsif q_unb_cfm > 0
# Negative pressure, so NCFM = (ICFM^1.5 + CFMimb^1.5)^0.67
infil_ncfm_heat = (icfm_heat**1.5 + q_unb_cfm**1.5)**0.67
infil_ncfm_cool = (icfm_cool**1.5 + q_unb_cfm**1.5)**0.67
else
if icfm_heat < q_unb_cfm.abs
# Dominating positive pressure, so NCFM = 0
infil_ncfm_heat = 0.0
else
# Mitigating positive pressure, so NCFM = (ICFM^1.5 - ABS(CFMimb)^1.5)^0.67
infil_ncfm_heat = (icfm_heat**1.5 - q_unb_cfm.abs**1.5)**0.67
end
if icfm_cool < q_unb_cfm.abs
# Dominating positive pressure, so NCFM = 0
infil_ncfm_cool = 0.0
else
# Mitigating positive pressure, so NCFM = (ICFM^1.5 - ABS(CFMimb)^1.5)^0.67
infil_ncfm_cool = (icfm_cool**1.5 - q_unb_cfm.abs**1.5)**0.67
end
end

hpxml_bldg.additional_properties.infil_heat_cfm = infil_cfm_heat
hpxml_bldg.additional_properties.infil_cool_cfm = infil_cfm_cool
hpxml_bldg.additional_properties.infil_heat_cfm = infil_ncfm_heat
hpxml_bldg.additional_properties.infil_cool_cfm = infil_ncfm_cool

# Infiltration load
bldg_Heat_Infil = 1.1 * mj.acf * infil_cfm_heat * mj.htd
bldg_Cool_Infil_Sens = 1.1 * mj.acf * infil_cfm_cool * mj.ctd
bldg_Cool_Infil_Lat = 0.68 * mj.acf * infil_cfm_cool * mj.cool_design_grains
bldg_Heat_Infil = 1.1 * mj.acf * infil_ncfm_heat * mj.htd
bldg_Cool_Infil_Sens = 1.1 * mj.acf * infil_ncfm_cool * mj.ctd
bldg_Cool_Infil_Lat = 0.68 * mj.acf * infil_ncfm_cool * mj.cool_design_grains

# Calculate vent cfm
vent_cfm_heat = q_unb_cfm + q_bal_cfm
vent_cfm_heat = q_bal_cfm
vent_cfm_cool = vent_cfm_heat

hpxml_bldg.additional_properties.vent_heat_cfm = vent_cfm_heat
hpxml_bldg.additional_properties.vent_cool_cfm = vent_cfm_cool

# Calculate vent cfm incorporating sens/lat effectiveness, preheat/precool, and recirc
vent_cfm_heat = q_unb_cfm + q_bal_cfm * (1.0 - bal_sens_eff) - q_preheat - q_recirc
vent_cfm_cool_sens = q_unb_cfm + q_bal_cfm * (1.0 - bal_sens_eff) - q_precool - q_recirc
vent_cfm_cool_lat = q_unb_cfm + q_bal_cfm * (1.0 - bal_lat_eff) - q_recirc
vent_cfm_heat = q_bal_cfm * (1.0 - bal_sens_eff) - q_preheat - q_recirc
vent_cfm_cool_sens = q_bal_cfm * (1.0 - bal_sens_eff) - q_precool - q_recirc
vent_cfm_cool_lat = q_bal_cfm * (1.0 - bal_lat_eff) - q_recirc

bldg_Heat_Vent = 1.1 * mj.acf * vent_cfm_heat * mj.htd
bldg_Cool_Vent_Sens = 1.1 * mj.acf * vent_cfm_cool_sens * mj.ctd
Expand Down Expand Up @@ -1686,6 +1709,44 @@ def self.apply_hvac_duct_loads_cooling(mj, zone, hvac_loads, zone_loads, all_spa
end
end

def self.apply_hvac_cfis_loads(mj, hvac_loads, zone_loads, hvac_heating, hvac_cooling, hpxml_bldg)
'''
CFIS Ventilation Loads
'''
if (not hvac_heating.nil?) && (not hvac_heating.distribution_system.nil?)
hvac_distribution = hvac_heating.distribution_system
elsif (not hvac_cooling.nil?) && (not hvac_cooling.distribution_system.nil?)
hvac_distribution = hvac_cooling.distribution_system
end
return if hvac_distribution.nil?

vent_mech_cfis = hpxml_bldg.ventilation_fans.find { |vent_mech| vent_mech.fan_type == HPXML::MechVentTypeCFIS && vent_mech.distribution_system_idref == hvac_distribution.id }
return if vent_mech_cfis.nil?

vent_cfm = vent_mech_cfis.total_unit_flow_rate

# Note: These are system loads, not space loads
heat_load = 1.1 * mj.acf * vent_cfm * mj.htd
cool_sens_load = 1.1 * mj.acf * vent_cfm * mj.ctd
cool_lat_load = 0.68 * mj.acf * vent_cfm * mj.cool_design_grains

hvac_loads.Heat_Vent += heat_load
hvac_loads.Heat_Tot += heat_load
hvac_loads.Cool_Vent_Sens += cool_sens_load
hvac_loads.Cool_Sens += cool_sens_load
hvac_loads.Cool_Vent_Lat += cool_lat_load
hvac_loads.Cool_Lat += cool_lat_load
hvac_loads.Cool_Tot += cool_sens_load + cool_lat_load

zone_loads.Heat_Vent += heat_load
zone_loads.Heat_Tot += heat_load
zone_loads.Cool_Vent_Sens += cool_sens_load
zone_loads.Cool_Sens += cool_sens_load
zone_loads.Cool_Vent_Lat += cool_lat_load
zone_loads.Cool_Lat += cool_lat_load
zone_loads.Cool_Tot += cool_sens_load + cool_lat_load
end

def self.apply_hvac_equipment_adjustments(mj, runner, hvac_sizings, weather, hvac_heating, hvac_cooling, hvac_system, hpxml_bldg)
'''
Equipment Adjustments
Expand Down Expand Up @@ -2604,7 +2665,7 @@ def self.process_heat_pump_adjustment(mj, runner, hvac_sizings, weather, hvac_he
end

def self.get_ventilation_data(hpxml_bldg)
# If CFIS w/ supplemental fan, assume air handler is running most of the hour and can provide
# If CFIS w/ supplemental fan, assume air handler is running the full hour and can provide
# all ventilation needs (i.e., supplemental fan does not need to run), so skip supplement fan
vent_fans_mech = hpxml_bldg.ventilation_fans.select { |f| f.used_for_whole_building_ventilation && !f.is_cfis_supplemental_fan? && f.flow_rate > 0 && f.hours_in_operation > 0 }
if vent_fans_mech.empty?
Expand Down Expand Up @@ -2635,10 +2696,10 @@ def self.get_ventilation_data(hpxml_bldg)
q_recirc = vent_mech_shared.map { |vent_mech| vent_mech.average_total_unit_flow_rate - vent_mech.average_oa_unit_flow_rate }.sum(0.0)

# Total CFMS
a_tot_sup = q_sup_tot + q_bal_tot + q_erv_hrv_tot + q_cfis_tot
q_tot_sup = q_sup_tot + q_bal_tot + q_erv_hrv_tot + q_cfis_tot
q_tot_exh = q_exh_tot + q_bal_tot + q_erv_hrv_tot
q_unbal = (a_tot_sup - q_tot_exh).abs
q_bal = [q_tot_exh, a_tot_sup].min
q_unbal = q_tot_exh - q_tot_sup
q_bal = [q_tot_exh, q_tot_sup].min

# Calculate effectiveness for all ERV/HRV and store results in a hash
hrv_erv_effectiveness_map = Airflow.calc_hrv_erv_effectiveness(vent_mech_erv_hrv_tot)
Expand Down
26 changes: 6 additions & 20 deletions HPXMLtoOpenStudio/tests/test_defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1450,13 +1450,13 @@ def test_floor_furnaces
hpxml_bldg.heating_systems[0].heating_autosizing_limit = nil
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_floor_furnace_values(default_hpxml_bldg.heating_systems[0], 0, 698, nil, true, 500, 1.0)
_test_default_floor_furnace_values(default_hpxml_bldg.heating_systems[0], 0, nil, nil, true, 500, 1.0)

# Test defaults w/o pilot
hpxml_bldg.heating_systems[0].pilot_light = nil
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_floor_furnace_values(default_hpxml_bldg.heating_systems[0], 0, 698, nil, false, nil, 1.0)
_test_default_floor_furnace_values(default_hpxml_bldg.heating_systems[0], 0, nil, nil, false, nil, 1.0)
end

def test_electric_resistance
Expand Down Expand Up @@ -1552,14 +1552,14 @@ def test_space_heaters
hpxml_bldg.heating_systems[0].heating_capacity = 12345
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_portable_heater_values(default_hpxml_bldg.heating_systems[0], 22, nil, 12345, 1.0)
_test_default_space_heater_values(default_hpxml_bldg.heating_systems[0], 22, nil, 12345, 1.0)

# Test autosizing with factors
hpxml_bldg.heating_systems[0].heating_capacity = nil
hpxml_bldg.heating_systems[0].heating_autosizing_factor = 1.2
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_portable_heater_values(default_hpxml_bldg.heating_systems[0], 22, nil, nil, 1.2)
_test_default_space_heater_values(default_hpxml_bldg.heating_systems[0], 22, nil, nil, 1.2)

# Test defaults
hpxml_bldg.heating_systems[0].fan_watts = nil
Expand All @@ -1568,7 +1568,7 @@ def test_space_heaters
hpxml_bldg.heating_systems[0].heating_autosizing_limit = nil
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_portable_heater_values(default_hpxml_bldg.heating_systems[0], 0, nil, nil, 1.0)
_test_default_space_heater_values(default_hpxml_bldg.heating_systems[0], 0, nil, nil, 1.0)
end

def test_fireplaces
Expand Down Expand Up @@ -4659,7 +4659,7 @@ def _test_default_stove_values(heating_system, fan_watts, heating_airflow_cfm, h
end
end

def _test_default_portable_heater_values(heating_system, fan_watts, heating_airflow_cfm, heating_capacity, heating_autosizing_factor)
def _test_default_space_heater_values(heating_system, fan_watts, heating_airflow_cfm, heating_capacity, heating_autosizing_factor)
assert_equal(fan_watts, heating_system.fan_watts)
if heating_airflow_cfm.nil? # nil implies an autosized value
assert(heating_system.heating_airflow_cfm > 0)
Expand All @@ -4674,20 +4674,6 @@ def _test_default_portable_heater_values(heating_system, fan_watts, heating_airf
end
end

def _test_default_fixed_heater_values(heating_system, fan_watts, heating_airflow_cfm, heating_capacity)
assert_equal(fan_watts, heating_system.fan_watts)
if heating_airflow_cfm.nil? # nil implies an autosized value
assert(heating_system.heating_airflow_cfm > 0)
else
assert_equal(heating_airflow_cfm, heating_system.heating_airflow_cfm)
end
if heating_capacity.nil?
assert(heating_system.heating_capacity > 0)
else
assert_equal(heating_capacity, heating_system.heating_capacity)
end
end

def _test_default_fireplace_values(heating_system, fan_watts, heating_airflow_cfm, heating_capacity, pilot_light, pilot_light_btuh, heating_autosizing_factor)
assert_equal(fan_watts, heating_system.fan_watts)
if heating_airflow_cfm.nil? # nil implies an autosized value
Expand Down
6 changes: 4 additions & 2 deletions HPXMLtoOpenStudio/tests/test_hvac_sizing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -469,10 +469,12 @@ def test_manual_j_residences
assert_in_delta(0, hpxml_bldg.hvac_plant.cdl_sens_floors, block_tol_btuh)
assert_in_delta(0, hpxml_bldg.hvac_plant.cdl_sens_slabs, block_tol_btuh)
assert_in_delta(865, hpxml_bldg.hvac_plant.cdl_sens_ceilings, block_tol_btuh)
# assert_in_delta(825, hpxml_bldg.hvac_plant.cdl_sens_infilvent, block_tol_btuh) Skip due to dehumidifying ventilation
assert_in_delta(0, hpxml_bldg.hvac_plant.cdl_sens_infil, block_tol_btuh)
assert_in_delta(825, hpxml_bldg.hvac_plant.cdl_sens_vent, block_tol_btuh)
assert_in_delta(5541, hpxml_bldg.hvac_plant.cdl_sens_intgains, block_tol_btuh)
assert_in_delta(655, hpxml_bldg.hvac_plant.cdl_lat_ducts, block_tol_btuh)
# assert_in_delta(0, hpxml_bldg.hvac_plant.cdl_lat_infilvent, block_tol_btuh) Skip due to dehumidifying ventilation
# assert_in_delta(0, hpxml_bldg.hvac_plant.cdl_lat_infil, block_tol_btuh) Skip due to dehumidifying ventilation
assert_in_delta(1938, hpxml_bldg.hvac_plant.cdl_lat_vent, block_tol_btuh)
assert_in_delta(800, hpxml_bldg.hvac_plant.cdl_lat_intgains, block_tol_btuh)

# Fixme: Skylight not included so disable for now
Expand Down
3 changes: 2 additions & 1 deletion workflow/tests/ACCA_Examples/Walker_Residence.xml
Original file line number Diff line number Diff line change
Expand Up @@ -985,9 +985,10 @@
<VentilationFans>
<VentilationFan>
<SystemIdentifier id='VentilationFan1'/>
<FanType>supply only</FanType>
<FanType>central fan integrated supply</FanType>
<RatedFlowRate>50.0</RatedFlowRate>
<UsedForWholeBuildingVentilation>true</UsedForWholeBuildingVentilation>
<AttachedToHVACDistributionSystem idref='HVACDistribution1'/>
</VentilationFan>
</VentilationFans>
</MechanicalVentilation>
Expand Down
6 changes: 3 additions & 3 deletions workflow/tests/base_results/results_hers_hvac.csv
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Test Case,HVAC (kWh or therm),HVAC Fan (kWh)
HVAC1a.xml,6277.0,803.89
HVAC1b.xml,4660.12,803.89
HVAC2a.xml,639.47,623.36
HVAC2b.xml,554.21,623.36
HVAC2a.xml,639.46,623.66
HVAC2b.xml,554.19,623.66
HVAC2c.xml,7623.36,1192.21
HVAC2d.xml,4619.68,1192.21
HVAC2e.xml,14618.09,623.36
HVAC2e.xml,14617.8,623.66

0 comments on commit f5b5c0e

Please sign in to comment.