Skip to content

Commit

Permalink
Merge pull request #1868 from NREL/cfis_refactor
Browse files Browse the repository at this point in the history
Bugfix for CFIS systems w/ supplemental fan and sub-hourly timesteps
  • Loading branch information
shorowit authored Oct 25, 2024
2 parents 9e0f85f + 3d7ff58 commit 76951e1
Show file tree
Hide file tree
Showing 15 changed files with 1,289 additions and 95 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ __Bugfixes__
- Fixes error if modeling a ground-to-air heat pump with a separate backup heating system.
- Fixes default CFIS fan power during ventilation only mode.
- Fixes a bug that potentially oversizes heat pumps when detailed performance capacity fractions are provided.
- For a CFIS system with a supplemental fan, fixes supplemental fan runtime when using sub-hourly timesteps.

## OpenStudio-HPXML v1.8.1

Expand Down
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>a34fa4e4-deee-4e59-8f0b-8c1a2c574cdc</version_id>
<version_modified>2024-10-23T18:46:26Z</version_modified>
<version_id>64c3bdea-b4b3-4254-9b2a-23987ae4e9f3</version_id>
<version_modified>2024-10-25T00:51:54Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -189,7 +189,7 @@
<filename>airflow.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>F2AD4FE1</checksum>
<checksum>87ABF972</checksum>
</file>
<file>
<filename>battery.rb</filename>
Expand All @@ -207,7 +207,7 @@
<filename>constants.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>8660B5E9</checksum>
<checksum>22E067E1</checksum>
</file>
<file>
<filename>constructions.rb</filename>
Expand Down Expand Up @@ -651,7 +651,7 @@
<filename>test_airflow.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>D4E42045</checksum>
<checksum>4366CDCD</checksum>
</file>
<file>
<filename>test_battery.rb</filename>
Expand Down
183 changes: 108 additions & 75 deletions HPXMLtoOpenStudio/resources/airflow.rb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion HPXMLtoOpenStudio/resources/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ module Constants

# Arrays/Maps
ERIVersions = ['2014', '2014A', '2014AE', '2014AEG', '2019', '2019A',
'2019AB', '2019ABC', '2019ABCD', '2022', '2022C']
'2019AB', '2019ABC', '2019ABCD', '2022', '2022C', '2022CE']
IECCZones = ['1A', '1B', '1C', '2A', '2B', '2C', '3A', '3B', '3C',
'4A', '4B', '4C', '5A', '5B', '5C', '6A', '6B', '6C', '7', '8']
StateCodesMap = { 'AK' => 'Alaska',
Expand Down
26 changes: 13 additions & 13 deletions HPXMLtoOpenStudio/tests/test_airflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -377,15 +377,15 @@ def test_mechanical_ventilation_cfis
vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation }
vent_fan_cfm = vent_fan.oa_unit_flow_rate
vent_fan_power = vent_fan.fan_power
vent_fan_mins = vent_fan.hours_in_operation / 24.0 * 60.0
vent_fan_operation = vent_fan.hours_in_operation / 24.0

# Check infiltration/ventilation program
program_values = get_ems_values(model.getEnergyManagementSystemPrograms, "#{Constants::ObjectTypeInfiltration} program")
assert_in_epsilon(vent_fan_cfm, UnitConversions.convert(program_values['Q_duct_oa'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fan_cfm, UnitConversions.convert(program_values['oa_cfm_ah'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['QWHV_sup'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['QWHV_exh'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fan_power, program_values['ah_fan_w'].sum, 0.01)
assert_in_epsilon(vent_fan_mins, program_values['t_min_hr_open'].sum, 0.01)
assert_in_epsilon(vent_fan_operation, program_values['f_operation'].sum, 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['Qbath'].sum, 'm^3/s', 'cfm'), 0.01)
# Load actuators
Expand All @@ -401,18 +401,18 @@ def test_mechanical_ventilation_cfis_with_supplemental_fan
# Get HPXML values
vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation }
vent_fan_cfm = vent_fan.oa_unit_flow_rate
vent_fan_mins = vent_fan.hours_in_operation / 24.0 * 60.0
vent_fan_operation = vent_fan.hours_in_operation / 24.0
suppl_vent_fan_cfm = vent_fan.cfis_supplemental_fan.oa_unit_flow_rate
suppl_vent_fan_power = vent_fan.cfis_supplemental_fan.fan_power

# Check infiltration/ventilation program
program_values = get_ems_values(model.getEnergyManagementSystemPrograms, "#{Constants::ObjectTypeInfiltration} program")
assert_in_epsilon(vent_fan_cfm, UnitConversions.convert(program_values['Q_duct_oa'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(suppl_vent_fan_cfm, UnitConversions.convert(program_values['suppl_Q_oa'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fan_cfm, UnitConversions.convert(program_values['oa_cfm_ah'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(suppl_vent_fan_cfm, UnitConversions.convert(program_values['oa_cfm_suppl'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['QWHV_sup'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['QWHV_exh'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(suppl_vent_fan_power, program_values['suppl_fan_w'].sum, 0.01)
assert_in_epsilon(vent_fan_mins, program_values['t_min_hr_open'].sum, 0.01)
assert_in_epsilon(vent_fan_operation, program_values['f_operation'].sum, 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['Qbath'].sum, 'm^3/s', 'cfm'), 0.01)
# Load actuators
Expand Down Expand Up @@ -497,7 +497,7 @@ def test_multiple_mechvent
vent_fan_cfis = whole_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS }
vent_fan_cfm_cfis = vent_fan_cfis.map { |f| f.oa_unit_flow_rate }.sum(0.0)
vent_fan_power_cfis = vent_fan_cfis.select { |f| f.cfis_addtl_runtime_operating_mode == HPXML::CFISModeAirHandler }.map { |f| f.fan_power }.sum(0.0)
vent_fan_mins_cfis = vent_fan_cfis.map { |f| f.hours_in_operation / 24.0 * 60.0 }.sum(0.0)
vent_fan_operation_cfis = vent_fan_cfis.map { |f| f.hours_in_operation / 24.0 }.sum(0.0)

# total mech vent fan power excluding cfis
total_mechvent_pow = vent_fan_power_sup + vent_fan_power_exh + vent_fan_power_bal + vent_fan_power_ervhrv
Expand All @@ -511,7 +511,7 @@ def test_multiple_mechvent
assert_in_epsilon(vent_fan_cfm_exh + vent_fan_cfm_bal + vent_fan_cfm_ervhrv, UnitConversions.convert(program_values['QWHV_exh'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(kitchen_fan_cfm, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(bath_fan_cfm, UnitConversions.convert(program_values['Qbath'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fan_cfm_cfis, UnitConversions.convert(program_values['Q_duct_oa'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fan_cfm_cfis, UnitConversions.convert(program_values['oa_cfm_ah'].sum, 'm^3/s', 'cfm'), 0.01)
# Fan power/load implementation
assert_equal(1, get_eed_for_ventilation(model, Constants::ObjectTypeMechanicalVentilationHouseFan).size)
assert_in_epsilon(total_mechvent_pow, get_eed_for_ventilation(model, Constants::ObjectTypeMechanicalVentilationHouseFan)[0].designLevel.get, 0.01)
Expand All @@ -528,7 +528,7 @@ def test_multiple_mechvent
assert_in_epsilon(1.0, bath_fan_eeds[0].fractionLost, 0.01)
assert_in_epsilon(1.0, bath_fan_eeds[1].fractionLost, 0.01)
# CFIS minutes
assert_in_epsilon(vent_fan_mins_cfis, program_values['t_min_hr_open'].sum, 0.01)
assert_in_epsilon(vent_fan_operation_cfis, program_values['f_operation'].sum, 0.01)
# Load actuators
assert_equal(1, get_oed_for_ventilation(model, "#{Constants::ObjectTypeMechanicalVentilationHouseFan} sensible load").size)
assert_equal(1, get_oed_for_ventilation(model, "#{Constants::ObjectTypeMechanicalVentilationHouseFan} latent load").size)
Expand Down Expand Up @@ -557,7 +557,7 @@ def test_shared_mechvent_multiple
# CFIS
vent_fans_cfm_oa_cfis = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS }.map { |f| f.oa_unit_flow_rate }.sum(0.0)
vent_fans_pow_cfis = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS }.map { |f| f.unit_fan_power }.sum(0.0)
vent_fans_mins_cfis = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS }.map { |f| f.hours_in_operation / 24.0 * 60.0 }.sum(0.0)
vent_fans_mins_cfis = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS }.map { |f| f.hours_in_operation / 24.0 }.sum(0.0)

# Load and energy eed
assert_equal(1, get_oed_for_ventilation(model, "#{Constants::ObjectTypeMechanicalVentilationHouseFan} sensible load").size)
Expand All @@ -574,8 +574,8 @@ def test_shared_mechvent_multiple
assert_in_epsilon((vent_fans_cfm_oa_preheat_sup + vent_fans_cfm_oa_preheat_bal + vent_fans_cfm_oa_preheat_ervhrv), UnitConversions.convert(program_values['Qpreheat'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon((vent_fans_cfm_oa_precool_sup + vent_fans_cfm_oa_precool_bal + vent_fans_cfm_oa_precool_ervhrv), UnitConversions.convert(program_values['Qprecool'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fans_pow_cfis, program_values['ah_fan_w'].sum, 0.01)
assert_in_epsilon(vent_fans_mins_cfis, program_values['t_min_hr_open'].sum, 0.01)
assert_in_epsilon(vent_fans_cfm_oa_cfis, UnitConversions.convert(program_values['Q_duct_oa'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fans_mins_cfis, program_values['f_operation'].sum, 0.01)
assert_in_epsilon(vent_fans_cfm_oa_cfis, UnitConversions.convert(program_values['oa_cfm_ah'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fans_cfm_tot_sup + vent_fans_cfm_tot_ervhrvbal, UnitConversions.convert(program_values['QWHV_sup'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(vent_fans_cfm_tot_exh + vent_fans_cfm_tot_ervhrvbal, UnitConversions.convert(program_values['QWHV_exh'].sum, 'm^3/s', 'cfm'), 0.01)
assert_in_epsilon(0, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)
Expand Down
1 change: 1 addition & 0 deletions tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2282,6 +2282,7 @@ def apply_hpxml_modification_sample_files(hpxml_path, hpxml)
elsif ['base-mechvent-cfis-no-outdoor-air-control.xml'].include? hpxml_file
hpxml_bldg.ventilation_fans[0].cfis_has_outdoor_air_control = false
elsif ['base-mechvent-cfis-supplemental-fan-exhaust.xml',
'base-mechvent-cfis-supplemental-fan-exhaust-15-mins.xml',
'base-mechvent-cfis-supplemental-fan-supply.xml',
'base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml'].include? hpxml_file
hpxml_bldg.ventilation_fans.add(id: "VentilationFan#{hpxml_bldg.ventilation_fans.size + 1}",
Expand Down
8 changes: 8 additions & 0 deletions workflow/hpxml_inputs.json
Original file line number Diff line number Diff line change
Expand Up @@ -3181,6 +3181,10 @@
"mech_vent_fan_power": 300,
"mech_vent_num_units_served": 1
},
"sample_files/base-mechvent-cfis-15-mins.xml": {
"parent_hpxml": "sample_files/base-mechvent-cfis.xml",
"simulation_control_timestep": 15
},
"sample_files/base-mechvent-cfis-airflow-fraction-zero.xml": {
"parent_hpxml": "sample_files/base-mechvent-cfis.xml"
},
Expand Down Expand Up @@ -3218,6 +3222,10 @@
"parent_hpxml": "sample_files/base-mechvent-cfis.xml",
"mech_vent_fan_power": null
},
"sample_files/base-mechvent-cfis-supplemental-fan-exhaust-15-mins.xml": {
"parent_hpxml": "sample_files/base-mechvent-cfis-supplemental-fan-exhaust.xml",
"simulation_control_timestep": 15
},
"sample_files/base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml": {
"parent_hpxml": "sample_files/base-mechvent-cfis-supplemental-fan-exhaust.xml"
},
Expand Down
2 changes: 1 addition & 1 deletion workflow/run_simulation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def run_workflow(basedir, rundir, hpxml, debug, skip_validation, add_comp_loads,
end

options[:debug] = false
opts.on('-d', '--debug', 'Generate additional OpenStudio/EnergyPlus output files for debugging') do |_t|
opts.on('-d', '--debug', 'Generate additional OpenStudio and EnergyPlus files for debugging') do |_t|
options[:debug] = true
end

Expand Down
Loading

0 comments on commit 76951e1

Please sign in to comment.