Skip to content

Commit 76951e1

Browse files
authored
Merge pull request #1868 from NREL/cfis_refactor
Bugfix for CFIS systems w/ supplemental fan and sub-hourly timesteps
2 parents 9e0f85f + 3d7ff58 commit 76951e1

15 files changed

+1289
-95
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ __Bugfixes__
5353
- Fixes error if modeling a ground-to-air heat pump with a separate backup heating system.
5454
- Fixes default CFIS fan power during ventilation only mode.
5555
- Fixes a bug that potentially oversizes heat pumps when detailed performance capacity fractions are provided.
56+
- For a CFIS system with a supplemental fan, fixes supplemental fan runtime when using sub-hourly timesteps.
5657

5758
## OpenStudio-HPXML v1.8.1
5859

HPXMLtoOpenStudio/measure.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<schema_version>3.1</schema_version>
44
<name>hpxm_lto_openstudio</name>
55
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
6-
<version_id>a34fa4e4-deee-4e59-8f0b-8c1a2c574cdc</version_id>
7-
<version_modified>2024-10-23T18:46:26Z</version_modified>
6+
<version_id>64c3bdea-b4b3-4254-9b2a-23987ae4e9f3</version_id>
7+
<version_modified>2024-10-25T00:51:54Z</version_modified>
88
<xml_checksum>D8922A73</xml_checksum>
99
<class_name>HPXMLtoOpenStudio</class_name>
1010
<display_name>HPXML to OpenStudio Translator</display_name>
@@ -189,7 +189,7 @@
189189
<filename>airflow.rb</filename>
190190
<filetype>rb</filetype>
191191
<usage_type>resource</usage_type>
192-
<checksum>F2AD4FE1</checksum>
192+
<checksum>87ABF972</checksum>
193193
</file>
194194
<file>
195195
<filename>battery.rb</filename>
@@ -207,7 +207,7 @@
207207
<filename>constants.rb</filename>
208208
<filetype>rb</filetype>
209209
<usage_type>resource</usage_type>
210-
<checksum>8660B5E9</checksum>
210+
<checksum>22E067E1</checksum>
211211
</file>
212212
<file>
213213
<filename>constructions.rb</filename>
@@ -651,7 +651,7 @@
651651
<filename>test_airflow.rb</filename>
652652
<filetype>rb</filetype>
653653
<usage_type>test</usage_type>
654-
<checksum>D4E42045</checksum>
654+
<checksum>4366CDCD</checksum>
655655
</file>
656656
<file>
657657
<filename>test_battery.rb</filename>

HPXMLtoOpenStudio/resources/airflow.rb

Lines changed: 108 additions & 75 deletions
Large diffs are not rendered by default.

HPXMLtoOpenStudio/resources/constants.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ module Constants
8686

8787
# Arrays/Maps
8888
ERIVersions = ['2014', '2014A', '2014AE', '2014AEG', '2019', '2019A',
89-
'2019AB', '2019ABC', '2019ABCD', '2022', '2022C']
89+
'2019AB', '2019ABC', '2019ABCD', '2022', '2022C', '2022CE']
9090
IECCZones = ['1A', '1B', '1C', '2A', '2B', '2C', '3A', '3B', '3C',
9191
'4A', '4B', '4C', '5A', '5B', '5C', '6A', '6B', '6C', '7', '8']
9292
StateCodesMap = { 'AK' => 'Alaska',

HPXMLtoOpenStudio/tests/test_airflow.rb

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,15 @@ def test_mechanical_ventilation_cfis
377377
vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation }
378378
vent_fan_cfm = vent_fan.oa_unit_flow_rate
379379
vent_fan_power = vent_fan.fan_power
380-
vent_fan_mins = vent_fan.hours_in_operation / 24.0 * 60.0
380+
vent_fan_operation = vent_fan.hours_in_operation / 24.0
381381

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

408408
# Check infiltration/ventilation program
409409
program_values = get_ems_values(model.getEnergyManagementSystemPrograms, "#{Constants::ObjectTypeInfiltration} program")
410-
assert_in_epsilon(vent_fan_cfm, UnitConversions.convert(program_values['Q_duct_oa'].sum, 'm^3/s', 'cfm'), 0.01)
411-
assert_in_epsilon(suppl_vent_fan_cfm, UnitConversions.convert(program_values['suppl_Q_oa'].sum, 'm^3/s', 'cfm'), 0.01)
410+
assert_in_epsilon(vent_fan_cfm, UnitConversions.convert(program_values['oa_cfm_ah'].sum, 'm^3/s', 'cfm'), 0.01)
411+
assert_in_epsilon(suppl_vent_fan_cfm, UnitConversions.convert(program_values['oa_cfm_suppl'].sum, 'm^3/s', 'cfm'), 0.01)
412412
assert_in_epsilon(0.0, UnitConversions.convert(program_values['QWHV_sup'].sum, 'm^3/s', 'cfm'), 0.01)
413413
assert_in_epsilon(0.0, UnitConversions.convert(program_values['QWHV_exh'].sum, 'm^3/s', 'cfm'), 0.01)
414414
assert_in_epsilon(suppl_vent_fan_power, program_values['suppl_fan_w'].sum, 0.01)
415-
assert_in_epsilon(vent_fan_mins, program_values['t_min_hr_open'].sum, 0.01)
415+
assert_in_epsilon(vent_fan_operation, program_values['f_operation'].sum, 0.01)
416416
assert_in_epsilon(0.0, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)
417417
assert_in_epsilon(0.0, UnitConversions.convert(program_values['Qbath'].sum, 'm^3/s', 'cfm'), 0.01)
418418
# Load actuators
@@ -497,7 +497,7 @@ def test_multiple_mechvent
497497
vent_fan_cfis = whole_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS }
498498
vent_fan_cfm_cfis = vent_fan_cfis.map { |f| f.oa_unit_flow_rate }.sum(0.0)
499499
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)
500-
vent_fan_mins_cfis = vent_fan_cfis.map { |f| f.hours_in_operation / 24.0 * 60.0 }.sum(0.0)
500+
vent_fan_operation_cfis = vent_fan_cfis.map { |f| f.hours_in_operation / 24.0 }.sum(0.0)
501501

502502
# total mech vent fan power excluding cfis
503503
total_mechvent_pow = vent_fan_power_sup + vent_fan_power_exh + vent_fan_power_bal + vent_fan_power_ervhrv
@@ -511,7 +511,7 @@ def test_multiple_mechvent
511511
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)
512512
assert_in_epsilon(kitchen_fan_cfm, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)
513513
assert_in_epsilon(bath_fan_cfm, UnitConversions.convert(program_values['Qbath'].sum, 'm^3/s', 'cfm'), 0.01)
514-
assert_in_epsilon(vent_fan_cfm_cfis, UnitConversions.convert(program_values['Q_duct_oa'].sum, 'm^3/s', 'cfm'), 0.01)
514+
assert_in_epsilon(vent_fan_cfm_cfis, UnitConversions.convert(program_values['oa_cfm_ah'].sum, 'm^3/s', 'cfm'), 0.01)
515515
# Fan power/load implementation
516516
assert_equal(1, get_eed_for_ventilation(model, Constants::ObjectTypeMechanicalVentilationHouseFan).size)
517517
assert_in_epsilon(total_mechvent_pow, get_eed_for_ventilation(model, Constants::ObjectTypeMechanicalVentilationHouseFan)[0].designLevel.get, 0.01)
@@ -528,7 +528,7 @@ def test_multiple_mechvent
528528
assert_in_epsilon(1.0, bath_fan_eeds[0].fractionLost, 0.01)
529529
assert_in_epsilon(1.0, bath_fan_eeds[1].fractionLost, 0.01)
530530
# CFIS minutes
531-
assert_in_epsilon(vent_fan_mins_cfis, program_values['t_min_hr_open'].sum, 0.01)
531+
assert_in_epsilon(vent_fan_operation_cfis, program_values['f_operation'].sum, 0.01)
532532
# Load actuators
533533
assert_equal(1, get_oed_for_ventilation(model, "#{Constants::ObjectTypeMechanicalVentilationHouseFan} sensible load").size)
534534
assert_equal(1, get_oed_for_ventilation(model, "#{Constants::ObjectTypeMechanicalVentilationHouseFan} latent load").size)
@@ -557,7 +557,7 @@ def test_shared_mechvent_multiple
557557
# CFIS
558558
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)
559559
vent_fans_pow_cfis = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS }.map { |f| f.unit_fan_power }.sum(0.0)
560-
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)
560+
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)
561561

562562
# Load and energy eed
563563
assert_equal(1, get_oed_for_ventilation(model, "#{Constants::ObjectTypeMechanicalVentilationHouseFan} sensible load").size)
@@ -574,8 +574,8 @@ def test_shared_mechvent_multiple
574574
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)
575575
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)
576576
assert_in_epsilon(vent_fans_pow_cfis, program_values['ah_fan_w'].sum, 0.01)
577-
assert_in_epsilon(vent_fans_mins_cfis, program_values['t_min_hr_open'].sum, 0.01)
578-
assert_in_epsilon(vent_fans_cfm_oa_cfis, UnitConversions.convert(program_values['Q_duct_oa'].sum, 'm^3/s', 'cfm'), 0.01)
577+
assert_in_epsilon(vent_fans_mins_cfis, program_values['f_operation'].sum, 0.01)
578+
assert_in_epsilon(vent_fans_cfm_oa_cfis, UnitConversions.convert(program_values['oa_cfm_ah'].sum, 'm^3/s', 'cfm'), 0.01)
579579
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)
580580
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)
581581
assert_in_epsilon(0, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)

tasks.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2282,6 +2282,7 @@ def apply_hpxml_modification_sample_files(hpxml_path, hpxml)
22822282
elsif ['base-mechvent-cfis-no-outdoor-air-control.xml'].include? hpxml_file
22832283
hpxml_bldg.ventilation_fans[0].cfis_has_outdoor_air_control = false
22842284
elsif ['base-mechvent-cfis-supplemental-fan-exhaust.xml',
2285+
'base-mechvent-cfis-supplemental-fan-exhaust-15-mins.xml',
22852286
'base-mechvent-cfis-supplemental-fan-supply.xml',
22862287
'base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml'].include? hpxml_file
22872288
hpxml_bldg.ventilation_fans.add(id: "VentilationFan#{hpxml_bldg.ventilation_fans.size + 1}",

workflow/hpxml_inputs.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3181,6 +3181,10 @@
31813181
"mech_vent_fan_power": 300,
31823182
"mech_vent_num_units_served": 1
31833183
},
3184+
"sample_files/base-mechvent-cfis-15-mins.xml": {
3185+
"parent_hpxml": "sample_files/base-mechvent-cfis.xml",
3186+
"simulation_control_timestep": 15
3187+
},
31843188
"sample_files/base-mechvent-cfis-airflow-fraction-zero.xml": {
31853189
"parent_hpxml": "sample_files/base-mechvent-cfis.xml"
31863190
},
@@ -3218,6 +3222,10 @@
32183222
"parent_hpxml": "sample_files/base-mechvent-cfis.xml",
32193223
"mech_vent_fan_power": null
32203224
},
3225+
"sample_files/base-mechvent-cfis-supplemental-fan-exhaust-15-mins.xml": {
3226+
"parent_hpxml": "sample_files/base-mechvent-cfis-supplemental-fan-exhaust.xml",
3227+
"simulation_control_timestep": 15
3228+
},
32213229
"sample_files/base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml": {
32223230
"parent_hpxml": "sample_files/base-mechvent-cfis-supplemental-fan-exhaust.xml"
32233231
},

workflow/run_simulation.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def run_workflow(basedir, rundir, hpxml, debug, skip_validation, add_comp_loads,
179179
end
180180

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

0 commit comments

Comments
 (0)