Source code for uwg.building

"""Class of specified building characteristics."""
from __future__ import division

from .psychrometrics import psychrometrics, moist_air_density
from .utilities import is_near_zero, float_in_range, float_positive

try:
    str = basestring
except NameError:
    pass


[docs]class Building(object): """Specified building characteristics. Args: floor_height: Floor height in meters. int_heat_night: Nighttime internal sensible heat gain [W/m2]. int_heat_day: Daytime internal sensible heat gain [W/m2]. int_heat_frad: Value between 0 and 1 for radiant fraction of internal gains. int_heat_flat: Value between 0 and 1 for latent fraction of internal gains. infil: Infiltration rate (ACH). vent: Ventilation rate (ACH). glazing_ratio: Value between 0 and 1 for glazing ratio. u_value: Window U-value including film coefficent [W/(m2-K)]. shgc: Value between 0 and 1 for window Solar Heat Gain Coefficient (SHGC). condtype: Text string for cooling condensation system type. Choose from AIR or WATER. cop: Coefficient of Performance (COP) of cooling system (nominal). coolcap: Rated cooling system capacity [W/m2]. heateff: Heating system capacity. initial_temp: Initial indoor air temperature [K]. Properties: * floor_height -- floor height (m) * int_heat -- timestep internal heat gains (W m-2 bld) (sensible only) * int_heat_night -- nighttime internal heat gains (W m-2 floor) * int_heat_day -- daytime internal heat gains (W m-2 floor) * int_heat_frad -- radiant fraction of internal gains * int_heat_flat -- latent fraction of internal gains * infil -- Infiltration (ACH) * vent -- Ventilation (m^3/s/m^2) * glazing_ratio -- glazing ratio * u_value -- window U-value (W m-2 K-1) (including film coeff) * shgc -- window SHGC * condtype -- cooling condensation system type {'AIR', 'WATER'} * cop -- COP of the cooling system (nominal) * cop_adj -- adjusted COP per temperature * cool_setpoint_day -- daytime indoor cooling set-point (K) * cool_setpoint_night -- nighttime indoor cooling set-point (K) * heat_setpoint_day -- daytime indoor heating set-point (K) * heat_setpoint_night -- nighttime indoor heating set-point (K) * heat_cap -- rated heating system capacity (W m-2) * heateff -- heating system efficiency (-) * canyon_fraction -- fraction of waste heat released to canyon, default = 1 * msys -- HVAC supply mass flowrate (kg s-1 m-2) * indoor_temp -- indoor air temperature (K) * indoor_hum -- indoor specific humidity (kg / kg) * Twb -- wetbulb temperature * Tdp -- dew point * indoorRhum -- indoor relative humidity * area_floor -- total floor space of the BEM * FanMax -- max fan flow rate (m^3/s) per DOE * nFloor -- number of floors * RadFOcc -- Radiant fraction of occupant * LatFOcc -- Latent fraction of occupant * RadFEquip -- Radiant fraction of equipment * RadFLight -- Radiant fraction of light * sensCoolDemand -- building sensible cooling demand (W m-2) * sensHeatDemand -- building sensible heating demand (W m-2) * copAdj -- adjusted COP per temperature * dehumDemand -- dehumidification energy (W m-2) * coolConsump -- cooling energy consumption (W m-2) * heatConsump -- heating energy consumption (W m-2) * sensWaste -- sensible waste heat (W m-2) * latWaste -- lat waste heat (W m-2) * fluxMass -- mass surface heat flux (W m-2) (mass to indoor air) * fluxWall -- wall surface heat flux (W m-2) (wall to inside) * fluxRoof -- roof surface heat flux (W m-2) (roof to inside) * fluxSolar -- solar heat gain (W m-2) through window (SHGC) * fluxWindow -- heat gain/loss from window (U-value) * fluxInterior -- internal heat gain adjusted for latent/LW heat (W m-2) * fluxInfil -- heat flux from infiltration (W m-2) * fluxVent -- heat flux from ventilation (W m-2) * ElecTotal -- total electricity consumption - (W/m^2) of floor * GasTotal -- total gas consumption - (W/m^2) of floor * Qhvac -- total heat removed (sensible + latent) * Qheat -- total heat added (sensible only) """ TEMP_COEF_CONFLICT_MSG = \ 'FATAL ERROR! Try running a shorter simulation (for a fraction of the year)\n' \ 'or try increasing the simulation timesteps per hour' def __init__(self, floor_height, int_heat_night, int_heat_day, int_heat_frad, int_heat_flat, infil, vent, glazing_ratio, u_value, shgc, condtype, cop, coolcap, heateff, initial_temp): self.floor_height = floor_height self.int_heat = int_heat_night self.int_heat_night = int_heat_night self.int_heat_day = int_heat_day self.int_heat_frad = int_heat_frad self.int_heat_flat = int_heat_flat self.infil = infil self.vent = vent self.glazing_ratio = glazing_ratio self.u_value = u_value self.shgc = shgc self.condtype = condtype self.cop = cop self.coolcap = coolcap self.heateff = heateff self.initial_temp = initial_temp self.indoor_temp = initial_temp self.cop_adj = cop # set properties self.indoor_hum = 0.012 self.heat_cap = 999 self.canyon_fraction = 1.0 self.cool_setpoint_day = 297 # 24 C self.cool_setpoint_night = 297 # 24 C self.heat_setpoint_day = 293 # 24 C self.heat_setpoint_night = 293 # 24 C self.msys = \ coolcap / 1004. / (min(self.cool_setpoint_day, self.cool_setpoint_night) - 14 - 273.15) @property def floor_height(self): """Get or set floor height in meters.""" return self._floor_height @floor_height.setter def floor_height(self, value): self._floor_height = float_positive(value, 'floor_height') @property def int_heat_night(self): """Get or set nighttime internal sensible heat gain [W/m2].""" return self._int_heat_night @int_heat_night.setter def int_heat_night(self, value): self._int_heat_night = float_positive(value, 'int_heat_night') @property def int_heat_frad(self): """Get or set value between 0 and 1 radiant fraction of internal gains.""" return self._int_heat_frad @int_heat_frad.setter def int_heat_frad(self, value): self._int_heat_frad = float_in_range(value, 0, 1, 'int_heat_frad') @property def int_heat_flat(self): """Get or set value between 0 and 1 for latent fraction of internal gains.""" return self._int_heat_flat @int_heat_flat.setter def int_heat_flat(self, value): self._int_heat_flat = float_in_range(value, 0, 1, 'int_heat_flat') @property def infil(self): """Get or set infiltration rate (ACH).""" return self._infil @infil.setter def infil(self, value): self._infil = float_positive(value, 'infil') @property def vent(self): """Get or set ventilation rate (ACH).""" return self._vent @vent.setter def vent(self, value): self._vent = float_positive(value, 'vent') @property def glazing_ratio(self): """Get or set value between 0 and 1 for glazing ratio.""" return self._glazing_ratio @glazing_ratio.setter def glazing_ratio(self, value): self._glazing_ratio = float_in_range(value, 0, 1, 'glazing_ratio') @property def u_value(self): """Get or set window U-value including film coefficent [W/(m2-K)].""" return self._u_value @u_value.setter def u_value(self, value): self._u_value = float_positive(value, 'u_value') @property def shgc(self): """Get or set building glazing Solar Heat Gain Coefficient.""" return self._shgc @shgc.setter def shgc(self, value): self._shgc = float_in_range(value, 0, 1, 'shgc') @property def condtype(self): """Get or set text string for cooling condensation system type. Choose from: * "AIR" * "WATER". """ return self._condtype @condtype.setter def condtype(self, value): value = value.upper() assert value in ('AIR', 'WATER'), 'condtype must be "AIR" or "WATER". ' \ 'Got: {}.'.format(value) self._condtype = value @property def cop(self): """Get or set the nominal Coefficient of Performance (COP) of cooling system.""" return self._cop @cop.setter def cop(self, value): self._cop = float_positive(value, 'cop') @property def coolcap(self): """Get or set rated cooling system capacity [W/m2].""" return self._coolcap @coolcap.setter def coolcap(self, value): self._coolcap = float_positive(value, 'coolcap') @property def heateff(self): """Get or set heating system capacity.""" return self._heateff @heateff.setter def heateff(self, value): self._heateff = float_positive(value, 'heateff') @property def initial_temp(self): """Get or set initial indoor air temperature [K].""" return self._initial_temp @initial_temp.setter def initial_temp(self, value): self._initial_temp = float_positive(value, 'initial_temp')
[docs] @classmethod def from_dict(cls, data): """Create a Building object from a dictionary. Args: data: A Building dictionary following the format below. .. code-block:: python { "type": "Building" "floor_height": self.floor_height, "int_heat_night": self.int_heat_night, "int_heat_day": self.int_heat_day, "int_heat_frad": self.int_heat_frad, "int_heat_flat": self.int_heat_flat, "infil": self.infil, "vent": self.vent, "glazing_ratio": self.glazing_ratio, "u_value": self.u_value, "shgc": self.shgc, "condtype": self.condtype, "cop": self.cop, "coolcap": self.coolcap, "heateff": self.heateff, "initial_temp": self.initial_temp } """ assert data['type'] == 'Building', 'Expected ' \ 'Building dictionary. Got {}.'.format(data['type']) return cls(data['floor_height'], data['int_heat_night'], data['int_heat_day'], data['int_heat_frad'], data['int_heat_flat'], data['infil'], data['vent'], data['glazing_ratio'], data['u_value'], data['shgc'], data['condtype'], data['cop'], data['coolcap'], data['heateff'], data['initial_temp'])
[docs] def to_dict(self): """Building dictionary representation.""" base = {'type': 'Building'} base['floor_height'] = self.floor_height base['int_heat_night'] = self.int_heat_night base['int_heat_day'] = self.int_heat_day base['int_heat_frad'] = self.int_heat_frad base['int_heat_flat'] = self.int_heat_flat base['infil'] = self.infil base['vent'] = self.vent base['glazing_ratio'] = self.glazing_ratio base['u_value'] = self.u_value base['shgc'] = self.shgc base['condtype'] = self.condtype base['cop'] = self.cop base['coolcap'] = self.coolcap base['heateff'] = self.heateff base['initial_temp'] = self.initial_temp return base
[docs] def BEMCalc(self, UCM, BEM, forc, parameter, simTime): """Update BEM by a single timestep.""" # total electricity consumption - (W/m^2) of floor self.ElecTotal = 0.0 self.nFloor = max(UCM.bldHeight / float(self.floor_height), 1) self.Qheat = 0.0 # total sensible heat added self.sensCoolDemand = 0.0 # building sensible cooling demand (W m-2) self.sensHeatDemand = 0.0 # building sensible heating demand (W m-2) self.coolConsump = 0.0 # cooling energy consumption (W m-2) self.heatConsump = 0.0 # heating energy consumption (W m-2) self.sensWaste = 0.0 # Sensible waste heat (W m-2) self.dehumDemand = 0.0 # dehumidification energy (W m-2) self.Qhvac = 0.0 # Total heat removed (sensible + latent) Qdehum = 0.0 # dens: Moist air density given dry bulb temp, humidity ratio, and pressure dens = moist_air_density( forc.pres, self.indoor_temp, self.indoor_hum) # kgv/m3 evapEff = 1. # evaporation efficiency in the condenser # total vent volumetric flow [m3 s-1] volVent = self.vent * self.nFloor volInfil = self.infil * UCM.bldHeight / \ 3600. # Change of units AC/H -> [m3 s-1] T_wall = BEM.wall.layerTemp[-1] # Inner layer volSWH = BEM.swh * self.nFloor / \ 3600. # Change of units l/hr per m^2 -> [L/s] T_ceil = BEM.roof.layerTemp[-1] # Inner layer T_mass = BEM.mass.layerTemp[0] # Outer layer T_indoor = self.indoor_temp # Indoor temp (initial) T_can = UCM.canTemp # Canyon temperature # Normalize areas to building foot print [m^2/m^2(bld)] facArea = UCM.verToHor / UCM.bldDensity # [m2(facade)/m2(bld)] wallArea = facArea * (1. - self.glazing_ratio) # [m2(wall)/m2(bld)] winArea = facArea * self.glazing_ratio # [m2(window)/m2(bld)] massArea = 2 * self.nFloor - 1 # ceiling/floor (top & bottom) # Set temperature set points according to night/day setpoints in building # schedule & simTime hr isEqualNightStart = \ is_near_zero((simTime.secDay / 3600.) - parameter.nightSetStart) if (simTime.secDay / 3600. < parameter.nightSetEnd) or \ (simTime.secDay / 3600. > parameter.nightSetStart or isEqualNightStart): T_cool = self.cool_setpoint_night T_heat = self.heat_setpoint_night self.int_heat = self.int_heat_night * self.nFloor else: T_cool = self.cool_setpoint_day T_heat = self.heat_setpoint_day self.int_heat = self.int_heat_day * self.nFloor # Indoor convection heat transfer coefficients zac_in_wall = 3.076 # wall heat convection coefficient zac_in_mass = 3.076 # mass heat convection coefficient # Check that T_ceil and T_indoor within reasonable bounds converge_hi = 100.0 + 273.15 converge_lo = -50.0 + 273.15 try: chk_tin = converge_lo <= T_indoor <= converge_hi chk_tce = converge_lo <= T_ceil <= converge_hi if chk_tin is not True or chk_tce is not True: raise Exception( "{}.\n Error at {}/{} {}s\nT_INDOOR: {}C\nT_CEILING: {}C\n{}.".format( self.TEMP_COEF_CONFLICT_MSG, simTime.month, simTime.day, simTime.secDay, T_indoor, T_ceil, BEM)) except ValueError: raise Exception("{}.\n Error at {}/{} {}s\n{}".format( self.TEMP_COEF_CONFLICT_MSG, simTime.month, simTime.day, simTime.secDay, BEM)) # If temperature is reasonable assign coefficients if T_ceil > T_indoor: # set higher ceiling heat convection coefficient # based on heat is higher on ceiling zac_in_ceil = 0.948 else: zac_in_ceil = 4.040 # ------------------------------------------------------------- # Heat fluxes (per m^2 of bld footprint) # ------------------------------------------------------------- # Solar Heat Gain: solar radiation received (W m-2) * area * SHGC winTrans = BEM.wall.solRec * self.shgc * winArea # Latent heat infiltration & ventilation (W/m^2 of bld footprint) from # volInfil/volVent: [m3 s-1 m-2 (bld/facade#)] # parameter.lv: latent heat of evaporation [J kgv-1] # dens: kga m-3 # UCM.canHum: canyon specific humidity (kgv kga-1) # indoorHum: indoor kv kga-1 # QL = W m-2 QLinfil = volInfil * dens * parameter.lv * \ (UCM.canHum - self.indoor_hum) QLvent = volVent * dens * parameter.lv * (UCM.canHum - self.indoor_hum) # QLintload (Qlatent Internal load): timestep int gain * int gain latent frac QLintload = self.int_heat * self.int_heat_flat # Heat/Cooling load (W/m^2 of bld footprint), if any self.sensCoolDemand = max( wallArea * zac_in_wall * (T_wall - T_cool) + # wall load massArea * zac_in_mass * (T_mass-T_cool) + # mass load # window load due to temp delta winArea * self.u_value * (T_can - T_cool) + zac_in_ceil * (T_ceil-T_cool) + # ceiling load self.int_heat + # internal load volInfil * dens * parameter.cp * (T_can - T_cool) + # m3 s-1 volVent * dens * parameter.cp * (T_can-T_cool) + # m3 s-1 winTrans, # solar load through window 0.) self.sensHeatDemand = max( -(wallArea * zac_in_wall * (T_wall-T_heat) + # wall load massArea * zac_in_mass * (T_mass-T_heat) + # mass load winArea * self.u_value * (T_can - T_heat) + # window load zac_in_ceil * (T_ceil-T_heat) + # ceiling load self.int_heat + # internal load volInfil * dens * parameter.cp * (T_can-T_heat) + # m3 s-1 volVent * dens * parameter.cp * (T_can-T_heat) + # m3 s-1 winTrans), # solar load through window 0.) # ------------------------------------------------------------- # HVAC system (cooling demand = W/m^2 bld footprint) # ------------------------------------------------------------- if self.sensCoolDemand > 0. and UCM.canTemp > 288.: # Cooling energy is the equivalent energy to bring a vol # where sensCoolDemand = dens * Cp * x * (T_indoor - 10C) & # given 7.8g/kg of air at 10C, assume 7g/kg of air # dehumDemand = x * dens * (self.indoorHum - # 0.9*0.0078)*parameter.lv VolCool = self.sensCoolDemand / \ (dens * parameter.cp * (T_indoor - 283.15)) self.dehumDemand = \ max(VolCool * dens * (self.indoor_hum - 0.9 * 0.0078) * parameter.lv, 0.) if (self.dehumDemand + self.sensCoolDemand) > (self.coolcap * self.nFloor): # if cooling demand greater then hvac cooling capacity self.Qhvac = self.coolcap * self.nFloor VolCool = ( VolCool / (self.dehumDemand + self.sensCoolDemand) * (self.coolcap * self.nFloor)) self.sensCoolDemand = ( self.sensCoolDemand * (self.coolcap * self.nFloor) / (self.dehumDemand + self.sensCoolDemand)) self.dehumDemand = ( self.dehumDemand * (self.coolcap * self.nFloor) / (self.dehumDemand + self.sensCoolDemand)) else: self.Qhvac = self.dehumDemand + self.sensCoolDemand Qdehum = VolCool * dens * parameter.lv * \ (self.indoor_hum - 0.9 * 0.0078) self.coolConsump = \ (max(self.sensCoolDemand + self.dehumDemand, 0.0)) / self.cop_adj # Waste heat from HVAC (per m^2 building foot print) if self.condtype == 'AIR': self.sensWaste = \ max(self.sensCoolDemand + self.dehumDemand, 0) + \ self.coolConsump self.latWaste = 0.0 elif self.condtype == 'WATER': # Not sure if this works well self.sensWaste = ( max(self.sensCoolDemand + self.dehumDemand, 0) + self.coolConsump * (1. - evapEff)) self.latWaste = ( max(self.sensCoolDemand + self.dehumDemand, 0) + self.coolConsump * evapEff) self.sensHeatDemand = 0. # ------------------------------------------------------------- # HVAC system (heating demand = W/m^2 bld footprint) # ------------------------------------------------------------- elif self.sensHeatDemand > 0. and UCM.canTemp < 288.: # limit on heating capacity self.Qheat = min(self.sensHeatDemand, self.heat_cap * self.nFloor) self.heatConsump = self.Qheat / self.heateff self.sensWaste = self.heatConsump - self.Qheat # waste per footprint self.heatConsump = self.heatConsump / self.nFloor # adjust to per flr area self.sensHeatDemand = self.Qheat / self.nFloor # adjust to per flr area Qdehum = 0.0 self.sensCoolDemand = 0.0 # ------------------------------------------------------------- # Evolution of the internal temperature and humidity # ------------------------------------------------------------- # wall, mass, roof, intload, infil, vent, hvac, heat, window Q = self.int_heat + winTrans + self.Qheat - self.sensCoolDemand H1 = (T_wall * wallArea * zac_in_wall + T_mass * massArea * zac_in_mass + T_ceil * zac_in_ceil + T_can * winArea * self.u_value + T_can * volInfil * dens * parameter.cp + T_can * volVent * dens * parameter.cp) H2 = (wallArea * zac_in_wall + massArea * zac_in_mass + zac_in_ceil + winArea * self.u_value + volInfil * dens * parameter.cp + volVent * dens * parameter.cp) # Assumes air temp of control volume is sum of surface boundary temps # weighted by area and heat transfer coefficient + generated heat self.indoor_temp = (H1 + Q) / H2 self.indoor_hum = ( self.indoor_hum + (simTime.dt / (dens * parameter.lv * UCM.bldHeight)) * (QLintload + QLinfil + QLvent - Qdehum)) # Calculate relative hum (Pw/Pws*100) using pressurce, indoor temp, hum _Tdb, _w, _phi, _h, _Tdp, _v = \ psychrometrics(self.indoor_temp, self.indoor_hum, forc.pres) self.indoorRhum = _phi # These are used for element calculation (per m^2 of element area) self.fluxWall = zac_in_wall * (T_indoor - T_wall) self.fluxRoof = zac_in_ceil * (T_indoor - T_ceil) self.fluxMass = ( zac_in_mass * (T_indoor - T_mass) + self.int_heat * self.int_heat_f_rad / massArea) # These are for record keeping only, per m^2 of floor area (W m-2) self.fluxSolar = winTrans / self.nFloor self.fluxWindow = winArea * self.u_value * \ (T_can - T_indoor) / self.nFloor self.fluxInterior = \ self.int_heat * self.int_heat_f_rad * \ (1. - self.int_heat_flat) / self.nFloor # volInfil: m3/s self.fluxInfil = \ volInfil * dens * parameter.cp * (T_can - T_indoor) / self.nFloor # volVent: m3/s self.fluxVent = volVent * dens * parameter.cp * \ (T_can - T_indoor) / self.nFloor self.coolConsump = self.coolConsump / self.nFloor self.sensCoolDemand = self.sensCoolDemand / self.nFloor # Total Electricity/building floor area (W/m^2) self.ElecTotal = self.coolConsump + BEM.elec + BEM.light # Waste heat to canyon, W/m^2 of building + water CpH20 = 4200. # specific heat capacity of water J/(kg-C) T_hot = 49 + 273.15 # Service water temp (assume no storage) # N.B No L to kg conversion for water in this equation because # 1 L of water = 1 kg of water. self.sensWaste = ( self.sensWaste + (1 / self.heateff - 1.) * (volSWH * CpH20 * (T_hot - forc.waterTemp)) + BEM.gas * (1 - self.heateff) * self.nFloor) # Gas equip per floor + water usage per floor + heating/floor self.GasTotal = ( BEM.gas + volSWH * CpH20 * (T_hot - forc.waterTemp) / self.nFloor / self.heateff + self.heatConsump)
def __repr__(self): return 'Building,\n floor_height: {}\n int_heat_night {}\n int_heat_day {}\n ' \ 'int_heat_frad {}\n int_heat_flat {}\n infil: {}\n vent: {}\n ' \ 'glazing_ratio: {}\n u_value: {}\n shgc: {}\n condtype: {}\n cop: {}\n ' \ 'cool_setpoint_day: {}\n cool_setpoint_night: {}\n heat_setpoint_day: {}\n' \ 'heat_setpoint_night: {}\n coolcap: {}\n heateff: {}\n ' \ 'initial_temp: {}'.format( self.floor_height, self.int_heat_night, self.int_heat_day, self.int_heat_frad, self.int_heat_flat, self.infil, self.vent, self.glazing_ratio, self.u_value, self.shgc, self.condtype, self.cop, self.cool_setpoint_day, self.cool_setpoint_night, self.heat_setpoint_day, self.heat_setpoint_night, self.coolcap, self.heateff, self.initial_temp)