Repository: NREL/hescore-hpxml

Issue:
Workaround for conditioned attics in HPXML 2.3
There is [no way to translate a conditioned attic](https://hescore-hpxml.readthedocs.io/en/latest/translation/zone_roof.html#id1) from HPXML 2.3. It [will be possible](https://hpxml.nrel.gov/datadictionary/3/Building/BuildingDetails/Enclosure/Attics/Attic/AtticType/Attic/Conditioned) when we move to HPXML 3. We should include an extension to allow people to get that in v2.3. 

Let's do this as follows: To get a conditioned attic in HEScore, you set `Attic/AtticType` to "other" and then `Attic/extension/Conditioned` to "true". If it meets those two criteria, then translate as `cond_attic` in HEScore. If not that act as it normally does (i.e. "other" will cause the translation to fail.).

To Do:

- [ ] Update translation
- [ ] Write test of new capability
- [ ] Update docs to reflect change in behavior

Discussion:

Patch:
diff --git a/docs/source/translation/zone_roof.rst b/docs/source/translation/zone_roof.rst
index b4f1e7df..4e1ed757 100644
--- a/docs/source/translation/zone_roof.rst
+++ b/docs/source/translation/zone_roof.rst
@@ -30,16 +30,19 @@ type according to the following mapping.
    unvented attic         vented_attic
    vented attic           vented_attic
    venting unknown attic  vented_attic
-   other                  *not translated*
+   other                  *see note below*
    =====================  ================
 
-.. warning:: 
+.. note::
    
-   There is no way to get a HEScore ``cond_attic``.
+   Currently, there's no existing HPXML element capturing a conditioned attic.
+   The only way to model a HEScore ``cond_attic`` is to specify HPXML Attic Type
+   to be ``other`` with an extra element ``Attic/extension/Conditioned`` to be
+   ``true``.
+
+   Otherwise, HPXML Attic Type ``other`` will not be translated and will
+   result in a translation error.
 
-.. note::   
-   
-   Items that are *not translated* will result in a translation error.
    
 HEScore can accept up to two attic/roof constructions. If there are more than
 two specified in HPXML, the properties of the ``Attic`` elements with
diff --git a/hescorehpxml/__init__.py b/hescorehpxml/__init__.py
index 056928d6..306fcba0 100644
--- a/hescorehpxml/__init__.py
+++ b/hescorehpxml/__init__.py
@@ -923,9 +923,13 @@ class HPXMLtoHEScoreTranslator(object):
             hpxml_attic_type = xpath(attic, 'h:AtticType/text()')
             atticd['rooftype'] = rooftypemap[hpxml_attic_type]
             if atticd['rooftype'] is None:
-                raise TranslationError(
-                    'Attic {}: Cannot translate HPXML AtticType {} to HEScore rooftype.'.format(atticid,
-                                                                                                hpxml_attic_type))
+                attc_is_cond = xpath(attic, 'h:extension/h:Conditioned/text()')
+                if attc_is_cond == 'true':
+                    atticd['rooftype'] = 'cond_attic'
+                else:
+                    raise TranslationError(
+                        'Attic {}: Cannot translate HPXML AtticType {} to HEScore rooftype.'.format(atticid,
+                                                                                                    hpxml_attic_type))
 
             # Roof color
             solar_absorptance = convert_to_type(float, xpath(roof, 'h:SolarAbsorptance/text()'))


Test patch:
diff --git a/tests/tests.py b/tests/tests.py
index 13fff2ac..ccc81832 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -1970,6 +1970,33 @@ class TestHEScore2019Updates(unittest.TestCase, ComparatorBase):
         self.assertEqual(system['type'], 'tankless')
         self.assertAlmostEqual(system['energy_factor'], 0.7)
 
+    def test_conditioned_attic(self):
+        tr = self._load_xmlfile('house4')
+        attic = self.xpath('//h:Attic[h:SystemIdentifier/@id="attic1"]')
+        attic_type = self.xpath('//h:Attic[h:SystemIdentifier/@id="attic1"]/h:AtticType')
+        attic_type.text = 'other'
+        self.assertRaisesRegexp(
+            TranslationError,
+            r'Attic attic1: Cannot translate HPXML AtticType other to HEScore rooftype.',
+            tr.hpxml_to_hescore_dict
+        )
+        is_attic_cond = etree.SubElement(etree.SubElement(attic, tr.addns('h:extension')), tr.addns('h:Conditioned'))
+        is_attic_cond.text = 'true'
+        d = tr.hpxml_to_hescore_dict()
+        roof_type = d['building']['zone']['zone_roof'][0]['roof_type']
+        self.assertEqual(roof_type, 'cond_attic')
+        is_attic_cond.text = 'false'
+        self.assertRaisesRegexp(
+            TranslationError,
+            r'Attic \w+: Cannot translate HPXML AtticType other to HEScore rooftype.',
+            tr.hpxml_to_hescore_dict
+        )
+        attic_type.text = 'vented attic'
+        is_attic_cond.text = 'true'
+        d = tr.hpxml_to_hescore_dict()
+        roof_type = d['building']['zone']['zone_roof'][0]['roof_type']
+        self.assertEqual(roof_type, 'vented_attic')
+
 
 if __name__ == "__main__":
     unittest.main()