From 1b5424919fd999959ec74ee4e9bfa84b5063d5a1 Mon Sep 17 00:00:00 2001 From: Scott Horowitz Date: Tue, 22 Oct 2024 12:47:17 -0600 Subject: [PATCH] First pass on new SupplementalFanRunsWithAirHandlerFan input for CFIS systems. --- HPXMLtoOpenStudio/measure.rb | 2 +- HPXMLtoOpenStudio/measure.xml | 16 +- HPXMLtoOpenStudio/resources/airflow.rb | 21 +- HPXMLtoOpenStudio/resources/defaults.rb | 4 + HPXMLtoOpenStudio/resources/hpxml.rb | 75 +-- .../hpxml_schematron/EPvalidator.xml | 3 + HPXMLtoOpenStudio/tests/test_defaults.rb | 22 +- docs/source/workflow_inputs.rst | 4 + tasks.rb | 10 +- workflow/hpxml_inputs.json | 3 + ...-supplemental-fan-exhaust-synchronized.xml | 577 ++++++++++++++++++ 11 files changed, 681 insertions(+), 56 deletions(-) create mode 100644 workflow/sample_files/base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml diff --git a/HPXMLtoOpenStudio/measure.rb b/HPXMLtoOpenStudio/measure.rb index 11c5b9e10f..0af0cb8d8a 100644 --- a/HPXMLtoOpenStudio/measure.rb +++ b/HPXMLtoOpenStudio/measure.rb @@ -150,7 +150,7 @@ def run(model, runner, user_arguments) Outputs.apply_ems_programs(model, hpxml_osm_map, hpxml.header, args[:add_component_loads]) Outputs.apply_output_file_controls(model, args[:debug]) Outputs.apply_additional_properties(model, hpxml, hpxml_osm_map, args[:hpxml_path], args[:building_id], args[:hpxml_defaults_path]) - # Outputs.apply_ems_debug_output(model) # Uncomment to debug EMS + Outputs.apply_ems_debug_output(model) # Uncomment to debug EMS # Write output files Outputs.write_debug_files(runner, model, args[:debug], args[:output_dir], epw_path) diff --git a/HPXMLtoOpenStudio/measure.xml b/HPXMLtoOpenStudio/measure.xml index f834f1337d..01116d2ebc 100644 --- a/HPXMLtoOpenStudio/measure.xml +++ b/HPXMLtoOpenStudio/measure.xml @@ -3,8 +3,8 @@ 3.1 hpxm_lto_openstudio b1543b30-9465-45ff-ba04-1d1f85e763bc - aab4ee31-48b7-4f7a-bfc0-1d8edf16961d - 2024-10-22T03:59:34Z + 4599ec47-df00-4af8-920a-2a4c460640d9 + 2024-10-22T18:46:21Z D8922A73 HPXMLtoOpenStudio HPXML to OpenStudio Translator @@ -183,13 +183,13 @@ measure.rb rb script - E1E63AE7 + 33FF636A airflow.rb rb resource - D2A99996 + 006218CD battery.rb @@ -327,7 +327,7 @@ defaults.rb rb resource - 5B6D3CB2 + E52E98C6 energyplus.rb @@ -357,7 +357,7 @@ hpxml.rb rb resource - E862E878 + 656CF61F hpxml_schema/HPXML.xsd @@ -375,7 +375,7 @@ hpxml_schematron/EPvalidator.xml xml resource - 009BEB48 + DD7BB2F9 hpxml_schematron/iso-schematron.xsd @@ -663,7 +663,7 @@ test_defaults.rb rb test - 9D489184 + 77AFEE2C test_enclosure.rb diff --git a/HPXMLtoOpenStudio/resources/airflow.rb b/HPXMLtoOpenStudio/resources/airflow.rb index f852cb20c5..473bcf32f3 100644 --- a/HPXMLtoOpenStudio/resources/airflow.rb +++ b/HPXMLtoOpenStudio/resources/airflow.rb @@ -1990,6 +1990,9 @@ def self.apply_cfis(runner, infil_program, vent_mech_fans, cfis_data, cfis_fan_a infil_program.addLine("Set #{f_extra_open_damper_var.name} = 0") infil_program.addLine("Set has_additional_runtime = #{vent_mech.cfis_addtl_runtime_operating_mode == HPXML::CFISModeNone ? 0 : 1}") infil_program.addLine("Set has_outdoor_air_control = #{vent_mech.cfis_has_outdoor_air_control ? 1 : 0}") + if vent_mech.cfis_addtl_runtime_operating_mode == HPXML::CFISModeSupplementalFan + infil_program.addLine("Set suppl_fan_w = #{vent_mech.cfis_supplemental_fan.unit_fan_power}") # W + end infil_program.addLine("If #{t_sum_open_damper_var.name} < t_min_hr_open") # Check whether we've met the minimum hourly runtime infil_program.addLine(" Set t_damper_open = 60 - (t_min_hr_open - #{t_sum_open_damper_var.name})") # Minute of the hour at which the damper must be opened @@ -2015,7 +2018,6 @@ def self.apply_cfis(runner, infil_program, vent_mech_fans, cfis_data, cfis_fan_a else infil_program.addLine(' Set suppl_f = 0.0') end - infil_program.addLine(" Set suppl_fan_w = #{vent_mech.cfis_supplemental_fan.unit_fan_power}") # W infil_program.addLine(" Set #{cfis_suppl_fan_actuator.name} = #{cfis_suppl_fan_actuator.name} + suppl_fan_w * suppl_f") if vent_mech.cfis_supplemental_fan.fan_type == HPXML::MechVentTypeSupply infil_program.addLine(' Set QWHV_cfis_suppl_sup = QWHV_cfis_suppl_sup + (suppl_f * suppl_Q_oa)') @@ -2031,14 +2033,21 @@ def self.apply_cfis(runner, infil_program, vent_mech_fans, cfis_data, cfis_fan_a infil_program.addLine(' Set f_total_open_damper = open_damper_runtime / (ZoneTimeStep * 60)') # Fraction of the timestep that the damper is open infil_program.addLine(" Set #{t_sum_open_damper_var.name} = #{t_sum_open_damper_var.name} + open_damper_runtime") infil_program.addLine(' EndIf') - if vent_mech.cfis_addtl_runtime_operating_mode == HPXML::CFISModeSupplementalFan - infil_program.addLine(" Set f_total_open_damper = @Max (f_total_open_damper - #{f_extra_open_damper_var.name}) 0.0") - end + infil_program.addLine(" Set f_hvac_open_damper = @Max (f_total_open_damper - #{f_extra_open_damper_var.name}) 0.0") # Fraction of the timestep that the damper is open and the HVAC system is running infil_program.addLine('EndIf') infil_program.addLine('If has_outdoor_air_control == 0') - infil_program.addLine(' Set f_total_open_damper = @Max f_total_open_damper fan_rtf_hvac') # Outdoor air is introduced for at least the entire time the HVAC system is running + infil_program.addLine(' Set f_hvac_open_damper = @Max f_hvac_open_damper fan_rtf_hvac') # Outdoor air is introduced for at least the entire time the HVAC system is running infil_program.addLine('EndIf') - infil_program.addLine('Set QWHV_cfis_sup = QWHV_cfis_sup + (f_total_open_damper * Q_duct_oa)') + infil_program.addLine('Set QWHV_cfis_sup = QWHV_cfis_sup + (f_hvac_open_damper * Q_duct_oa)') + next unless vent_mech.cfis_addtl_runtime_operating_mode == HPXML::CFISModeSupplementalFan && vent_mech.cfis_supplemental_fan_runs_with_air_handler_fan + + # Also run supplemental fan when damper is open and HVAC system is running + infil_program.addLine("Set #{cfis_suppl_fan_actuator.name} = #{cfis_suppl_fan_actuator.name} + (suppl_fan_w * f_hvac_open_damper)") + if vent_mech.cfis_supplemental_fan.fan_type == HPXML::MechVentTypeSupply + infil_program.addLine('Set QWHV_cfis_suppl_sup = QWHV_cfis_suppl_sup + (f_hvac_open_damper * suppl_Q_oa)') + elsif vent_mech.cfis_supplemental_fan.fan_type == HPXML::MechVentTypeExhaust + infil_program.addLine('Set QWHV_cfis_suppl_exh = QWHV_cfis_suppl_exh + (f_hvac_open_damper * suppl_Q_oa)') + end end end diff --git a/HPXMLtoOpenStudio/resources/defaults.rb b/HPXMLtoOpenStudio/resources/defaults.rb index df077becff..9f62f339b3 100644 --- a/HPXMLtoOpenStudio/resources/defaults.rb +++ b/HPXMLtoOpenStudio/resources/defaults.rb @@ -2755,6 +2755,10 @@ def self.apply_ventilation_fans(hpxml_bldg, weather, eri_version) vent_fan.cfis_vent_mode_airflow_fraction = 1.0 vent_fan.cfis_vent_mode_airflow_fraction_isdefaulted = true end + if vent_fan.cfis_supplemental_fan_runs_with_air_handler_fan.nil? && (vent_fan.cfis_addtl_runtime_operating_mode == HPXML::CFISModeSupplementalFan) + vent_fan.cfis_supplemental_fan_runs_with_air_handler_fan = false + vent_fan.cfis_supplemental_fan_runs_with_air_handler_fan_isdefaulted = true + end end # Default kitchen fan diff --git a/HPXMLtoOpenStudio/resources/hpxml.rb b/HPXMLtoOpenStudio/resources/hpxml.rb index f536684c1d..537abbc77d 100644 --- a/HPXMLtoOpenStudio/resources/hpxml.rb +++ b/HPXMLtoOpenStudio/resources/hpxml.rb @@ -7993,41 +7993,42 @@ def from_doc(building) # Object for /HPXML/Building/BuildingDetails/Systems/MechanicalVentilation/VentilationFans/VentilationFan. class VentilationFan < BaseElement - ATTRS = [:id, # [String] SystemIdentifier/@id - :count, # [Integer] Count - :fan_type, # [String] FanType (HPXML::MechVentTypeXXX) - :cfis_has_outdoor_air_control, # [Boolean] CFISControls/HasOutdoorAirControl - :cfis_addtl_runtime_operating_mode, # [String] CFISControls/AdditionalRuntimeOperatingMode (HPXML::CFISModeXXX) - :cfis_supplemental_fan_idref, # [String] CFISControls/SupplementalFan/@idref - :rated_flow_rate, # [Double] RatedFlowRate (cfm) - :calculated_flow_rate, # [Double] CalculatedFlowRate (cfm) - :tested_flow_rate, # [Double] TestedFlowRate (cfm) - :hours_in_operation, # [Double] HoursInOperation (hrs/day) - :delivered_ventilation, # [Double] DeliveredVentilation (cfm) - :fan_location, # [String] FanLocation (HPXML::LocationXXX) - :used_for_local_ventilation, # [Boolean] UsedForLocalVentilation - :used_for_whole_building_ventilation, # [Boolean] UsedForWholeBuildingVentilation - :used_for_seasonal_cooling_load_reduction, # [Boolean] UsedForSeasonalCoolingLoadReduction - :used_for_garage_ventilation, # [Boolean] UsedForGarageVentilation - :is_shared_system, # [Boolean] IsSharedSystem - :fraction_recirculation, # [Double] FractionRecirculation (frac) - :total_recovery_efficiency, # [Double] TotalRecoveryEfficiency (frac) - :sensible_recovery_efficiency, # [Double] SensibleRecoveryEfficiency (frac) - :total_recovery_efficiency_adjusted, # [Double] AdjustedTotalRecoveryEfficiency (frac) - :sensible_recovery_efficiency_adjusted, # [Double] AdjustedSensibleRecoveryEfficiency (frac) - :fan_power, # [Double] FanPower (W) - :distribution_system_idref, # [String] AttachedToHVACDistributionSystem/@idref - :start_hour, # [Integer] extension/StartHour - :in_unit_flow_rate, # [Double] extension/InUnitFlowRate (cfm) - :preheating_fuel, # [String] extension/PreHeating/Fuel (HPXML::FuelTypeXXX) - :preheating_efficiency_cop, # [Double] extension/PreHeating/AnnualHeatingEfficiency[Units="COP"]/Value (W/W) - :preheating_fraction_load_served, # [Double] extension/PreHeating/FractionVentilationHeatLoadServed (frac) - :precooling_fuel, # [String] extension/PreCooling/Fuel (HPXML::FuelTypeXXX) - :precooling_efficiency_cop, # [Double] extension/PreCooling/AnnualCoolingEfficiency[Units="COP"]/Value (W/W) - :precooling_fraction_load_served, # [Double] extension/PreCooling/FractionVentilationCoolLoadServed (frac) - :flow_rate_not_tested, # [Boolean] extension/FlowRateNotTested - :fan_power_defaulted, # [Boolean] extension/FanPowerDefaulted - :cfis_vent_mode_airflow_fraction] # [Double] extension/VentilationOnlyModeAirflowFraction (frac) + ATTRS = [:id, # [String] SystemIdentifier/@id + :count, # [Integer] Count + :fan_type, # [String] FanType (HPXML::MechVentTypeXXX) + :cfis_has_outdoor_air_control, # [Boolean] CFISControls/HasOutdoorAirControl + :cfis_addtl_runtime_operating_mode, # [String] CFISControls/AdditionalRuntimeOperatingMode (HPXML::CFISModeXXX) + :cfis_supplemental_fan_idref, # [String] CFISControls/SupplementalFan/@idref + :cfis_supplemental_fan_runs_with_air_handler_fan, # [Boolean] CFISControls/extension/SupplementalFanRunsWithAirHandlerFan + :rated_flow_rate, # [Double] RatedFlowRate (cfm) + :calculated_flow_rate, # [Double] CalculatedFlowRate (cfm) + :tested_flow_rate, # [Double] TestedFlowRate (cfm) + :hours_in_operation, # [Double] HoursInOperation (hrs/day) + :delivered_ventilation, # [Double] DeliveredVentilation (cfm) + :fan_location, # [String] FanLocation (HPXML::LocationXXX) + :used_for_local_ventilation, # [Boolean] UsedForLocalVentilation + :used_for_whole_building_ventilation, # [Boolean] UsedForWholeBuildingVentilation + :used_for_seasonal_cooling_load_reduction, # [Boolean] UsedForSeasonalCoolingLoadReduction + :used_for_garage_ventilation, # [Boolean] UsedForGarageVentilation + :is_shared_system, # [Boolean] IsSharedSystem + :fraction_recirculation, # [Double] FractionRecirculation (frac) + :total_recovery_efficiency, # [Double] TotalRecoveryEfficiency (frac) + :sensible_recovery_efficiency, # [Double] SensibleRecoveryEfficiency (frac) + :total_recovery_efficiency_adjusted, # [Double] AdjustedTotalRecoveryEfficiency (frac) + :sensible_recovery_efficiency_adjusted, # [Double] AdjustedSensibleRecoveryEfficiency (frac) + :fan_power, # [Double] FanPower (W) + :distribution_system_idref, # [String] AttachedToHVACDistributionSystem/@idref + :start_hour, # [Integer] extension/StartHour + :in_unit_flow_rate, # [Double] extension/InUnitFlowRate (cfm) + :preheating_fuel, # [String] extension/PreHeating/Fuel (HPXML::FuelTypeXXX) + :preheating_efficiency_cop, # [Double] extension/PreHeating/AnnualHeatingEfficiency[Units="COP"]/Value (W/W) + :preheating_fraction_load_served, # [Double] extension/PreHeating/FractionVentilationHeatLoadServed (frac) + :precooling_fuel, # [String] extension/PreCooling/Fuel (HPXML::FuelTypeXXX) + :precooling_efficiency_cop, # [Double] extension/PreCooling/AnnualCoolingEfficiency[Units="COP"]/Value (W/W) + :precooling_fraction_load_served, # [Double] extension/PreCooling/FractionVentilationCoolLoadServed (frac) + :flow_rate_not_tested, # [Boolean] extension/FlowRateNotTested + :fan_power_defaulted, # [Boolean] extension/FanPowerDefaulted + :cfis_vent_mode_airflow_fraction] # [Double] extension/VentilationOnlyModeAirflowFraction (frac) attr_accessor(*ATTRS) # Returns the HVAC distribution system for the ventilation fan. @@ -8244,7 +8245,7 @@ def to_doc(building) XMLHelper.add_attribute(sys_id, 'id', @id) XMLHelper.add_element(ventilation_fan, 'Count', @count, :integer, @count_isdefaulted) unless @count.nil? XMLHelper.add_element(ventilation_fan, 'FanType', @fan_type, :string) unless @fan_type.nil? - if (not @cfis_addtl_runtime_operating_mode.nil?) || (not @cfis_supplemental_fan_idref.nil?) || (not @cfis_has_outdoor_air_control.nil?) + if (not @cfis_addtl_runtime_operating_mode.nil?) || (not @cfis_supplemental_fan_idref.nil?) || (not @cfis_has_outdoor_air_control.nil?) || (not @cfis_supplemental_fan_runs_with_air_handler_fan.nil?) cfis_controls = XMLHelper.add_element(ventilation_fan, 'CFISControls') XMLHelper.add_element(cfis_controls, 'HasOutdoorAirControl', @cfis_has_outdoor_air_control, :boolean, @cfis_has_outdoor_air_control_isdefaulted) unless @cfis_has_outdoor_air_control.nil? XMLHelper.add_element(cfis_controls, 'AdditionalRuntimeOperatingMode', @cfis_addtl_runtime_operating_mode, :string, @cfis_addtl_runtime_operating_mode_isdefaulted) unless @cfis_addtl_runtime_operating_mode.nil? @@ -8252,6 +8253,7 @@ def to_doc(building) supplemental_fan = XMLHelper.add_element(cfis_controls, 'SupplementalFan') XMLHelper.add_attribute(supplemental_fan, 'idref', @cfis_supplemental_fan_idref) end + XMLHelper.add_extension(cfis_controls, 'SupplementalFanRunsWithAirHandlerFan', @cfis_supplemental_fan_runs_with_air_handler_fan, :boolean, @cfis_supplemental_fan_runs_with_air_handler_fan_isdefaulted) unless @cfis_supplemental_fan_runs_with_air_handler_fan.nil? end XMLHelper.add_element(ventilation_fan, 'RatedFlowRate', @rated_flow_rate, :float, @rated_flow_rate_isdefaulted) unless @rated_flow_rate.nil? XMLHelper.add_element(ventilation_fan, 'CalculatedFlowRate', @calculated_flow_rate, :float, @calculated_flow_rate_isdefaulted) unless @calculated_flow_rate.nil? @@ -8310,6 +8312,7 @@ def from_doc(ventilation_fan) @cfis_has_outdoor_air_control = XMLHelper.get_value(ventilation_fan, 'CFISControls/HasOutdoorAirControl', :boolean) @cfis_addtl_runtime_operating_mode = XMLHelper.get_value(ventilation_fan, 'CFISControls/AdditionalRuntimeOperatingMode', :string) @cfis_supplemental_fan_idref = HPXML::get_idref(XMLHelper.get_element(ventilation_fan, 'CFISControls/SupplementalFan')) + @cfis_supplemental_fan_runs_with_air_handler_fan = XMLHelper.get_value(ventilation_fan, 'CFISControls/extension/SupplementalFanRunsWithAirHandlerFan', :boolean) @rated_flow_rate = XMLHelper.get_value(ventilation_fan, 'RatedFlowRate', :float) @calculated_flow_rate = XMLHelper.get_value(ventilation_fan, 'CalculatedFlowRate', :float) @tested_flow_rate = XMLHelper.get_value(ventilation_fan, 'TestedFlowRate', :float) diff --git a/HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml b/HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml index 8f592c8c44..df22728743 100644 --- a/HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml +++ b/HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml @@ -2039,6 +2039,7 @@ [CFISAdditionalRuntimeMode=AirHandlerFan] Expected 0 element(s) for xpath: CFISControls/SupplementalFan + Expected 0 element(s) for xpath: CFISControls/extension/SupplementalFanRunsWithAirHandlerFan Expected 0 or 1 element(s) for xpath: FanPower Expected 0 or 1 element(s) for xpath: extension/VentilationOnlyModeAirflowFraction Expected extension/VentilationOnlyModeAirflowFraction to be greater than or equal to 0 @@ -2050,6 +2051,7 @@ [CFISAdditionalRuntimeMode=SupplementalFan] Expected 1 element(s) for xpath: CFISControls/SupplementalFan + Expected 0 or 1 element(s) for xpath: CFISControls/extension/SupplementalFanRunsWithAirHandlerFan Expected 0 element(s) for xpath: FanPower Expected 0 element(s) for xpath: extension/VentilationOnlyModeAirflowFraction @@ -2059,6 +2061,7 @@ [CFISAdditionalRuntimeMode=None] Expected 0 element(s) for xpath: CFISControls/SupplementalFan + Expected 0 element(s) for xpath: CFISControls/extension/SupplementalFanRunsWithAirHandlerFan Expected 0 element(s) for xpath: FanPower Expected 0 element(s) for xpath: extension/VentilationOnlyModeAirflowFraction diff --git a/HPXMLtoOpenStudio/tests/test_defaults.rb b/HPXMLtoOpenStudio/tests/test_defaults.rb index e1a38bd9d7..e8fcf4d0d4 100644 --- a/HPXMLtoOpenStudio/tests/test_defaults.rb +++ b/HPXMLtoOpenStudio/tests/test_defaults.rb @@ -3039,14 +3039,27 @@ def test_mech_ventilation_fans vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation && f.fan_type == HPXML::MechVentTypeCFIS } vent_fan.hours_in_operation = 12.0 vent_fan.rated_flow_rate = 222.0 + vent_fan.cfis_supplemental_fan_runs_with_air_handler_fan = true suppl_vent_fan = vent_fan.cfis_supplemental_fan suppl_vent_fan.tested_flow_rate = 79.0 suppl_vent_fan.fan_power = 9.0 XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path) _default_hpxml, default_hpxml_bldg = _test_measure() - _test_default_mech_vent_values(default_hpxml_bldg, false, 12.0, nil, 222.0, nil, HPXML::CFISModeSupplementalFan, true) + _test_default_mech_vent_values(default_hpxml_bldg, false, 12.0, nil, 222.0, nil, HPXML::CFISModeSupplementalFan, true, true) _test_default_mech_vent_suppl_values(default_hpxml_bldg, false, nil, 9.0, 79.0) + # Test defaults w/ CFIS & supplemental fan + vent_fan.is_shared_system = nil + vent_fan.hours_in_operation = nil + vent_fan.fan_power = nil + vent_fan.rated_flow_rate = nil + vent_fan.cfis_vent_mode_airflow_fraction = nil + vent_fan.cfis_has_outdoor_air_control = nil + vent_fan.cfis_supplemental_fan_runs_with_air_handler_fan = nil + XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path) + _default_hpxml, default_hpxml_bldg = _test_measure() + _test_default_mech_vent_values(default_hpxml_bldg, false, 8.0, nil, 305.4, nil, HPXML::CFISModeSupplementalFan, true, false) + # Test defaults w/ CFIS supplemental fan suppl_vent_fan.tested_flow_rate = nil suppl_vent_fan.is_shared_system = nil @@ -5437,7 +5450,7 @@ def _test_default_hydronic_distribution_values(hpxml_bldg, manualj_hot_water_pip def _test_default_mech_vent_values(hpxml_bldg, is_shared_system, hours_in_operation, fan_power, flow_rate, cfis_vent_mode_airflow_fraction = nil, cfis_addtl_runtime_operating_mode = nil, - cfis_has_outdoor_air_control = nil) + cfis_has_outdoor_air_control = nil, cfis_suppl_fan_runs_with_air_handler = nil) vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation && !f.is_cfis_supplemental_fan } assert_equal(is_shared_system, vent_fan.is_shared_system) @@ -5463,6 +5476,11 @@ def _test_default_mech_vent_values(hpxml_bldg, is_shared_system, hours_in_operat else assert_equal(cfis_has_outdoor_air_control, vent_fan.cfis_has_outdoor_air_control) end + if cfis_suppl_fan_runs_with_air_handler.nil? + assert_nil(vent_fan.cfis_supplemental_fan_runs_with_air_handler_fan) + else + assert_equal(cfis_suppl_fan_runs_with_air_handler, vent_fan.cfis_supplemental_fan_runs_with_air_handler_fan) + end end def _test_default_mech_vent_suppl_values(hpxml_bldg, is_shared_system, hours_in_operation, fan_power, flow_rate) diff --git a/docs/source/workflow_inputs.rst b/docs/source/workflow_inputs.rst index fcdad049de..722ea85d65 100644 --- a/docs/source/workflow_inputs.rst +++ b/docs/source/workflow_inputs.rst @@ -3780,6 +3780,7 @@ A CFIS system is a supply ventilation system that provides outdoor air to the re ``CFISControls/HasOutdoorAirControl`` boolean No true Presence of controls to block outdoor air when not ventilating [#]_ ``CFISControls/AdditionalRuntimeOperatingMode`` string See [#]_ No air handler fan How additional ventilation is provided (beyond HVAC system operation) ``CFISControls/SupplementalFan`` idref See [#]_ See [#]_ The supplemental fan providing additional ventilation + ``CFISControls/extension/SupplementalFanRunsWithAirHandlerFan`` boolean No [#]_ false Whether the supplemental fan also runs with the air handler fan [#]_ ``RatedFlowRate`` or ``TestedFlowRate`` or ``CalculatedFlowRate`` or ``DeliveredVentilation`` double cfm >= 0 No See [#]_ Flow rate [#]_ ``HoursInOperation`` double hrs/day >= 0, <= 24 false 8 Hours per day of operation [#]_ ``UsedForWholeBuildingVentilation`` boolean true Yes Ventilation fan use case [#]_ @@ -3792,6 +3793,9 @@ A CFIS system is a supply ventilation system that provides outdoor air to the re .. [#] AdditionalRuntimeOperatingMode choices are "air handler fan", "supplemental fan", or "none". .. [#] SupplementalFan must reference another ``VentilationFan`` where UsedForWholeBuildingVentilation=true, IsSharedSystem=false, and FanType="exhaust only" or "supply only". .. [#] SupplementalFan only required if AdditionalRuntimeOperatingMode is "supplemental fan". + .. [#] SupplementalFanRunsWithAirHandlerFan only applies when AdditionalRuntimeOperatingMode="supplemental fan". + .. [#] If SupplementalFanRunsWithAirHandlerFan is true, in addition to its normal operation, the supplemental fan will also run simultaneously with the air handler fan when outdoor air is being brought in. + This is typically used with a supplemental exhaust fan to provide "balanced" (supply + exhaust) airflow. .. [#] If flow rate not provided, defaults to the required mechanical ventilation rate per `ANSI/RESNET/ICC 301-2022 `_: Qfan = required mechanical ventilation rate (cfm) = ((Qtot^2 – 4*Qinf_eff^2 + 2*Qinf_eff*Qtot + Qinf_eff^2)^0.5 + Qtot - Qinf_eff) / 2 diff --git a/tasks.rb b/tasks.rb index 9a3fd0d023..dfa5ba2190 100644 --- a/tasks.rb +++ b/tasks.rb @@ -2280,18 +2280,22 @@ 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-supply.xml'].include? hpxml_file + '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}", tested_flow_rate: 120, fan_power: 30, used_for_whole_building_ventilation: true) - if hpxml_file == 'base-mechvent-cfis-supplemental-fan-exhaust.xml' + if hpxml_file.include? 'exhaust' hpxml_bldg.ventilation_fans[-1].fan_type = HPXML::MechVentTypeExhaust - else + elsif hpxml_file.include? 'supply' hpxml_bldg.ventilation_fans[-1].fan_type = HPXML::MechVentTypeSupply end hpxml_bldg.ventilation_fans[0].cfis_addtl_runtime_operating_mode = HPXML::CFISModeSupplementalFan hpxml_bldg.ventilation_fans[0].cfis_supplemental_fan_idref = hpxml_bldg.ventilation_fans[1].id + if hpxml_file == 'base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml' + hpxml_bldg.ventilation_fans[0].cfis_supplemental_fan_runs_with_air_handler_fan = true + end end # ---------------- # diff --git a/workflow/hpxml_inputs.json b/workflow/hpxml_inputs.json index f12654cfc0..3ed9121fbc 100644 --- a/workflow/hpxml_inputs.json +++ b/workflow/hpxml_inputs.json @@ -3215,6 +3215,9 @@ "parent_hpxml": "sample_files/base-mechvent-cfis.xml", "mech_vent_fan_power": null }, + "sample_files/base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml": { + "parent_hpxml": "sample_files/base-mechvent-cfis-supplemental-fan-exhaust.xml" + }, "sample_files/base-mechvent-cfis-supplemental-fan-supply.xml": { "parent_hpxml": "sample_files/base-mechvent-cfis.xml", "mech_vent_fan_power": null diff --git a/workflow/sample_files/base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml b/workflow/sample_files/base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml new file mode 100644 index 0000000000..50a3ddeae7 --- /dev/null +++ b/workflow/sample_files/base-mechvent-cfis-supplemental-fan-exhaust-synchronized.xml @@ -0,0 +1,577 @@ + + + + HPXML + tasks.rb + 2000-01-01T00:00:00-07:00 + create + + + + + 60 + + + + Bills + + + + + + + + +
+ CO +
+
+ + proposed workscope + + + + + suburban + stand-alone + no units above or below + 180 + + electricity + natural gas + + + + single-family detached + 2.0 + 1.0 + 8.0 + 3 + 2 + 2700.0 + 21600.0 + + + + + 2006 + 5B + + + + USA_CO_Denver.Intl.AP.725650_TMY3 + + USA_CO_Denver.Intl.AP.725650_TMY3.epw + + + + + + + + 50.0 + + ACH + 3.0 + + 21600.0 + + + + + + + + false + + + false + + + + + + + + + + + true + + + + + + + + + + + attic - unvented + 1509.3 + asphalt or fiberglass shingles + 0.7 + 0.92 + 6.0 + + + 2.3 + + + + + + + outside + basement - conditioned + 115.6 + wood siding + 0.7 + 0.92 + + + 23.0 + + + + + + + outside + conditioned space + + + + 1200.0 + wood siding + 0.7 + 0.92 + + gypsum board + + + + 23.0 + + + + + outside + attic - unvented + gable + + + + 225.0 + wood siding + 0.7 + 0.92 + + + 4.0 + + + + + + + ground + basement - conditioned + 8.0 + 1200.0 + 8.0 + 7.0 + + gypsum board + + + + + continuous - exterior + 8.9 + 0.0 + 8.0 + + + continuous - interior + 0.0 + + + + + + + + attic - unvented + conditioned space + ceiling + + + + 1350.0 + + gypsum board + + + + 39.3 + + + + + + + basement - conditioned + 1350.0 + 4.0 + 150.0 + + + + 0.0 + 0.0 + + + + + + 0.0 + 0.0 + + + + 0.0 + 0.0 + + + + + + + 108.0 + 0 + 0.33 + 0.45 + + + 0.7 + 0.85 + + 0.67 + + + + + 72.0 + 90 + 0.33 + 0.45 + + + 0.7 + 0.85 + + 0.67 + + + + + 108.0 + 180 + 0.33 + 0.45 + + + 0.7 + 0.85 + + 0.67 + + + + + 72.0 + 270 + 0.33 + 0.45 + + + 0.7 + 0.85 + + 0.67 + + + + + + + + 40.0 + 180 + 4.4 + + + + + + + + + + + + + + + + + natural gas + 36000.0 + + AFUE + 0.92 + + 1.0 + + + + + central air conditioner + electricity + 24000.0 + single stage + 1.0 + + SEER + 13.0 + + 0.73 + + + + + 68.0 + 78.0 + + + + + + regular velocity + + supply + + CFM25 + 75.0 + to outside + + + + return + + CFM25 + 25.0 + to outside + + + + + supply + 4.0 + attic - unvented + 150.0 + + + + return + 0.0 + attic - unvented + 50.0 + + + + + + + + + + central fan integrated supply + + supplemental fan + + + true + + + 330.0 + 8.0 + true + + + + + exhaust only + 120.0 + true + 30.0 + + + + + + + electricity + storage water heater + conditioned space + 40.0 + 1.0 + 18767.0 + 0.95 + 125.0 + + + + + + 50.0 + + + + 0.0 + + + + + shower head + true + + + + faucet + false + + + + + + + conditioned space + 1.21 + 380.0 + 0.12 + 1.09 + 27.0 + 6.0 + 3.2 + + + + conditioned space + electricity + 3.73 + true + 150.0 + + + + conditioned space + 307.0 + 12 + 0.12 + 1.09 + 22.32 + 4.0 + + + + conditioned space + 650.0 + + + + conditioned space + electricity + false + + + + false + + + + + + interior + 0.4 + + + + + + + interior + 0.1 + + + + + + + interior + 0.25 + + + + + + + exterior + 0.4 + + + + + + + exterior + 0.1 + + + + + + + exterior + 0.25 + + + + + + + + + TV other + + kWh/year + 620.0 + + + + + other + + kWh/year + 2457.0 + + + 0.855 + 0.045 + + + + +
+
\ No newline at end of file