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

Enclosure attics and roofs #16

Merged
merged 15 commits into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from 14 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
175 changes: 169 additions & 6 deletions hpxml_version_translator/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,169 @@ def get_event_type_from_building_id(building_id):
# Enclosure
# https://github.com/hpxmlwg/hpxml/pull/181

# Attics
for i, attic in enumerate(root.xpath(
'h:Building/h:BuildingDetails/h:Enclosure/h:AtticAndRoof/h:Attics/h:Attic', **xpkw
)):
enclosure = attic.getparent().getparent().getparent()
if not hasattr(enclosure, 'Attics'):
add_after(
enclosure,
['AirInfiltration'],
E.Attics()
)
this_attic = deepcopy(attic)

if hasattr(this_attic, 'AtticType'):
if this_attic.AtticType == 'vented attic':
this_attic.AtticType = E.AtticType(E.Attic(E.Vented(True)))
elif this_attic.AtticType == 'unvented attic':
this_attic.AtticType = E.AtticType(E.Attic(E.Vented(False)))
elif this_attic.AtticType == 'flat roof':
this_attic.AtticType = E.AtticType(E.FlatRoof())
elif this_attic.AtticType == 'cathedral ceiling':
this_attic.AtticType = E.AtticType(E.CathedralCeiling())
elif this_attic.AtticType == 'cape cod':
this_attic.AtticType = E.AtticType(E.Attic(E.CapeCod(True)))
elif this_attic.AtticType == 'other':
this_attic.AtticType = E.AtticType(E.Other())
elif this_attic.AtticType == 'venting unknown attic':
this_attic.AtticType = E.AtticType(E.Attic(E.extension(E.Vented('unknown'))))
bpark1327 marked this conversation as resolved.
Show resolved Hide resolved

# move AttachedToRoof to after VentilationRate
if hasattr(this_attic, 'AttachedToRoof'):
attached_to_roof = deepcopy(this_attic.AttachedToRoof)
add_after(
this_attic,
['SystemIdentifier',
'AttachedToSpace',
'AtticType',
'VentilationRate'],
attached_to_roof
)
this_attic.remove(this_attic.AttachedToRoof[0]) # remove the AttachedToRoof of HPXML v2
# find the wall with the same id and add AtticWallType = knee wall
if hasattr(this_attic, 'AtticKneeWall'):
knee_wall_id = this_attic.AtticKneeWall.attrib['idref']
knee_wall = root.xpath(
'h:Building/h:BuildingDetails/h:Enclosure/h:Walls/h:Wall[h:SystemIdentifier/@id=$sysid]',
sysid=knee_wall_id, **xpkw)[0]
add_after(
knee_wall,
['SystemIdentifier',
'ExteriorAdjacentTo',
'InteriorAdjacentTo'],
E.AtticWallType('knee wall')
)
# create a FrameFloor adjacent to the attic and assign the area below to Area
# and then copy AtticFloorInsulation over to Insulation of the frame floor
if hasattr(this_attic, 'AtticFloorInsulation'):
attic_floor_insulation = deepcopy(this_attic.AtticFloorInsulation)
attic_floor_insulation.tag = f'{{{hpxml3_ns}}}Insulation'
enclosure.append(
E.FrameFloors(
E.FrameFloor(
E.SystemIdentifier(id='attic_floor'),
E.InteriorAdjacentTo('attic'),
)
)
)
if hasattr(this_attic, 'Area'):
enclosure.FrameFloors.FrameFloor.append(E.Area(float(this_attic.Area)))
enclosure.FrameFloors.FrameFloor.append(attic_floor_insulation)
# find the roof whose InteriorAdjacentTo is attic and then copy it to Insulation of the roof
# FIXME: add insulation to v2 Roofs and these roofs will be converted into hpxml v3 later
if hasattr(this_attic, 'AtticRoofInsulation'):
roof_insulation = deepcopy(this_attic.AtticRoofInsulation)
roof_insulation.tag = f'{{{hpxml3_ns}}}Insulation'
for i, rf in enumerate(root.xpath(
'h:Building/h:BuildingDetails/h:Enclosure/h:AtticAndRoof/h:Roofs/h:Roof', **xpkw
)):
add_after(
rf,
['Pitch',
'RoofArea',
'RadiantBarrier',
'RadiantBarrierLocation'],
roof_insulation
)
# move Rafters to Roof
# FIXME: move Rafters to v2 Roofs and these roofs will be converted into hpxml v3 later
if hasattr(this_attic, 'Rafters'):
rafters = deepcopy(this_attic.Rafters)
for i, rf in enumerate(root.xpath(
'h:Building/h:BuildingDetails/h:Enclosure/h:AtticAndRoof/h:Roofs/h:Roof', **xpkw
)):
add_after(
rf,
['RoofColor',
'SolarAbsorptance',
'Emittance'],
rafters
)

el_not_in_v3 = [
'ExteriorAdjacentTo',
'InteriorAdjacentTo',
'AtticKneeWall',
'AtticFloorInsulation',
'AtticRoofInsulation',
'Area',
'Rafters'
]
for el in el_not_in_v3:
if hasattr(this_attic, el):
this_attic.remove(this_attic[el])

enclosure.Attics.append(this_attic)

# Roofs
for i, roof in enumerate(root.xpath(
'h:Building/h:BuildingDetails/h:Enclosure/h:AtticAndRoof/h:Roofs/h:Roof', **xpkw
)):
enclosure = roof.getparent().getparent().getparent()
if not hasattr(enclosure, 'Roofs'):
add_after(
enclosure,
['AirInfiltration',
'Attics',
'Foundations',
'Garages'],
E.Roofs()
)
enclosure.Roofs.append(deepcopy(roof))

if hasattr(roof, 'RoofArea'):
add_after(
enclosure.Roofs.Roof,
['SystemIdentifier',
'ExternalResource',
'AttachedToSpace',
'InteriorAdjacentTo'],
E.Area(float(roof.RoofArea))
)
enclosure.Roofs.Roof.remove(enclosure.Roofs.Roof.RoofArea)

if hasattr(roof, 'RoofType'):
add_after(
enclosure.Roofs.Roof,
['SystemIdentifier',
'ExternalResource',
'AttachedToSpace',
'InteriorAdjacentTo',
'Area',
'Orientation',
'Azimuth'],
E.RoofType(str(roof.RoofType))
)
enclosure.Roofs.Roof.remove(enclosure.Roofs.Roof.RoofType[1]) # remove the RoofType of HPXML v2

# remove AtticAndRoof after rearranging all attics and roofs
try:
root.Building.BuildingDetails.Enclosure.remove(root.Building.BuildingDetails.Enclosure.AtticAndRoof)
except AttributeError:
pass

# Frame Floors
for i, ff in enumerate(root.xpath(
'h:Building/h:BuildingDetails/h:Enclosure/h:Foundations/h:Foundation/h:FrameFloor', **xpkw
Expand Down Expand Up @@ -293,12 +456,6 @@ def get_event_type_from_building_id(building_id):
enclosure.FrameFloors.append(this_ff)
foundation.remove(ff)

# Remove 'Insulation/InsulationLocation'
# TODO: Use it for other enclosure types
for ins_loc in root.xpath('//h:Insulation/h:InsulationLocation', **xpkw):
ins = ins_loc.getparent()
ins.remove(ins.InsulationLocation)

# Slabs
for i, slab in enumerate(root.xpath(
'h:Building/h:BuildingDetails/h:Enclosure/h:Foundations/h:Foundation/h:Slab', **xpkw
Expand All @@ -324,6 +481,12 @@ def get_event_type_from_building_id(building_id):
enclosure.Slabs.append(deepcopy(slab))
foundation.remove(slab)

# Remove 'Insulation/InsulationLocation'
# TODO: Use it for other enclosure types
for ins_loc in root.xpath('//h:Insulation/h:InsulationLocation', **xpkw):
ins = ins_loc.getparent()
ins.remove(ins.InsulationLocation)

# TODO: Adds desuperheater flexibility
# https://github.com/hpxmlwg/hpxml/pull/184

Expand Down
93 changes: 93 additions & 0 deletions test/hpxml_files/enclosure_attics_and_roofs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<HPXML xmlns="http://hpxmlonline.com/2014/6" schemaVersion="2.3">
<XMLTransactionHeaderInformation>
<XMLType></XMLType>
<XMLGeneratedBy></XMLGeneratedBy>
<CreatedDateAndTime>2021-04-05T14:17:07.685077</CreatedDateAndTime>
<Transaction>create</Transaction>
</XMLTransactionHeaderInformation>
<SoftwareInfo/>
<Building>
<BuildingID id="bldg1"></BuildingID>
<ProjectStatus>
<EventType>audit</EventType>
</ProjectStatus>
<BuildingDetails>
<Enclosure>
<AtticAndRoof>
<Roofs>
<Roof>
<SystemIdentifier id='roof-1'/>
<RoofColor>dark</RoofColor>
<SolarAbsorptance>0.7</SolarAbsorptance>
<Emittance>0.9</Emittance>
<RoofType>shingles</RoofType>
<Pitch>6.0</Pitch>
<RoofArea>1118.5</RoofArea>
</Roof>
</Roofs>
<Attics>
<Attic>
<SystemIdentifier id='attic-1'/>
<AttachedToRoof idref='roof-1'/>
<ExteriorAdjacentTo>ambient</ExteriorAdjacentTo>
<InteriorAdjacentTo>attic</InteriorAdjacentTo>
<AtticKneeWall idref='wall-1'/>
<AtticType>unvented attic</AtticType>
<Area>1000</Area>
<Rafters>
<Size>2x4</Size>
<Material>wood</Material>
</Rafters>
</Attic>
<Attic>
<SystemIdentifier id='attic-2'/>
<AtticType>venting unknown attic</AtticType>
<AtticFloorInsulation>
<SystemIdentifier id='attic-floor-insulation'/>
<InsulationGrade>1</InsulationGrade>
<InsulationCondition>poor</InsulationCondition>
<AssemblyEffectiveRValue>5.5</AssemblyEffectiveRValue>
</AtticFloorInsulation>
<AtticRoofInsulation>
<SystemIdentifier id='attic-roof-insulation'/>
<InsulationGrade>3</InsulationGrade>
<InsulationCondition>good</InsulationCondition>
<Layer>
<InstallationType>cavity</InstallationType>
<NominalRValue>7.5</NominalRValue>
</Layer>
</AtticRoofInsulation>
<Area>1500.0</Area>
</Attic>
<Attic>
<SystemIdentifier id='attic-3'/>
<AtticType>vented attic</AtticType>
</Attic>
<Attic>
<SystemIdentifier id='attic-4'/>
<AtticType>flat roof</AtticType>
</Attic>
<Attic>
<SystemIdentifier id='attic-5'/>
<AtticType>cathedral ceiling</AtticType>
</Attic>
<Attic>
<SystemIdentifier id='attic-6'/>
<AtticType>cape cod</AtticType>
</Attic>
<Attic>
<SystemIdentifier id='attic-7'/>
<AtticType>other</AtticType>
</Attic>
</Attics>
</AtticAndRoof>
<Walls>
<Wall>
<SystemIdentifier id='wall-1'/>
</Wall>
</Walls>
</Enclosure>
</BuildingDetails>
</Building>
</HPXML>
56 changes: 56 additions & 0 deletions test/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,62 @@ def test_clothes_dryer():
assert not hasattr(dryer2, 'EfficiencyFactor')


def test_enclosure_attics():
root = convert_hpxml_and_parse(hpxml_dir / 'enclosure_attics_and_roofs.xml')

attic1 = root.Building.BuildingDetails.Enclosure.Attics.Attic[0]
enclosure = attic1.getparent().getparent()
assert not attic1.AtticType.Attic.Vented # unvented attic
assert attic1.AttachedToRoof.attrib['idref'] == 'roof-1'
assert not hasattr(enclosure, 'AtticAndRoof')
assert not hasattr(enclosure, 'ExteriorAdjacentTo')
assert enclosure.Walls.Wall[0].AtticWallType == 'knee wall'
assert enclosure.Roofs.Roof[0].Rafters.Size == '2x4'
assert enclosure.Roofs.Roof[0].Rafters.Material == 'wood'
assert enclosure.Roofs.Roof[0].Insulation.InsulationGrade == 3
assert enclosure.Roofs.Roof[0].Insulation.InsulationCondition == 'good'
assert enclosure.Roofs.Roof[0].Insulation.Layer.InstallationType == 'cavity'
assert enclosure.Roofs.Roof[0].Insulation.Layer.NominalRValue == 7.5
assert enclosure.FrameFloors.FrameFloor[0].InteriorAdjacentTo == 'attic'
assert enclosure.FrameFloors.FrameFloor[0].Area == 1500.0
assert enclosure.FrameFloors.FrameFloor[0].Insulation.InsulationGrade == 1
assert enclosure.FrameFloors.FrameFloor[0].Insulation.InsulationCondition == 'poor'
assert enclosure.FrameFloors.FrameFloor[0].Insulation.AssemblyEffectiveRValue == 5.5

attic2 = root.Building.BuildingDetails.Enclosure.Attics.Attic[1]
assert attic2.AtticType.Attic.extension.Vented == 'unknown' # venting unknown attic

attic3 = root.Building.BuildingDetails.Enclosure.Attics.Attic[2]
assert attic3.AtticType.Attic.Vented # vented attic

attic4 = root.Building.BuildingDetails.Enclosure.Attics.Attic[3]
assert hasattr(attic4.AtticType, 'FlatRoof')

attic5 = root.Building.BuildingDetails.Enclosure.Attics.Attic[4]
assert hasattr(attic5.AtticType, 'CathedralCeiling')

attic6 = root.Building.BuildingDetails.Enclosure.Attics.Attic[5]
assert attic6.AtticType.Attic.CapeCod

attic7 = root.Building.BuildingDetails.Enclosure.Attics.Attic[6]
assert hasattr(attic7.AtticType, 'Other')


def test_enclosure_roofs():
root = convert_hpxml_and_parse(hpxml_dir / 'enclosure_attics_and_roofs.xml')

roof1 = root.Building.BuildingDetails.Enclosure.Roofs.Roof[0]
enclosure = roof1.getparent().getparent()
assert roof1.Area == 1118.5
assert roof1.RoofType == 'shingles'
assert roof1.RoofColor == 'dark'
assert roof1.SolarAbsorptance == 0.7
assert roof1.Emittance == 0.9
assert roof1.Pitch == 6.0
assert not hasattr(roof1, 'RoofArea')
assert not hasattr(enclosure, 'AtticAndRoof')


def test_frame_floors():
root = convert_hpxml_and_parse(hpxml_dir / 'enclosure_frame_floors.xml')

Expand Down