From 04c7c57c966302ce9573e4609e7c6f66d802d344 Mon Sep 17 00:00:00 2001 From: Samuel Letellier-Duchesne Date: Wed, 19 Jan 2022 11:46:52 -0500 Subject: [PATCH] Supports Material:NoMass and Material:AirGap in OpaqueMaterial class (#274) * Writes NoMassMaterial class like OpaqueMaterial * Enables Conversion of OpaqueMaterial to Material:NoMass and Material:AirGap * Fix version tests --- archetypal/eplus_interface/version.py | 2 +- archetypal/settings.py | 2 +- .../constructions/opaque_construction.py | 2 +- .../template/materials/nomass_material.py | 85 +++++++------------ .../template/materials/opaque_material.py | 49 ++++++++--- tests/test_idfclass.py | 2 +- tests/test_version.py | 2 +- 7 files changed, 72 insertions(+), 72 deletions(-) diff --git a/archetypal/eplus_interface/version.py b/archetypal/eplus_interface/version.py index 8ac8c250..085ebaf3 100644 --- a/archetypal/eplus_interface/version.py +++ b/archetypal/eplus_interface/version.py @@ -121,7 +121,7 @@ def valid_versions(self) -> set: """List the idd file version found on this machine.""" if not self.valid_idd_paths: # Little hack in case E+ is not installed - _choices = set(settings.ep_version) + _choices = {settings.ep_version,} else: _choices = set(self.valid_idd_paths.keys()) diff --git a/archetypal/settings.py b/archetypal/settings.py index f1e382f7..fd6a2956 100644 --- a/archetypal/settings.py +++ b/archetypal/settings.py @@ -155,4 +155,4 @@ def set_weigth_attr(self, weight): zone_weight = ZoneWeight(n=0) # Latest version of EnergyPlus compatible with archetypal looks for ENERGYPLUS_VERSION in os.environ -ep_version = os.getenv("ENERGYPLUS_VERSION", "9-2-0").replace("-", ".") +ep_version = os.getenv("ENERGYPLUS_VERSION", "9-2-0") diff --git a/archetypal/template/constructions/opaque_construction.py b/archetypal/template/constructions/opaque_construction.py index c97c1ab2..4ef85a49 100644 --- a/archetypal/template/constructions/opaque_construction.py +++ b/archetypal/template/constructions/opaque_construction.py @@ -418,7 +418,7 @@ def from_epbunch(cls, epbunch, **kwargs): **kwargs: keywords passed to the LayeredConstruction constructor. """ assert epbunch.key.lower() in ("internalmass", "construction", 'construction:internalsource'), ( - f"Expected ('Internalmass', 'Construction', 'construction:internalsouce')." f"Got '{epbunch.key}'." + f"Expected ('Internalmass', 'Construction', 'construction:internalsource')." f"Got '{epbunch.key}'." ) name = epbunch.Name diff --git a/archetypal/template/materials/nomass_material.py b/archetypal/template/materials/nomass_material.py index 7cffde2a..d4b267be 100644 --- a/archetypal/template/materials/nomass_material.py +++ b/archetypal/template/materials/nomass_material.py @@ -6,6 +6,7 @@ from sigfig import round from validator_collection import validators +from archetypal.template import GasMaterial from archetypal.template.materials.material_base import MaterialBase from archetypal.utils import log @@ -119,7 +120,11 @@ def ThermalEmittance(self): @ThermalEmittance.setter def ThermalEmittance(self, value): - self._thermal_emittance = validators.float(value, minimum=0, maximum=1) + if value == "" or value is None: + value = 0.9 + self._thermal_emittance = validators.float( + value, minimum=0, maximum=1, allow_empty=True + ) @property def VisibleAbsorptance(self): @@ -128,6 +133,8 @@ def VisibleAbsorptance(self): @VisibleAbsorptance.setter def VisibleAbsorptance(self, value): + if value == "" or value is None or value is None: + value = 0.7 self._visible_absorptance = validators.float( value, minimum=0, maximum=1, allow_empty=True ) @@ -299,7 +306,6 @@ def from_epbunch(cls, epbunch, **kwargs): ThermalEmittance=epbunch.Thermal_Absorptance, VisibleAbsorptance=epbunch.Visible_Absorptance, Name=epbunch.Name, - idf=epbunch.theidf, **kwargs, ) elif epbunch.key.upper() == "MATERIAL:NOMASS": @@ -313,41 +319,12 @@ def from_epbunch(cls, epbunch, **kwargs): ThermalEmittance=epbunch.Thermal_Absorptance, VisibleAbsorptance=epbunch.Visible_Absorptance, Name=epbunch.Name, - idf=epbunch.theidf, **kwargs, ) elif epbunch.key.upper() == "MATERIAL:AIRGAP": gas_prop = { - "AIR": dict( - Conductivity=0.02436, - Density=1.754, - SpecificHeat=1000, - ThermalEmittance=0.001, - ), - "ARGON": dict( - Conductivity=0.016, - Density=1.784, - SpecificHeat=1000, - ThermalEmittance=0.001, - ), - "KRYPTON": dict( - Conductivity=0.0088, - Density=3.749, - SpecificHeat=1000, - ThermalEmittance=0.001, - ), - "XENON": dict( - Conductivity=0.0051, - Density=5.761, - SpecificHeat=1000, - ThermalEmittance=0.001, - ), - "SF6": dict( - Conductivity=0.001345, - Density=6.17, - SpecificHeat=1000, - ThermalEmittance=0.001, - ), + obj.Name.upper(): obj.mapping() + for obj in [GasMaterial(gas_name) for gas_name in GasMaterial._GASTYPES] } for gasname, properties in gas_prop.items(): if gasname.lower() in epbunch.Name.lower(): @@ -356,7 +333,6 @@ def from_epbunch(cls, epbunch, **kwargs): Name=epbunch.Name, Thickness=thickness, **properties, - idf=epbunch.theidf, ) else: thickness = ( @@ -366,7 +342,6 @@ def from_epbunch(cls, epbunch, **kwargs): Name=epbunch.Name, Thickness=thickness, **gas_prop["AIR"], - idf=epbunch.theidf, ) else: raise NotImplementedError( @@ -386,6 +361,7 @@ def to_epbunch(self, idf): """ return idf.newidfobject( "MATERIAL:NOMASS", + Name=self.Name, Roughness=self.Roughness, Thermal_Resistance=self.r_value, Thermal_Absorptance=self.ThermalEmittance, @@ -461,26 +437,25 @@ def __eq__(self, other): if not isinstance(other, NoMassMaterial): return NotImplemented else: - return all( - [ - self.r_value == other.r_value, - self.SolarAbsorptance == other.SolarAbsorptance, - self.ThermalEmittance == other.ThermalEmittance, - self.VisibleAbsorptance == other.VisibleAbsorptance, - self.Roughness == other.Roughness, - self.Cost == other.Cost, - self.MoistureDiffusionResistance - == self.MoistureDiffusionResistance, - self.EmbodiedCarbon == other.EmbodiedCarbon, - self.EmbodiedEnergy == other.EmbodiedEnergy, - self.TransportCarbon == other.TransportCarbon, - self.TransportDistance == other.TransportDistance, - self.TransportEnergy == other.TransportEnergy, - np.array_equal( - self.SubstitutionRatePattern, other.SubstitutionRatePattern - ), - self.SubstitutionTimestep == other.SubstitutionTimestep, - ] + return self.__key__() == other.__key__() + + def __key__(self): + """Get a tuple of attributes. Useful for hashing and comparing.""" + return ( + self.r_value, + self.SolarAbsorptance, + self.ThermalEmittance, + self.VisibleAbsorptance, + self.Roughness, + self.Cost, + self.MoistureDiffusionResistance, + self.EmbodiedCarbon, + self.EmbodiedEnergy, + self.TransportCarbon, + self.TransportDistance, + self.TransportEnergy, + self.SubstitutionRatePattern, + self.SubstitutionTimestep, ) def __copy__(self): diff --git a/archetypal/template/materials/opaque_material.py b/archetypal/template/materials/opaque_material.py index 413c9644..437787b0 100644 --- a/archetypal/template/materials/opaque_material.py +++ b/archetypal/template/materials/opaque_material.py @@ -34,6 +34,7 @@ class OpaqueMaterial(MaterialBase): "_moisture_diffusion_resistance", "_conductivity", "_density", + "_key" ) def __init__( @@ -117,6 +118,9 @@ def __init__( self.VisibleAbsorptance = VisibleAbsorptance self.MoistureDiffusionResistance = MoistureDiffusionResistance + self._key: str = kwargs.get("_key", "") + # TODO: replace when NoMass and AirGap is properly supported + @property def Conductivity(self): """Get or set the conductivity of the material [W/m-K].""" @@ -414,6 +418,7 @@ def from_epbunch(cls, epbunch, **kwargs): ThermalEmittance=epbunch.Thermal_Absorptance, VisibleAbsorptance=epbunch.Visible_Absorptance, Name=epbunch.Name, + _key=epbunch.key.upper(), **kwargs, ) elif epbunch.key.upper() == "MATERIAL:AIRGAP": @@ -429,6 +434,7 @@ def from_epbunch(cls, epbunch, **kwargs): Name=epbunch.Name, Thickness=thickness, SpecificHeat=100.5, + _key=epbunch.key.upper(), **properties, ) else: @@ -440,6 +446,7 @@ def from_epbunch(cls, epbunch, **kwargs): Name=epbunch.Name, Thickness=thickness, SpecificHeat=100.5, + _key=epbunch.key.upper(), **gas_prop["AIR"], ) else: @@ -472,18 +479,36 @@ def to_epbunch(self, idf, thickness) -> EpBunch: Returns: EpBunch: The EpBunch object added to the idf model. """ - return idf.newidfobject( - "MATERIAL", - Name=self.Name, - Roughness=self.Roughness, - Thickness=thickness, - Conductivity=self.Conductivity, - Density=self.Density, - Specific_Heat=self.SpecificHeat, - Thermal_Absorptance=self.ThermalEmittance, - Solar_Absorptance=self.SolarAbsorptance, - Visible_Absorptance=self.VisibleAbsorptance, - ) + if self._key == "MATERIAL:NOMASS": + # Special case for Material:NoMass + return idf.newidfobject( + "MATERIAL:NOMASS", + Name=self.Name, + Roughness=self.Roughness, + Thermal_Resistance=thickness / self.Conductivity, + Thermal_Absorptance=self.ThermalEmittance, + Solar_Absorptance=self.SolarAbsorptance, + Visible_Absorptance=self.VisibleAbsorptance, + ) + elif self._key == "MATERIAL:AIRGAP": + return idf.newidfobject( + "MATERIAL:AIRGAP", + Name=self.Name, + Thermal_Resistance=thickness / self.Conductivity, + ) + else: + return idf.newidfobject( + "MATERIAL", + Name=self.Name, + Roughness=self.Roughness, + Thickness=thickness, + Conductivity=self.Conductivity, + Density=self.Density, + Specific_Heat=self.SpecificHeat, + Thermal_Absorptance=self.ThermalEmittance, + Solar_Absorptance=self.SolarAbsorptance, + Visible_Absorptance=self.VisibleAbsorptance, + ) def validate(self): """Validate object and fill in missing values. diff --git a/tests/test_idfclass.py b/tests/test_idfclass.py index 7e1a38ce..95212c41 100644 --- a/tests/test_idfclass.py +++ b/tests/test_idfclass.py @@ -250,7 +250,7 @@ def idf(self, request): def test_init_version(self, idf): """Test creation of in-memory IDF file""" - assert idf.file_version.dot == settings.ep_version + assert idf.file_version.dash == settings.ep_version # test another instance in this session with a different version number. idf = IDF(as_version="8-9-0") diff --git a/tests/test_version.py b/tests/test_version.py index b6896f46..8df39ab5 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -46,4 +46,4 @@ def test_idd_on_missing_install(self): idd_version = EnergyPlusVersion("9.2") idd_version._valid_paths = {} # fakes not finding any versions on machine. - assert idd_version.valid_versions == {"9-2-0"} + assert idd_version.valid_versions == {"9-2-0",}