Skip to content

Commit

Permalink
Merge pull request #1816 from NREL/cfis_continued
Browse files Browse the repository at this point in the history
CFIS cleanup
  • Loading branch information
shorowit authored Oct 16, 2024
2 parents 09c7cd1 + bb8d8b0 commit 2dd566f
Show file tree
Hide file tree
Showing 20 changed files with 142 additions and 106 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ __Bugfixes__
- Fixes lower element height for a water heater using the advanced `WaterHeatingSystem/extension/TankModelType=stratified`.
- Fixes possible error for a combi boiler system.
- 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.

## OpenStudio-HPXML v1.8.1

Expand Down
24 changes: 9 additions & 15 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>dbd88505-b00e-4617-9501-2b6c664db124</version_id>
<version_modified>2024-10-13T19:48:28Z</version_modified>
<version_id>b5f6daaa-2d62-4c04-8442-5dd880a2a3eb</version_id>
<version_modified>2024-10-14T15:59:52Z</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>A1DA58C9</checksum>
<checksum>443A48EB</checksum>
</file>
<file>
<filename>battery.rb</filename>
Expand Down Expand Up @@ -327,7 +327,7 @@
<filename>defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>1C554EBA</checksum>
<checksum>DF462CB6</checksum>
</file>
<file>
<filename>energyplus.rb</filename>
Expand Down Expand Up @@ -357,7 +357,7 @@
<filename>hpxml.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>75062717</checksum>
<checksum>D8F0176E</checksum>
</file>
<file>
<filename>hpxml_schema/HPXML.xsd</filename>
Expand All @@ -375,7 +375,7 @@
<filename>hpxml_schematron/EPvalidator.xml</filename>
<filetype>xml</filetype>
<usage_type>resource</usage_type>
<checksum>F77D6962</checksum>
<checksum>5238EC23</checksum>
</file>
<file>
<filename>hpxml_schematron/iso-schematron.xsd</filename>
Expand Down Expand Up @@ -647,17 +647,11 @@
<usage_type>resource</usage_type>
<checksum>93120E27</checksum>
</file>
<file>
<filename>in.schedules.csv</filename>
<filetype>csv</filetype>
<usage_type>test</usage_type>
<checksum>61EDE63A</checksum>
</file>
<file>
<filename>test_airflow.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>3FC8C8A7</checksum>
<checksum>06A02536</checksum>
</file>
<file>
<filename>test_battery.rb</filename>
Expand All @@ -669,7 +663,7 @@
<filename>test_defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>DF7D214E</checksum>
<checksum>05F155DA</checksum>
</file>
<file>
<filename>test_enclosure.rb</filename>
Expand Down Expand Up @@ -741,7 +735,7 @@
<filename>test_validation.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>D7BF36E5</checksum>
<checksum>2E4AE571</checksum>
</file>
<file>
<filename>test_water_heater.rb</filename>
Expand Down
2 changes: 1 addition & 1 deletion HPXMLtoOpenStudio/resources/airflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1921,7 +1921,6 @@ def self.apply_cfis(runner, infil_program, vent_mech_fans, cfis_data, cfis_fan_a
fan_data[:rtf_sensor][object].each do |rtf_sensor|
infil_program.addLine("Set fan_rtf_hvac = fan_rtf_hvac + #{rtf_sensor.name}")
end
infil_program.addLine("Set cfis_fan_w = #{vent_mech.unit_fan_power}") # W

infil_program.addLine('If @ABS(Minute - ZoneTimeStep*60) < 0.1')
infil_program.addLine(" Set #{cfis_data[:t_sum_open_var][vent_mech.id].name} = 0") # New hour, time on summation re-initializes to 0
Expand All @@ -1943,6 +1942,7 @@ def self.apply_cfis(runner, infil_program, vent_mech_fans, cfis_data, cfis_fan_a
infil_program.addLine(" Set #{cfis_data[:f_damper_extra_open_var][vent_mech.id].name} = @Max (cfis_f_damper_open - fan_rtf_hvac) 0.0")
if vent_mech.cfis_addtl_runtime_operating_mode == HPXML::CFISModeAirHandler
# Air handler meets additional runtime requirement
infil_program.addLine("Set cfis_fan_w = #{vent_mech.unit_fan_power}") # W
infil_program.addLine(" Set #{cfis_fan_actuator.name} = #{cfis_fan_actuator.name} + cfis_fan_w * #{cfis_data[:f_damper_extra_open_var][vent_mech.id].name}")
elsif vent_mech.cfis_addtl_runtime_operating_mode == HPXML::CFISModeSupplementalFan
if vent_mech.cfis_supplemental_fan.oa_unit_flow_rate < vent_mech.average_unit_flow_rate
Expand Down
60 changes: 44 additions & 16 deletions HPXMLtoOpenStudio/resources/defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ def self.apply(runner, hpxml, hpxml_bldg, weather, schedules_file: nil, convert_
# Do HVAC sizing after all other defaults have been applied
all_zone_loads, all_space_loads = apply_hvac_sizing(runner, hpxml_bldg, weather)

# Default detailed performance has to be after sizing to have autosized capacity information
# These need to be applied after sizing HVAC capacities/airflows
apply_detailed_performance_data_for_var_speed_systems(hpxml_bldg)
apply_cfis_fan_power(hpxml_bldg)

cleanup_zones_spaces(hpxml_bldg)

Expand Down Expand Up @@ -2734,21 +2735,21 @@ def self.apply_ventilation_fans(hpxml_bldg, weather, eri_version)
vent_fan.rated_flow_rate_isdefaulted = true
end

if vent_fan.fan_power.nil?
fan_w_per_cfm = get_mech_vent_fan_efficiency(vent_fan, eri_version)
vent_fan.fan_power = (vent_fan.flow_rate * fan_w_per_cfm).round(1)
if vent_fan.fan_power.nil? && vent_fan.fan_type != HPXML::MechVentTypeCFIS # CFIS systems have their fan power defaulted later once we have autosized the total blower fan airflow rate
fan_w_per_cfm = get_mech_vent_fan_efficiency(vent_fan)
vent_fan.fan_power = (vent_fan.flow_rate * fan_w_per_cfm).round(2)
vent_fan.fan_power_isdefaulted = true
end
next unless vent_fan.fan_type == HPXML::MechVentTypeCFIS

if vent_fan.cfis_vent_mode_airflow_fraction.nil?
vent_fan.cfis_vent_mode_airflow_fraction = 1.0
vent_fan.cfis_vent_mode_airflow_fraction_isdefaulted = true
end
if vent_fan.cfis_addtl_runtime_operating_mode.nil?
vent_fan.cfis_addtl_runtime_operating_mode = HPXML::CFISModeAirHandler
vent_fan.cfis_addtl_runtime_operating_mode_isdefaulted = true
end
if vent_fan.cfis_vent_mode_airflow_fraction.nil? && (vent_fan.cfis_addtl_runtime_operating_mode == HPXML::CFISModeAirHandler)
vent_fan.cfis_vent_mode_airflow_fraction = 1.0
vent_fan.cfis_vent_mode_airflow_fraction_isdefaulted = true
end
end

# Default kitchen fan
Expand Down Expand Up @@ -2818,6 +2819,40 @@ def self.apply_ventilation_fans(hpxml_bldg, weather, eri_version)
end
end

# Assigns the blower fan power for a CFIS system where the optional input has been omitted.
#
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
# @return [nil]
def self.apply_cfis_fan_power(hpxml_bldg)
hpxml_bldg.ventilation_fans.each do |vent_fan|
next unless vent_fan.used_for_whole_building_ventilation
next unless vent_fan.fan_type == HPXML::MechVentTypeCFIS
next unless vent_fan.cfis_addtl_runtime_operating_mode == HPXML::CFISModeAirHandler
next unless vent_fan.fan_power.nil?

hvac_systems = vent_fan.distribution_system.hvac_systems
fan_w_per_cfm = hvac_systems[0].fan_watts_per_cfm

# Get max blower airflow rate
blower_flow_rate = nil
hvac_systems.each do |hvac_system|
if hvac_system.respond_to?(:heating_airflow_cfm) && hvac_system.heating_airflow_cfm > blower_flow_rate.to_f
blower_flow_rate = hvac_system.heating_airflow_cfm
end
if hvac_system.respond_to?(:cooling_airflow_cfm) && hvac_system.cooling_airflow_cfm > blower_flow_rate.to_f
blower_flow_rate = hvac_system.cooling_airflow_cfm
end
end
fail 'Unexpected error.' if blower_flow_rate.to_f == 0

# Calculate blower airflow rate in vent only mode
blower_flow_rate *= vent_fan.cfis_vent_mode_airflow_fraction

vent_fan.fan_power = (blower_flow_rate * fan_w_per_cfm).round(2)
vent_fan.fan_power_isdefaulted = true
end
end

# Assigns default values for omitted optional inputs in the HPXML::WaterHeatingSystem objects
#
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
Expand Down Expand Up @@ -4664,9 +4699,8 @@ def self.get_mech_vent_flow_rate_for_vent_fan(hpxml_bldg, vent_fan, weather, eri
# Gets the default whole-home mechanical ventilation fan efficiency.
#
# @param vent_fan [HPXML::VentilationFan] The HPXML ventilation fan of interest
# @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions
# @return [Double] Fan efficiency (W/cfm)
def self.get_mech_vent_fan_efficiency(vent_fan, eri_version)
def self.get_mech_vent_fan_efficiency(vent_fan)
# Returns fan power in W/cfm, based on ANSI 301
if vent_fan.is_shared_system
return 1.00 # Table 4.2.2(1) Note (n)
Expand All @@ -4676,12 +4710,6 @@ def self.get_mech_vent_fan_efficiency(vent_fan, eri_version)
return 0.70
elsif [HPXML::MechVentTypeERV, HPXML::MechVentTypeHRV].include? vent_fan.fan_type
return 1.00
elsif [HPXML::MechVentTypeCFIS].include? vent_fan.fan_type
if Constants::ERIVersions.index(eri_version) >= Constants::ERIVersions.index('2022')
return 0.58
else
return 0.50
end
else
fail "Unexpected fan_type: '#{fan_type}'."
end
Expand Down
5 changes: 5 additions & 0 deletions HPXMLtoOpenStudio/resources/hpxml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8211,6 +8211,11 @@ def is_cfis_supplemental_fan
#
# @return [nil]
def delete
if is_cfis_supplemental_fan
@parent_object.ventilation_fans.each do |vent_fan|
vent_fan.cfis_supplemental_fan_idref = nil if vent_fan.cfis_supplemental_fan_idref == @id
end
end
@parent_object.ventilation_fans.delete(self)
end

Expand Down
27 changes: 19 additions & 8 deletions HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2025,30 +2025,41 @@
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:MechanicalVentilation/h:VentilationFans/h:VentilationFan[h:UsedForWholeBuildingVentilation="true" and h:FanType="central fan integrated supply"]'>
<sch:assert role='ERROR' test='count(h:IsSharedSystem[text()="true"]) = 0'>Expected 0 element(s) for xpath: IsSharedSystem[text()="true"]</sch:assert>
<sch:assert role='ERROR' test='count(h:CFISControls/h:AdditionalRuntimeOperatingMode) &lt;= 1'>Expected 0 or 1 element(s) for xpath: CFISControls/AdditionalRuntimeOperatingMode</sch:assert>
<sch:assert role='ERROR' test='h:CFISControls/h:AdditionalRuntimeOperatingMode[text()="air handler fan" or text()="supplemental fan" or text()="none"] or not(h:CFISControls/h:AdditionalRuntimeOperatingMode)'>Expected CFISControls/AdditionalRuntimeOperatingMode to be 'air handler fan' or 'supplemental fan' or 'none'</sch:assert> <!-- See [MechanicalVentilationType=CFISWithSupplementalFan] -->
<sch:assert role='ERROR' test='h:CFISControls/h:AdditionalRuntimeOperatingMode[text()="air handler fan" or text()="supplemental fan" or text()="none"] or not(h:CFISControls/h:AdditionalRuntimeOperatingMode)'>Expected CFISControls/AdditionalRuntimeOperatingMode to be 'air handler fan' or 'supplemental fan' or 'none'</sch:assert> <!-- See [CFISAdditionalRuntimeMode=AirHandlerFan] or [CFISAdditionalRuntimeMode=SupplementalFan] or [CFISAdditionalRuntimeMode=None] -->
<sch:assert role='ERROR' test='count(h:RatedFlowRate) + count(h:CalculatedFlowRate) + count(h:TestedFlowRate) + count(h:DeliveredVentilation) &gt;= 0'>Expected 0 or more element(s) for xpath: RatedFlowRate | CalculatedFlowRate | TestedFlowRate | DeliveredVentilation</sch:assert>
<sch:assert role='ERROR' test='count(h:HoursInOperation) &lt;= 1'>Expected 0 or 1 element(s) for xpath: HoursInOperation</sch:assert>
<sch:assert role='ERROR' test='count(h:TotalRecoveryEfficiency) + count(h:AdjustedTotalRecoveryEfficiency) = 0'>Expected 0 element(s) for xpath: TotalRecoveryEfficiency | AdjustedTotalRecoveryEfficiency</sch:assert>
<sch:assert role='ERROR' test='count(h:SensibleRecoveryEfficiency) + count(h:AdjustedSensibleRecoveryEfficiency) = 0'>Expected 0 element(s) for xpath: SensibleRecoveryEfficiency | AdjustedSensibleRecoveryEfficiency</sch:assert>
<sch:assert role='ERROR' test='count(h:FanPower) &lt;= 1'>Expected 0 or 1 element(s) for xpath: FanPower</sch:assert>
<sch:assert role='ERROR' test='count(h:AttachedToHVACDistributionSystem) = 1'>Expected 1 element(s) for xpath: AttachedToHVACDistributionSystem</sch:assert>
</sch:rule>
</sch:pattern>

<sch:pattern>
<sch:title>[CFISAdditionalRuntimeMode=AirHandlerFan]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:MechanicalVentilation/h:VentilationFans/h:VentilationFan[h:UsedForWholeBuildingVentilation="true" and h:FanType="central fan integrated supply" and h:CFISControls/h:AdditionalRuntimeOperatingMode="air handler fan"]'>
<sch:assert role='ERROR' test='count(h:CFISControls/h:SupplementalFan) = 0'>Expected 0 element(s) for xpath: CFISControls/SupplementalFan</sch:assert>
<sch:assert role='ERROR' test='count(h:FanPower) &lt;= 1'>Expected 0 or 1 element(s) for xpath: FanPower</sch:assert>
<sch:assert role='ERROR' test='count(h:extension/h:VentilationOnlyModeAirflowFraction) &lt;= 1'>Expected 0 or 1 element(s) for xpath: extension/VentilationOnlyModeAirflowFraction</sch:assert>
<sch:assert role='ERROR' test='number(h:extension/h:VentilationOnlyModeAirflowFraction) &gt;= 0 or not(h:extension/h:VentilationOnlyModeAirflowFraction)'>Expected extension/VentilationOnlyModeAirflowFraction to be greater than or equal to 0</sch:assert>
<sch:assert role='ERROR' test='number(h:extension/h:VentilationOnlyModeAirflowFraction) &lt;= 1 or not(h:extension/h:VentilationOnlyModeAirflowFraction)'>Expected extension/VentilationOnlyModeAirflowFraction to be less than or equal to 1</sch:assert>
</sch:rule>
</sch:pattern>

<sch:pattern>
<sch:title>[MechanicalVentilationType=CFISWithSupplementalFan]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:MechanicalVentilation/h:VentilationFans/h:VentilationFan[h:UsedForWholeBuildingVentilation="true" and h:FanType="central fan integrated supply"]/h:CFISControls[h:AdditionalRuntimeOperatingMode="supplemental fan"]'>
<sch:assert role='ERROR' test='count(h:SupplementalFan) = 1'>Expected 1 element(s) for xpath: SupplementalFan</sch:assert>
<sch:title>[CFISAdditionalRuntimeMode=SupplementalFan]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:MechanicalVentilation/h:VentilationFans/h:VentilationFan[h:UsedForWholeBuildingVentilation="true" and h:FanType="central fan integrated supply" and h:CFISControls/h:AdditionalRuntimeOperatingMode="supplemental fan"]'>
<sch:assert role='ERROR' test='count(h:CFISControls/h:SupplementalFan) = 1'>Expected 1 element(s) for xpath: CFISControls/SupplementalFan</sch:assert>
<sch:assert role='ERROR' test='count(h:FanPower) = 0'>Expected 0 element(s) for xpath: FanPower</sch:assert>
<sch:assert role='ERROR' test='count(h:extension/h:VentilationOnlyModeAirflowFraction) = 0'>Expected 0 element(s) for xpath: extension/VentilationOnlyModeAirflowFraction</sch:assert>
</sch:rule>
</sch:pattern>

<sch:pattern>
<sch:title>[MechanicalVentilationType=CFISWithoutSupplementalFan]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:MechanicalVentilation/h:VentilationFans/h:VentilationFan[h:UsedForWholeBuildingVentilation="true" and h:FanType="central fan integrated supply"]/h:CFISControls[h:AdditionalRuntimeOperatingMode!="supplemental fan"]'>
<sch:assert role='ERROR' test='count(h:SupplementalFan) = 0'>Expected 0 element(s) for xpath: SupplementalFan</sch:assert>
<sch:title>[CFISAdditionalRuntimeMode=None]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:MechanicalVentilation/h:VentilationFans/h:VentilationFan[h:UsedForWholeBuildingVentilation="true" and h:FanType="central fan integrated supply" and h:CFISControls/h:AdditionalRuntimeOperatingMode="none"]'>
<sch:assert role='ERROR' test='count(h:CFISControls/h:SupplementalFan) = 0'>Expected 0 element(s) for xpath: CFISControls/SupplementalFan</sch:assert>
<sch:assert role='ERROR' test='count(h:FanPower) = 0'>Expected 0 element(s) for xpath: FanPower</sch:assert>
<sch:assert role='ERROR' test='count(h:extension/h:VentilationOnlyModeAirflowFraction) = 0'>Expected 0 element(s) for xpath: extension/VentilationOnlyModeAirflowFraction</sch:assert>
</sch:rule>
</sch:pattern>

Expand Down
4 changes: 1 addition & 3 deletions HPXMLtoOpenStudio/tests/test_airflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,6 @@ 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_power = vent_fan.fan_power
vent_fan_mins = vent_fan.hours_in_operation / 24.0 * 60.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
Expand All @@ -412,7 +411,6 @@ def test_mechanical_ventilation_cfis_with_supplemental_fan
assert_in_epsilon(suppl_vent_fan_cfm, UnitConversions.convert(program_values['cfis_suppl_Q_oa'].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['cfis_fan_w'].sum, 0.01)
assert_in_epsilon(suppl_vent_fan_power, program_values['cfis_suppl_fan_w'].sum, 0.01)
assert_in_epsilon(vent_fan_mins, program_values['cfis_t_min_hr_open'].sum, 0.01)
assert_in_epsilon(0.0, UnitConversions.convert(program_values['Qrange'].sum, 'm^3/s', 'cfm'), 0.01)
Expand Down Expand Up @@ -498,7 +496,7 @@ def test_multiple_mechvent
vent_fan_power_ervhrv = vent_fan_ervhrv.map { |f| f.average_unit_fan_power }.sum(0.0)
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.map { |f| f.fan_power }.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)

# total mech vent fan power excluding cfis
Expand Down
Loading

0 comments on commit 2dd566f

Please sign in to comment.