Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ANSI 301-2022: Fraction Duct Area #709

Merged
merged 9 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ __New Features__
- Ground source heat pump model enhancements.
- Allows `Roof/RadiantBarrier` to be omitted; defaults to false.
- Adds more error-checking for inappropriate inputs (e.g., HVAC SHR=0 or clothes washer IMEF=0).
- Allows `FractionDuctArea` as alternative to `DuctSurfaceArea`

__Bugfixes__
- Fixes possible 301ruleset.rb error due to floating point arithmetic.
Expand Down
29 changes: 19 additions & 10 deletions docs/source/workflow_inputs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1532,16 +1532,16 @@ Additional information is entered in each ``DuctLeakageMeasurement``.

Additional information is entered in each ``Ducts``.

============================= ======= ============ =========== ======== ========== ===============================
Element Type Units Constraints Required Default Notes
============================= ======= ============ =========== ======== ========== ===============================
``SystemIdentifier`` id Yes Unique identifier
``DuctType`` string See [#]_ Yes Supply or return ducts
``DuctInsulationRValue`` double F-ft2-hr/Btu >= 0 Yes R-value of duct insulation [#]_
``DuctBuriedInsulationLevel`` string See [#]_ No not buried Duct buried insulation level [#]_
``DuctLocation`` string See [#]_ Yes Duct location
``DuctSurfaceArea`` double ft2 >= 0 Yes Duct surface area
============================= ======= ============ =========== ======== ========== ===============================
=============================================== ======= ============ ================ ======== ========== ======================================
Element Type Units Constraints Required Default Notes
=============================================== ======= ============ ================ ======== ========== ======================================
``SystemIdentifier`` id Yes Unique identifier
``DuctType`` string See [#]_ Yes Supply or return ducts
``DuctInsulationRValue`` double F-ft2-hr/Btu >= 0 Yes R-value of duct insulation [#]_
``DuctBuriedInsulationLevel`` string See [#]_ No not buried Duct buried insulation level [#]_
``DuctLocation`` string See [#]_ Yes Duct location
``FractionDuctArea`` and/or ``DuctSurfaceArea`` double frac or ft2 0-1 or >= 0 [#]_ Yes [#]_ See [#]_ Duct fraction/surface area in location
=============================================== ======= ============ ================ ======== ========== ======================================

.. [#] DuctType choices are "supply" or "return".
.. [#] DuctInsulationRValue should not include the exterior air film (i.e., use 0 for an uninsulated duct).
Expand All @@ -1554,6 +1554,15 @@ Additional information is entered in each ``Ducts``.
See the `Building America Solution Center <https://basc.pnnl.gov/resource-guides/ducts-buried-attic-insulation>`_ for more information.
.. [#] DuctLocation choices are "conditioned space", "basement - conditioned", "basement - unconditioned", "crawlspace - unvented", "crawlspace - vented", "attic - unvented", "attic - vented", "garage", "outside", "exterior wall", "under slab", "roof deck", "other housing unit", "other heated space", "other multifamily buffer space", or "other non-freezing space".
See :ref:`hpxmllocations` for descriptions.
.. [#] The sum of all FractionDuctArea must each equal to 1, both for the supply side and return side.
bpark1327 marked this conversation as resolved.
Show resolved Hide resolved
.. [#] If both are provided, DuctSurfaceArea will be used in the model.
.. [#] Duct surface areas will be calculated based on BSR/RESNET/ICC 301-2022 Table 4.2.2(1) footnote z. aa.:
bpark1327 marked this conversation as resolved.
Show resolved Hide resolved

\- **Supply duct area**: 0.27 * ConditionedFloorAreaServed

\- **Return duct area**: (if Number of Returns < 6, 0.05 * Number of Returns, 0.25 otherwise) * ConditionedFloorAreaServed

If FractionDuctArea is provided, each duct surface area will be FractionDuctArea times total duct area, which is calculated using the sum of primary and secondary duct areas from the equations above.
bpark1327 marked this conversation as resolved.
Show resolved Hide resolved

.. _hvac_distribution_hydronic:

Expand Down
1 change: 1 addition & 0 deletions rulesets/resources/301ruleset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,7 @@ def self.set_systems_hvac_rated(orig_bldg, new_bldg)
duct_insulation_r_value: orig_duct.duct_insulation_r_value,
duct_location: orig_duct.duct_location,
duct_surface_area: orig_duct.duct_surface_area,
duct_fraction_area: orig_duct.duct_fraction_area,
duct_buried_insulation_level: orig_duct.duct_buried_insulation_level)
end
end
Expand Down
5 changes: 4 additions & 1 deletion rulesets/resources/301validator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1100,9 +1100,12 @@
<sch:assert role='ERROR' test='h:DuctBuriedInsulationLevel[text()="not buried" or text()="partially buried" or text()="fully buried" or text()="deeply buried"] or not(h:DuctBuriedInsulationLevel)'>Expected DuctBuriedInsulationLevel to be 'not buried' or 'partially buried' or 'fully buried' or 'deeply buried'</sch:assert>
<sch:assert role='ERROR' test='count(h:DuctLocation) = 1'>Expected 1 element(s) for xpath: DuctLocation</sch:assert> <!-- See [HVACDuct=WithLocation] or [HVACDuct=WithoutLocation] -->
<sch:assert role='ERROR' test='h:DuctLocation[text()="conditioned space" or text()="basement - conditioned" or text()="basement - unconditioned" or text()="crawlspace - vented" or text()="crawlspace - unvented" or text()="attic - vented" or text()="attic - unvented" or text()="garage" or text()="exterior wall" or text()="under slab" or text()="roof deck" or text()="outside" or text()="other housing unit" or text()="other heated space" or text()="other multifamily buffer space" or text()="other non-freezing space"] or not(h:DuctLocation)'>Expected DuctLocation to be 'conditioned space' or 'basement - conditioned' or 'basement - unconditioned' or 'crawlspace - vented' or 'crawlspace - unvented' or 'attic - vented' or 'attic - unvented' or 'garage' or 'exterior wall' or 'under slab' or 'roof deck' or 'outside' or 'other housing unit' or 'other heated space' or 'other multifamily buffer space' or 'other non-freezing space'</sch:assert>
<sch:assert role='ERROR' test='count(h:DuctSurfaceArea) = 1'>Expected 1 element(s) for xpath: DuctSurfaceArea</sch:assert>
<sch:assert role='ERROR' test='count(h:FractionDuctArea) + count(h:DuctSurfaceArea) &gt;= 1'>Expected 1 or more element(s) for xpath: FractionDuctArea | DuctSurfaceArea</sch:assert>
<sch:assert role='ERROR' test='count(../h:NumberofReturnRegisters) = 1'>Expected 1 element(s) for xpath: ../NumberofReturnRegisters</sch:assert>
<sch:assert role='ERROR' test='count(../../../h:ConditionedFloorAreaServed) = 1'>Expected 1 element(s) for xpath: ../../../ConditionedFloorAreaServed</sch:assert>
<!-- Sum Checks -->
<sch:assert role='ERROR' test='(sum(h:Ducts[h:DuctType="supply"]/h:FractionDuctArea) &gt;= 0.99 and sum(h:Ducts[h:DuctType="supply"]/h:FractionDuctArea) &lt;= 1.01) or count(h:Ducts[h:DuctType="supply"]/h:FractionDuctArea) = 0'>Expected sum(Ducts/FractionDuctArea) for DuctType="supply" to be 1</sch:assert>
<sch:assert role='ERROR' test='(sum(h:Ducts[h:DuctType="return"]/h:FractionDuctArea) &gt;= 0.99 and sum(h:Ducts[h:DuctType="return"]/h:FractionDuctArea) &lt;= 1.01) or count(h:Ducts[h:DuctType="return"]/h:FractionDuctArea) = 0'>Expected sum(Ducts/FractionDuctArea) for DuctType="return" to be 1</sch:assert>
</sch:rule>
</sch:pattern>

Expand Down
3 changes: 2 additions & 1 deletion rulesets/resources/ES_ZERHruleset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,8 @@ def self.get_radiant_barrier_bool(orig_bldg)

ducts_in_uncond_attic = false
all_ducts.each do |duct|
if [HPXML::LocationAtticVented, HPXML::LocationAtticUnvented].include?(duct.duct_location) && duct.duct_surface_area > 0
if [HPXML::LocationAtticVented, HPXML::LocationAtticUnvented].include?(duct.duct_location) &&
(!duct.duct_surface_area.to_f.zero? || !duct.duct_fraction_area.to_f.zero?)
ducts_in_uncond_attic = true
end
end
Expand Down
33 changes: 33 additions & 0 deletions rulesets/tests/test_hvac.rb
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,39 @@ def test_ducts_buried
end
end

def test_duct_fraction_area
hpxml_name = 'base.xml'
hpxml = HPXML.new(hpxml_path: File.join(@root_path, 'workflow', 'sample_files', hpxml_name))
hpxml_bldg = hpxml.buildings[0]
hpxml_bldg.hvac_distributions.each do |hvac_distribution|
hvac_distribution.ducts.each do |duct|
duct.duct_surface_area = nil
duct.duct_fraction_area = 0.7
end
end
[HPXML::DuctTypeSupply, HPXML::DuctTypeReturn].each do |duct_type|
hpxml_bldg.hvac_distributions[-1].ducts.add(id: "Ducts#{hpxml_bldg.hvac_distributions[-1].ducts.size + 1}",
duct_type: duct_type,
duct_insulation_r_value: 0,
duct_location: HPXML::LocationConditionedSpace,
duct_fraction_area: 0.3)
end
hpxml_name = File.basename(@tmp_hpxml_path)
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)

_all_calc_types.each do |calc_type|
_hpxml, hpxml_bldg = _test_ruleset(hpxml_name, calc_type)
if [Constants.CalcTypeERIRatedHome].include? calc_type
_check_ducts(hpxml_bldg, [{ duct_type: HPXML::DuctTypeSupply, duct_rvalue: 4.0, duct_area: 510.3, duct_location: HPXML::LocationAtticUnvented, duct_buried: HPXML::DuctBuriedInsulationNone },
{ duct_type: HPXML::DuctTypeReturn, duct_rvalue: 0.0, duct_area: 189.0, duct_location: HPXML::LocationAtticUnvented, duct_buried: HPXML::DuctBuriedInsulationNone },
{ duct_type: HPXML::DuctTypeSupply, duct_rvalue: 0.0, duct_area: 218.7, duct_location: HPXML::LocationConditionedSpace, duct_buried: HPXML::DuctBuriedInsulationNone },
{ duct_type: HPXML::DuctTypeReturn, duct_rvalue: 0.0, duct_area: 81.0, duct_location: HPXML::LocationConditionedSpace, duct_buried: HPXML::DuctBuriedInsulationNone }])
else
_check_ducts(hpxml_bldg)
end
end
end

def test_dse
hpxml_name = 'base-hvac-dse.xml'

Expand Down
1 change: 1 addition & 0 deletions tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2439,6 +2439,7 @@ def create_sample_hpxmls
'base-hvac-central-ac-only-var-speed.xml',
'base-hvac-central-ac-plus-air-to-air-heat-pump-heating.xml',
'base-hvac-dse.xml',
'base-hvac-ducts-area-fractions.xml',
bpark1327 marked this conversation as resolved.
Show resolved Hide resolved
'base-hvac-ducts-leakage-cfm50.xml',
'base-hvac-ducts-buried.xml',
'base-hvac-dual-fuel-air-to-air-heat-pump-1-speed.xml',
Expand Down