Source code for fairyfly_therm.material.solid

# coding=utf-8
"""Solid THERM material."""
from __future__ import division
import xml.etree.ElementTree as ET

from fairyfly._lockable import lockable
from fairyfly.typing import float_in_range, float_positive, uuid_from_therm_id

from ._base import _ThermMaterialBase


[docs] @lockable class SolidMaterial(_ThermMaterialBase): """Typical conductive material. Args: conductivity: Number for the thermal conductivity of the material [W/m-K]. emissivity: Number between 0 and 1 for the infrared hemispherical emissivity of the front side of the material. (Default: 0.9). emissivity_back: Number between 0 and 1 for the infrared hemispherical emissivity of the back side of the material. If None, this will default to the same value specified for emissivity. (Default: None) density: Optional number for the density of the material [kg/m3]. (Default: None). porosity: Optional number between zero and one for the porosity of the material. (Default: None). specific_heat: Optional number for the specific heat of the material [J/kg-K]. If None, it is not included in the export. (Default: None). vapor_diffusion_resistance: Optional number for the water vapor diffusion resistance factor [Dimensionless]. (Default: None). identifier: Text string for a unique object ID. Must be a UUID in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. If None, a UUID will automatically be generated. (Default: None). Properties: * identifier * display_name * conductivity * emissivity * emissivity_back * density * porosity * specific_heat * vapor_diffusion_resistance * resistivity * color * protected * user_data """ __slots__ = ('_conductivity', '_emissivity', '_emissivity_back', '_density', '_porosity', '_specific_heat', '_vapor_diffusion_resistance') def __init__( self, conductivity, emissivity=0.9, emissivity_back=None, density=None, porosity=None, specific_heat=None, vapor_diffusion_resistance=None, identifier=None ): """Initialize therm material.""" _ThermMaterialBase.__init__(self, identifier) self.conductivity = conductivity self.emissivity = emissivity self.emissivity_back = emissivity_back self.density = density self.porosity = porosity self.specific_heat = specific_heat self.vapor_diffusion_resistance = vapor_diffusion_resistance @property def conductivity(self): """Get or set the conductivity of the material layer [W/m-K].""" return self._conductivity @conductivity.setter def conductivity(self, cond): self._conductivity = float_positive(cond, 'material conductivity') assert self._conductivity != 0, 'Conductivity cannot be equal to zero.' @property def emissivity(self): """Get or set the hemispherical emissivity of the front side of the material.""" return self._emissivity @emissivity.setter def emissivity(self, ir_e): ir_e = float_in_range(ir_e, 0.0, 1.0, 'material emissivity') self._emissivity = ir_e @property def emissivity_back(self): """Get or set the hemispherical emissivity of the back side of the material.""" return self._emissivity_back if self._emissivity_back is not None \ else self._emissivity @emissivity_back.setter def emissivity_back(self, ir_e): if ir_e is not None: ir_e = float_in_range(ir_e, 0.0, 1.0, 'material emissivity') self._emissivity_back = ir_e @property def density(self): """Get or set the density of the material layer [kg/m3].""" return self._density @density.setter def density(self, value): if value is not None: value = float_positive(value, 'material density') self._density = value @property def porosity(self): """Get or set a number between zero and one for the porosity.""" return self._porosity @porosity.setter def porosity(self, value): if value is not None: value = float_in_range(value, 0.0, 1.0, 'material porosity') self._porosity = value @property def specific_heat(self): """Get or set the specific heat of the material layer [J/kg-K].""" return self._specific_heat @specific_heat.setter def specific_heat(self, value): if value is not None: value = float_positive(value, 'material specific heat') self._specific_heat = value @property def vapor_diffusion_resistance(self): """Get or set the vapor diffusion resistance of the material.""" return self._vapor_diffusion_resistance @vapor_diffusion_resistance.setter def vapor_diffusion_resistance(self, value): if value is not None: value = float_positive(value, 'vapor diffusion resistance') self._vapor_diffusion_resistance = value @property def resistivity(self): """Get or set the resistivity of the material layer [m-K/W].""" return 1 / self._conductivity @resistivity.setter def resistivity(self, resis): self._conductivity = 1 / float_positive(resis, 'material resistivity')
[docs] @classmethod def from_therm_xml(cls, xml_element): """Create a SolidMaterial from an XML element of a THERM Material. Args: xml_element: An XML element of a THERM material. """ # create the base material from the UUID and conductivity xml_uuid = xml_element.find('UUID') identifier = xml_uuid.text if len(identifier) == 31: identifier = uuid_from_therm_id(identifier) xml_solid = xml_element.find('Solid') xml_hyt = xml_solid.find('HygroThermal') xml_cond = xml_hyt.find('ThermalConductivityDry') conductivity = xml_cond.text mat = SolidMaterial(conductivity, identifier=identifier) # assign the other hygrothermal attributes if specified xml_dens = xml_hyt.find('BulkDensity') if xml_dens is not None: mat.density = xml_dens.text xml_por = xml_hyt.find('Porosity') if xml_por is not None: mat.porosity = xml_por.text xml_shc = xml_hyt.find('SpecificHeatCapacityDry') if xml_shc is not None: mat.specific_heat = xml_shc.text xml_vdr = xml_hyt.find('WaterVaporDiffusionResistanceFactor') if xml_vdr is not None: mat.vapor_diffusion_resistance = xml_vdr.text # assign the optical properties if specified xml_optical = xml_solid.find('Optical') if xml_optical is not None: xml_int = xml_optical.find('Integrated') if xml_int is not None: xml_inf = xml_int.find('Infrared') if xml_inf is not None: xml_emiss = xml_inf.find('Emissivity-Front') if xml_emiss is not None: mat.emissivity = xml_emiss.text xml_emiss_b = xml_inf.find('Emissivity-Back') if xml_emiss_b is not None: mat.emissivity_back = xml_emiss_b.text # assign the name and color if they are specified xml_name = xml_element.find('Name') if xml_name is not None: mat.display_name = xml_name.text xml_col = xml_element.find('Color') if xml_col is not None: mat.color = xml_col.text xml_protect = xml_element.find('Protected') if xml_protect is not None: mat.protected = True if xml_protect.text == 'true' else False return mat
[docs] @classmethod def from_therm_xml_str(cls, xml_str): """Create a SolidMaterial from an XML text string of a THERM Material. Args: xml_str: An XML text string of a THERM material. """ root = ET.fromstring(xml_str) return cls.from_therm_xml(root)
[docs] @classmethod def from_dict(cls, data): """Create a SolidMaterial from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "type": 'SolidMaterial', "identifier": 'f26f3597-e3ee-43fe-a0b3-ec673f993d86', "display_name": 'Concrete', "conductivity": 2.31, "emissivity": 0.9, "emissivity_back": 0.9, "density": 2322, "porosity": 0.24, "specific_heat": 832, "vapor_diffusion_resistance": 19 } """ assert data['type'] == 'SolidMaterial', \ 'Expected SolidMaterial. Got {}.'.format(data['type']) emiss = data['emissivity'] if 'emissivity' in data and \ data['emissivity'] is not None else 0.9 emiss_b = data['emissivity_back'] if 'emissivity_back' in data else None dens = data['density'] if 'density' in data else None poro = data['porosity'] if 'porosity' in data else None s_heat = data['specific_heat'] if 'specific_heat' in data else None vdr = data['vapor_diffusion_resistance'] \ if 'vapor_diffusion_resistance' in data else None new_mat = cls( data['conductivity'], emiss, emiss_b, dens, poro, s_heat, vdr, data['identifier']) if 'display_name' in data and data['display_name'] is not None: new_mat.display_name = data['display_name'] if 'color' in data and data['color'] is not None: new_mat.color = data['color'] if 'protected' in data and data['protected'] is not None: new_mat.protected = data['protected'] if 'user_data' in data and data['user_data'] is not None: new_mat.user_data = data['user_data'] return new_mat
[docs] def to_therm_xml(self, materials_element=None): """Get an THERM XML element of the material. Args: materials_element: An optional XML Element for the Materials to which the generated objects will be added. If None, a new XML Element will be generated. .. code-block:: xml <Material> <UUID>1543f77f-e4aa-47d4-b7bf-2365d7bc0b9d</UUID> <Name>Polyurethane Foam</Name> <Protected>false</Protected> <Color>0xFFFFC1</Color> <Solid> <HygroThermal> <ThermalConductivityDry>0.05</ThermalConductivityDry> </HygroThermal> <Optical> <Integrated> <Infrared> <Emissivity-Front>0.9</Emissivity-Front> <Emissivity-Back>0.9</Emissivity-Back> </Infrared> </Integrated> </Optical> </Solid> </Material> """ # create a new Materials element if one is not specified if materials_element is not None: xml_mat = ET.SubElement(materials_element, 'Material') else: xml_mat = ET.Element('Material') # add all of the required basic attributes xml_id = ET.SubElement(xml_mat, 'UUID') xml_id.text = self.identifier xml_name = ET.SubElement(xml_mat, 'Name') xml_name.text = self.display_name xml_protect = ET.SubElement(xml_mat, 'Protected') xml_protect.text = 'true' if self.protected else 'false' xml_color = ET.SubElement(xml_mat, 'Color') xml_color.text = self.color.to_hex().replace('#', '0x') xml_solid = ET.SubElement(xml_mat, 'Solid') # add all of the required hygrothermal and optical attributes xml_hyt = ET.SubElement(xml_solid, 'HygroThermal') xml_cond = ET.SubElement(xml_hyt, 'ThermalConductivityDry') xml_cond.text = str(self.conductivity) xml_optical = ET.SubElement(xml_solid, 'Optical') xml_int = ET.SubElement(xml_optical, 'Integrated') xml_inf = ET.SubElement(xml_int, 'Infrared') xml_emiss = ET.SubElement(xml_inf, 'Emissivity-Front') xml_emiss.text = str(self.emissivity) xml_emiss_b = ET.SubElement(xml_inf, 'Emissivity-Back') xml_emiss_b.text = str(self.emissivity_back) # add any of the optional hygrothermal attributes if self.density is not None: xml_dens = ET.SubElement(xml_hyt, 'BulkDensity') xml_dens.text = str(self.density) if self.porosity is not None: xml_por = ET.SubElement(xml_hyt, 'Porosity') xml_por.text = str(self.porosity) if self.specific_heat is not None: xml_shc = ET.SubElement(xml_hyt, 'SpecificHeatCapacityDry') xml_shc.text = str(self.specific_heat) if self.vapor_diffusion_resistance is not None: xml_vdr = ET.SubElement(xml_hyt, 'WaterVaporDiffusionResistanceFactor') xml_vdr.text = str(self.vapor_diffusion_resistance) return xml_mat
[docs] def to_therm_xml_str(self): """Get an THERM XML string of the material.""" xml_root = self.to_therm_xml() try: # try to indent the XML to make it read-able ET.indent(xml_root) return ET.tostring(xml_root, encoding='unicode') except AttributeError: # we are in Python 2 and no indent is available return ET.tostring(xml_root)
[docs] def to_dict(self): """SolidMaterial dictionary representation.""" base = { 'type': 'SolidMaterial', 'identifier': self.identifier, 'conductivity': self.conductivity, 'emissivity': self.emissivity } if self._emissivity_back is not None: base['emissivity_back'] = self._emissivity_back if self._density is not None: base['density'] = self._density if self._porosity is not None: base['porosity'] = self.porosity if self._specific_heat is not None: base['specific_heat'] = self.specific_heat if self._vapor_diffusion_resistance is not None: base['vapor_diffusion_resistance'] = self.vapor_diffusion_resistance if self._display_name is not None: base['display_name'] = self.display_name base['protected'] = self._protected base['color'] = self.color.to_hex() if self._user_data is not None: base['user_data'] = self.user_data return base
def __key(self): """A tuple based on the object properties, useful for hashing.""" return (self.identifier, self.conductivity, self.emissivity, self.emissivity_back, self.density, self.porosity, self.specific_heat, self.vapor_diffusion_resistance) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, SolidMaterial) and self.__key() == other.__key() def __ne__(self, other): return not self.__eq__(other) def __copy__(self): new_material = self.__class__( self.conductivity, self._emissivity, self._emissivity_back, self._density, self._porosity, self._specific_heat, self._vapor_diffusion_resistance, self.identifier) new_material._display_name = self._display_name new_material._color = self._color new_material._protected = self._protected new_material._user_data = None if self._user_data is None \ else self._user_data.copy() return new_material def __repr__(self): return 'Solid THERM Material: {}'.format(self.display_name)