Source code for fairyfly_therm.condition.steadystate

# coding=utf-8
"""SteadyState THERM condition."""
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 _ThermConditionBase


[docs] @lockable class SteadyState(_ThermConditionBase): """Typical steady state condition. Args: temperature: A number for the temperature at the boundary in degrees Celsius. For NFRC conditions, this temperature should be 21C for interior boundary conditions and -18 C for winter exterior boundary conditions. film_coefficient: A number in W/m2-K that represents the convective resistance of the air film at the boundary condition. Typical film coefficient values range from 36 W/m2-K (for an exterior condition where outdoor wind strips away most convective resistance) to 2.5 W/m2-K (for a vertically-oriented interior wood/vinyl surface). For NFRC conditions, this should be 26 for exterior boundary conditions and around 3 for interior boundary conditions. emissivity: An optional number between 0 and 1 to set the emissivity along the boundary, which represents the emissivity of the environment to which the material in contact with the boundary is radiating to. (Default: 1). radiant_temperature: A number for the radiant temperature at the boundary in degrees Celsius. If None, this will be the same as the specified temperature. (Default: None). heat_flux: An optional number in W/m2 that represents additional energy flux across the boundary. This can be used to account for solar flux among other forms of heat flux. (Default: 0). relative_humidity: An optional value between 0 and 1 for the relative humidity along the boundary. (Default: 0.5). 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 * temperature * film_coefficient * emissivity * radiant_temperature * heat_flux * relative_humidity * color * protected * project_tag * user_data """ __slots__ = ('_temperature', '_film_coefficient', '_emissivity', '_radiant_temperature', '_heat_flux', '_relative_humidity') def __init__( self, temperature, film_coefficient, emissivity=1.0, radiant_temperature=None, heat_flux=0, relative_humidity=0.5, identifier=None ): """Initialize therm material.""" _ThermConditionBase.__init__(self, identifier) self.temperature = temperature self.film_coefficient = film_coefficient self.emissivity = emissivity self.radiant_temperature = radiant_temperature self.heat_flux = heat_flux self.relative_humidity = relative_humidity @property def temperature(self): """Get or set the temperature of the condition [C].""" return self._temperature @temperature.setter def temperature(self, value): self._temperature = \ float_in_range(value, mi=-273.15, input_name='condition temperature') @property def film_coefficient(self): """Get or set the film coefficient along the boundary [ W/m2-K].""" return self._film_coefficient @film_coefficient.setter def film_coefficient(self, value): self._film_coefficient = float_positive(value, 'film coefficient') @property def emissivity(self): """Get or set the hemispherical emissivity of the environment of the condition. """ return self._emissivity @emissivity.setter def emissivity(self, ir_e): ir_e = float_in_range(ir_e, 0.0, 1.0, 'condition emissivity') self._emissivity = ir_e @property def radiant_temperature(self): """Get or set the radiant temperature along the boundary.""" return self._radiant_temperature if self._radiant_temperature is not None \ else self._temperature @radiant_temperature.setter def radiant_temperature(self, ir_t): if ir_t is not None: ir_t = float_in_range(ir_t, mi=-273.15, input_name='condition radiant temperature') self._radiant_temperature = ir_t @property def heat_flux(self): """Get or set the additional energy flux across the boundary [W/m2].""" return self._heat_flux @heat_flux.setter def heat_flux(self, value): self._heat_flux = float_positive(value, 'condition heat flux') @property def relative_humidity(self): """Get or set a number between zero and one for the relative humidity.""" return self._relative_humidity @relative_humidity.setter def relative_humidity(self, value): self._relative_humidity = \ float_in_range(value, 0.0, 1.0, 'condition relative humidity')
[docs] @classmethod def from_therm_xml(cls, xml_element): """Create SteadyState from an XML element of a THERM BoundaryCondition. Args: xml_element: An XML element of a THERM BoundaryCondition. """ # create the base material from the UUID, temperature, and film coefficient xml_uuid = xml_element.find('UUID') identifier = xml_uuid.text if len(identifier) == 31: identifier = uuid_from_therm_id(identifier) xml_comp = xml_element.find('Comprehensive') xml_conv = xml_comp.find('Convection') xml_t = xml_conv.find('Temperature') temperature = xml_t.text xml_fc = xml_conv.find('FilmCoefficient') film_coefficient = xml_fc.text cond = SteadyState(temperature, film_coefficient, identifier=identifier) # assign the other attributes if specified xml_rh = xml_comp.find('RelativeHumidity') if xml_rh is not None: cond.relative_humidity = xml_rh.text xml_flux = xml_comp.find('ConstantFlux') if xml_flux is not None: xml_fl = xml_flux.find('Flux') if xml_fl is not None: cond.heat_flux = xml_fl.text # assign the radiation properties if specified xml_rad = xml_comp.find('Radiation') if xml_rad is not None: xml_rm = xml_rad.find('AutomaticEnclosure') if xml_rm is not None: xml_rm = xml_rad.find('BlackBodyRadiation') if xml_rm is not None: xml_mrt = xml_rm.find('Temperature') if xml_mrt is not None: cond.radiant_temperature = xml_mrt.text xml_emiss = xml_rm.find('Emissivity') if xml_emiss is not None: cond.emissivity = xml_emiss.text # assign the name and color if they are specified xml_name = xml_element.find('Name') if xml_name is not None: cond.display_name = xml_name.text xml_col = xml_element.find('Color') if xml_col is not None: cond.color = xml_col.text xml_protect = xml_element.find('Protected') if xml_protect is not None: cond.protected = True if xml_protect.text == 'true' else False xml_tag = xml_element.find('ProjectNameTag') if xml_tag is not None: cond.project_tag = xml_tag.text return cond
[docs] @classmethod def from_therm_xml_str(cls, xml_str): """Create SteadyState from an XML string of a THERM BoundaryCondition. Args: xml_str: An XML text string of a THERM BoundaryCondition. """ root = ET.fromstring(xml_str) return cls.from_therm_xml(root)
[docs] @classmethod def from_dict(cls, data): """Create a SteadyState from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "type": 'SteadyState', "identifier": 'f26f3597-e3ee-43fe-a0b3-ec673f993d86', "display_name": 'NFRC 100-2010 Exterior', "temperature": -18, "film_coefficient": 26, "emissivity": 1, "radiant_temperature": -18, "heat_flux": 0, "relative_humidity": 0.5 } """ assert data['type'] == 'SteadyState', \ 'Expected SteadyState. Got {}.'.format(data['type']) emiss = data['emissivity'] if 'emissivity' in data and \ data['emissivity'] is not None else 1.0 rad_temp = data['radiant_temperature'] if 'radiant_temperature' in data else None heat_flux = data['heat_flux'] if 'heat_flux' in data else 0 rh = data['relative_humidity'] if 'relative_humidity' in data else 0.5 new_cond = cls( data['temperature'], data['film_coefficient'], emiss, rad_temp, heat_flux, rh, data['identifier'] ) if 'display_name' in data and data['display_name'] is not None: new_cond.display_name = data['display_name'] if 'color' in data and data['color'] is not None: new_cond.color = data['color'] if 'protected' in data and data['protected'] is not None: new_cond.protected = data['protected'] if 'project_tag' in data and data['project_tag']: new_cond._project_tag = data['project_tag'] if 'user_data' in data and data['user_data'] is not None: new_cond.user_data = data['user_data'] return new_cond
[docs] def to_therm_xml(self, bcs_element=None): """Get an THERM XML element of the boundary condition. Args: bcs_element: An optional XML Element for the BoundaryConditions to which the generated objects will be added. If None, a new XML Element will be generated. .. code-block:: xml <BoundaryCondition> <UUID>1810f37a-de4d-4e2d-95d5-09fe01157c34</UUID> <Name>NFRC 100-2010 Exterior</Name> <ProjectNameTag></ProjectNameTag> <Protected>true</Protected> <Color>0x0080C0</Color> <IGUSurface>false</IGUSurface> <Comprehensive> <RelativeHumidity>0.5</RelativeHumidity> <Convection> <Temperature>-18</Temperature> <FilmCoefficient>26</FilmCoefficient> </Convection> <ConstantFlux> <Flux>0</Flux> </ConstantFlux> <Radiation> <BlackBodyRadiation> <Temperature>-18</Temperature> <Emissivity>1</Emissivity> <ViewFactor>1</ViewFactor> </BlackBodyRadiation> </Radiation> </Comprehensive> </BoundaryCondition> """ # create a new Materials element if one is not specified if bcs_element is not None: xml_cond = ET.SubElement(bcs_element, 'BoundaryCondition') else: xml_cond = ET.Element('BoundaryCondition') # add all of the required basic attributes xml_id = ET.SubElement(xml_cond, 'UUID') xml_id.text = self.identifier xml_name = ET.SubElement(xml_cond, 'Name') xml_name.text = self.display_name if self.project_tag: xml_tag = ET.SubElement(xml_cond, 'ProjectNameTag') xml_tag.text = self.project_tag xml_protect = ET.SubElement(xml_cond, 'Protected') xml_protect.text = 'true' if self.protected else 'false' xml_color = ET.SubElement(xml_cond, 'Color') xml_color.text = self.color.to_hex().replace('#', '0x') xml_igu = ET.SubElement(xml_cond, 'IGUSurface') xml_igu.text = 'false' if self.film_coefficient == 0: # translate the condition as simple xml_simple = ET.SubElement(xml_cond, 'Simplified') xml_rh = ET.SubElement(xml_simple, 'RelativeHumidity') xml_rh.text = str(self.relative_humidity) xml_fc = ET.SubElement(xml_simple, 'FilmCoefficient') xml_fc = '0' xml_ct = ET.SubElement(xml_simple, 'Temperature') xml_ct.text = str(self.temperature) else: # add all of the comprehensive attributes xml_comp = ET.SubElement(xml_cond, 'Comprehensive') xml_rh = ET.SubElement(xml_comp, 'RelativeHumidity') xml_rh.text = str(self.relative_humidity) xml_conv = ET.SubElement(xml_comp, 'Convection') xml_ct = ET.SubElement(xml_conv, 'Temperature') xml_ct.text = str(self.temperature) xml_fc = ET.SubElement(xml_conv, 'FilmCoefficient') xml_fc.text = str(self.film_coefficient) xml_heat = ET.SubElement(xml_comp, 'ConstantFlux') xml_flux = ET.SubElement(xml_heat, 'Flux') xml_flux.text = str(self.heat_flux) xml_rad = ET.SubElement(xml_comp, 'Radiation') xml_auto = ET.SubElement(xml_rad, 'AutomaticEnclosure') xml_mrt = ET.SubElement(xml_auto, 'Temperature') xml_mrt.text = str(self.radiant_temperature) xml_emiss = ET.SubElement(xml_auto, 'Emissivity') xml_emiss.text = str(self.emissivity) return xml_cond
[docs] def to_therm_xml_str(self): """Get an THERM XML string of the condition.""" 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): """SteadyState dictionary representation.""" base = { 'type': 'SteadyState', 'identifier': self.identifier, 'temperature': self.temperature, 'film_coefficient': self.film_coefficient } if self.emissivity != 1: base['emissivity'] = self.emissivity if self._radiant_temperature is not None: base['radiant_temperature'] = self._radiant_temperature if self.heat_flux != 0: base['heat_flux'] = self.heat_flux if self._relative_humidity != 0.5: base['relative_humidity'] = self.relative_humidity 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._project_tag is not None: base['project_tag'] = self.project_tag if self._user_data is not None: base['user_data'] = self.user_data return base
[docs] @staticmethod def extract_all_from_xml_file(xml_file): """Extract all Condition objects from a THERM XML file. Args: xml_file: A path to an XML file containing objects Condition objects. Returns: A list of all Comprehensive Condition objects in the file. """ # read the file and get the root tree = ET.parse(xml_file) root = tree.getroot() # extract all of the PureGas objects conditions = [] for con_obj in root: if con_obj.tag == 'BoundaryCondition' and \ con_obj.find('Comprehensive') is not None: SteadyState.from_therm_xml(con_obj) try: conditions.append(SteadyState.from_therm_xml(con_obj)) except Exception: # not a valid conditions pass return conditions
def __key(self): """A tuple based on the object properties, useful for hashing.""" return (self.identifier, self.temperature, self.film_coefficient, self.emissivity, self.radiant_temperature, self.heat_flux, self.relative_humidity) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, SteadyState) and self.__key() == other.__key() def __ne__(self, other): return not self.__eq__(other) def __copy__(self): new_cond = self.__class__( self.temperature, self.film_coefficient, self._emissivity, self._radiant_temperature, self._heat_flux, self._relative_humidity, self.identifier ) new_cond._display_name = self._display_name new_cond._color = self._color new_cond._protected = self._protected new_cond._project_tag = self._project_tag new_cond._user_data = None if self._user_data is None \ else self._user_data.copy() return new_cond def __repr__(self): return 'Comprehensive THERM Condition: {}'.format(self.display_name)