introduced dhw to the meb exporter

This commit is contained in:
Pilar Monsalvete 2023-03-20 14:15:57 -04:00
parent bb10d888c3
commit 88e2cb6796
9 changed files with 86 additions and 311 deletions

View File

@ -38,6 +38,7 @@ class Building(CityObject):
self._shell = None self._shell = None
self._alias = None self._alias = None
self._type = 'building' self._type = 'building'
self._cold_water_temperature = dict()
self._heating = dict() self._heating = dict()
self._cooling = dict() self._cooling = dict()
self._lighting_electrical_demand = dict() self._lighting_electrical_demand = dict()
@ -265,6 +266,22 @@ class Building(CityObject):
if value is not None: if value is not None:
self._storeys_above_ground = int(value) self._storeys_above_ground = int(value)
@property
def cold_water_temperature(self) -> {float}:
"""
Get cold water temperature in degrees Celsius
:return: dict{DataFrame(float)}
"""
return self._cold_water_temperature
@cold_water_temperature.setter
def cold_water_temperature(self, value):
"""
Set cold water temperature in degrees Celsius
:param value: dict{DataFrame(float)}
"""
self._cold_water_temperature = value
@property @property
def heating(self) -> dict: def heating(self) -> dict:
""" """

View File

@ -600,11 +600,14 @@ class ThermalZone:
""" """
self._domestic_hot_water = DomesticHotWater() self._domestic_hot_water = DomesticHotWater()
_mean_peak_density_load = 0 _mean_peak_density_load = 0
_mean_peak_flow = 0
_mean_service_temperature = 0 _mean_service_temperature = 0
for usage in self.usages: for usage in self.usages:
_mean_peak_density_load += usage.percentage * usage.domestic_hot_water.density _mean_peak_density_load += usage.percentage * usage.domestic_hot_water.density
_mean_peak_flow += usage.percentage * usage.domestic_hot_water.peak_flow
_mean_service_temperature += usage.percentage * usage.domestic_hot_water.service_temperature _mean_service_temperature += usage.percentage * usage.domestic_hot_water.service_temperature
self._domestic_hot_water.density = _mean_peak_density_load self._domestic_hot_water.density = _mean_peak_density_load
self._domestic_hot_water.peak_flow = _mean_peak_flow
self._domestic_hot_water.service_temperature = _mean_service_temperature self._domestic_hot_water.service_temperature = _mean_service_temperature
_domestic_hot_water_reference = self.usages[0].domestic_hot_water _domestic_hot_water_reference = self.usages[0].domestic_hot_water

View File

@ -1,250 +0,0 @@
"""
UsageZone module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import uuid
from typing import Union, List
import hub.helpers.constants as cte
from hub.city_model_structure.building_demand.occupancy import Occupancy
from hub.city_model_structure.building_demand.lighting import Lighting
from hub.city_model_structure.building_demand.appliances import Appliances
from hub.city_model_structure.building_demand.thermal_control import ThermalControl
from hub.city_model_structure.building_demand.internal_gain import InternalGain
class UsageZone:
"""
UsageZone class
"""
def __init__(self):
self._id = None
self._usage = None
self._percentage = None
self._internal_gains = None
self._hours_day = None
self._days_year = None
self._mechanical_air_change = None
self._occupancy = None
self._lighting = None
self._appliances = None
self._thermal_control = None
@property
def id(self):
"""
Get usage zone id, a universally unique identifier randomly generated
:return: str
"""
if self._id is None:
self._id = uuid.uuid4()
return self._id
@property
def usage(self) -> Union[None, str]:
"""
Get usage zone usage
:return: None or str
"""
return self._usage
@usage.setter
def usage(self, value):
"""
Set usage zone usage
:param value: str
"""
if value is not None:
self._usage = str(value)
@property
def percentage(self):
"""
Get usage zone percentage in range[0,1]
:return: float
"""
return self._percentage
@percentage.setter
def percentage(self, value):
"""
Set usage zone percentage in range[0,1]
:param value: float
"""
if value is not None:
self._percentage = float(value)
@property
def internal_gains(self) -> List[InternalGain]:
"""
Calculates and returns the list of all internal gains defined
:return: InternalGains
"""
if self._internal_gains is None:
if self.occupancy is not None:
if self.occupancy.latent_internal_gain is not None:
_internal_gain = InternalGain()
_internal_gain.type = cte.OCCUPANCY
_total_heat_gain = (self.occupancy.sensible_convective_internal_gain
+ self.occupancy.sensible_radiative_internal_gain
+ self.occupancy.latent_internal_gain)
_internal_gain.average_internal_gain = _total_heat_gain
_internal_gain.latent_fraction = 0
_internal_gain.radiative_fraction = 0
_internal_gain.convective_fraction = 0
if _total_heat_gain != 0:
_internal_gain.latent_fraction = self.occupancy.latent_internal_gain / _total_heat_gain
_internal_gain.radiative_fraction = self.occupancy.sensible_radiative_internal_gain / _total_heat_gain
_internal_gain.convective_fraction = self.occupancy.sensible_convective_internal_gain / _total_heat_gain
_internal_gain.schedules = self.occupancy.occupancy_schedules
self._internal_gains = [_internal_gain]
if self.lighting is not None:
_internal_gain = InternalGain()
_internal_gain.type = cte.LIGHTING
_internal_gain.average_internal_gain = self.lighting.density
_internal_gain.latent_fraction = self.lighting.latent_fraction
_internal_gain.radiative_fraction = self.lighting.radiative_fraction
_internal_gain.convective_fraction = self.lighting.convective_fraction
_internal_gain.schedules = self.lighting.schedules
if self._internal_gains is not None:
self._internal_gains.append(_internal_gain)
else:
self._internal_gains = [_internal_gain]
if self.appliances is not None:
_internal_gain = InternalGain()
_internal_gain.type = cte.APPLIANCES
_internal_gain.average_internal_gain = self.appliances.density
_internal_gain.latent_fraction = self.appliances.latent_fraction
_internal_gain.radiative_fraction = self.appliances.radiative_fraction
_internal_gain.convective_fraction = self.appliances.convective_fraction
_internal_gain.schedules = self.appliances.schedules
if self._internal_gains is not None:
self._internal_gains.append(_internal_gain)
else:
self._internal_gains = [_internal_gain]
return self._internal_gains
@internal_gains.setter
def internal_gains(self, value):
"""
Set usage zone internal gains
:param value: [InternalGain]
"""
self._internal_gains = value
@property
def hours_day(self) -> Union[None, float]:
"""
Get usage zone usage hours per day
:return: None or float
"""
return self._hours_day
@hours_day.setter
def hours_day(self, value):
"""
Set usage zone usage hours per day
:param value: float
"""
if value is not None:
self._hours_day = float(value)
@property
def days_year(self) -> Union[None, float]:
"""
Get usage zone usage days per year
:return: None or float
"""
return self._days_year
@days_year.setter
def days_year(self, value):
"""
Set usage zone usage days per year
:param value: float
"""
if value is not None:
self._days_year = float(value)
@property
def mechanical_air_change(self) -> Union[None, float]:
"""
Get usage zone mechanical air change in air change per hour (ACH)
:return: None or float
"""
return self._mechanical_air_change
@mechanical_air_change.setter
def mechanical_air_change(self, value):
"""
Set usage zone mechanical air change in air change per hour (ACH)
:param value: float
"""
if value is not None:
self._mechanical_air_change = float(value)
@property
def occupancy(self) -> Union[None, Occupancy]:
"""
Get occupancy in the usage zone
:return: None or Occupancy
"""
return self._occupancy
@occupancy.setter
def occupancy(self, value):
"""
Set occupancy in the usage zone
:param value: Occupancy
"""
self._occupancy = value
@property
def lighting(self) -> Union[None, Lighting]:
"""
Get lighting information
:return: None or Lighting
"""
return self._lighting
@lighting.setter
def lighting(self, value):
"""
Set lighting information
:param value: Lighting
"""
self._lighting = value
@property
def appliances(self) -> Union[None, Appliances]:
"""
Get appliances information
:return: None or Appliances
"""
return self._appliances
@appliances.setter
def appliances(self, value):
"""
Set appliances information
:param value: Appliances
"""
self._appliances = value
@property
def thermal_control(self) -> Union[None, ThermalControl]:
"""
Get thermal control of this thermal zone
:return: None or ThermalControl
"""
return self._thermal_control
@thermal_control.setter
def thermal_control(self, value):
"""
Set thermal control for this thermal zone
:param value: ThermalControl
"""
self._thermal_control = value

View File

@ -10,6 +10,7 @@ import pandas as pd
import csv import csv
import hub.helpers.constants as cte import hub.helpers.constants as cte
class InselMonthlyEnergyBalance: class InselMonthlyEnergyBalance:
""" """
Import SRA results Import SRA results

View File

@ -8,6 +8,7 @@ import copy
import sys import sys
import numpy import numpy
from hub.hub_logger import logger
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.city_model_structure.building_demand.usage import Usage from hub.city_model_structure.building_demand.usage import Usage
@ -19,7 +20,6 @@ from hub.city_model_structure.building_demand.domestic_hot_water import Domestic
from hub.city_model_structure.attributes.schedule import Schedule from hub.city_model_structure.attributes.schedule import Schedule
from hub.city_model_structure.building_demand.internal_gain import InternalGain from hub.city_model_structure.building_demand.internal_gain import InternalGain
from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory
from hub.imports.usage.usage_helper import UsageHelper
class ComnetUsageParameters: class ComnetUsageParameters:
@ -42,8 +42,8 @@ class ComnetUsageParameters:
try: try:
archetype_usage = self._search_archetypes(comnet_catalog, usage_name) archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
except KeyError: except KeyError:
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' logger.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}')
f' {building.function}') sys.stderr.write(f'Building {building.name} has unknown usage archetype for usage: {usage_name}')
continue continue
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
@ -56,7 +56,7 @@ class ComnetUsageParameters:
volume_per_area = internal_zone.volume / internal_zone.area volume_per_area = internal_zone.volume / internal_zone.area
usage = Usage() usage = Usage()
usage.name = usage_name usage.name = usage_name
self._assign_values(usage, archetype_usage, volume_per_area, building.ground_temperature) self._assign_values(usage, archetype_usage, volume_per_area, building.cold_water_temperature)
usage.percentage = 1 usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, archetype_usage) self._calculate_reduced_values_from_extended_library(usage, archetype_usage)
@ -71,7 +71,7 @@ class ComnetUsageParameters:
raise KeyError('archetype not found') raise KeyError('archetype not found')
@staticmethod @staticmethod
def _assign_values(usage, archetype, volume_per_area, ground_temperature): def _assign_values(usage, archetype, volume_per_area, cold_water_temperature):
# Due to the fact that python is not a typed language, the wrong object type is assigned to # Due to the fact that python is not a typed language, the wrong object type is assigned to
# usage.occupancy when writing usage.occupancy = archetype.occupancy. # usage.occupancy when writing usage.occupancy = archetype.occupancy.
# Same happens for lighting and appliances. Therefore, this walk around has been done. # Same happens for lighting and appliances. Therefore, this walk around has been done.
@ -106,7 +106,7 @@ class ComnetUsageParameters:
_domestic_hot_water = DomesticHotWater() _domestic_hot_water = DomesticHotWater()
_domestic_hot_water.density = archetype.domestic_hot_water.density _domestic_hot_water.density = archetype.domestic_hot_water.density
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature _domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
cold_temperature = UsageHelper().cold_water_temperature(ground_temperature) cold_temperature = cold_water_temperature[cte.YEAR]['epw']
peak_flow = 0 peak_flow = 0
if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0: if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0:
peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \ peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \

View File

@ -7,6 +7,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import sys import sys
from hub.hub_logger import logger
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.city_model_structure.building_demand.usage import Usage from hub.city_model_structure.building_demand.usage import Usage
@ -16,7 +17,6 @@ from hub.city_model_structure.building_demand.appliances import Appliances
from hub.city_model_structure.building_demand.thermal_control import ThermalControl from hub.city_model_structure.building_demand.thermal_control import ThermalControl
from hub.city_model_structure.building_demand.domestic_hot_water import DomesticHotWater from hub.city_model_structure.building_demand.domestic_hot_water import DomesticHotWater
from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory
from hub.imports.usage.usage_helper import UsageHelper
class NrcanUsageParameters: class NrcanUsageParameters:
@ -41,16 +41,16 @@ class NrcanUsageParameters:
try: try:
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name) archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
except KeyError: except KeyError:
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' logger.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
f' {building.function}') sys.stderr.write(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
continue continue
usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function] usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
try: try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, usage_name) comnet_archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
except KeyError: except KeyError:
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' logger.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
f' {building.function}') sys.stderr.write(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
continue continue
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
@ -63,7 +63,7 @@ class NrcanUsageParameters:
volume_per_area = internal_zone.volume / internal_zone.area volume_per_area = internal_zone.volume / internal_zone.area
usage = Usage() usage = Usage()
usage.name = usage_name usage.name = usage_name
self._assign_values(usage, archetype_usage, volume_per_area, building.ground_temperature) self._assign_values(usage, archetype_usage, volume_per_area, building.cold_water_temperature)
self._assign_comnet_extra_values(usage, comnet_archetype_usage) self._assign_comnet_extra_values(usage, comnet_archetype_usage)
usage.percentage = 1 usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, archetype_usage) self._calculate_reduced_values_from_extended_library(usage, archetype_usage)
@ -79,7 +79,7 @@ class NrcanUsageParameters:
raise KeyError('archetype not found') raise KeyError('archetype not found')
@staticmethod @staticmethod
def _assign_values(usage, archetype, volume_per_area, ground_temperature): def _assign_values(usage, archetype, volume_per_area, cold_water_temperature):
if archetype.mechanical_air_change > 0: if archetype.mechanical_air_change > 0:
usage.mechanical_air_change = archetype.mechanical_air_change usage.mechanical_air_change = archetype.mechanical_air_change
elif archetype.ventilation_rate > 0: elif archetype.ventilation_rate > 0:
@ -116,7 +116,7 @@ class NrcanUsageParameters:
_domestic_hot_water = DomesticHotWater() _domestic_hot_water = DomesticHotWater()
_domestic_hot_water.peak_flow = archetype.domestic_hot_water.peak_flow _domestic_hot_water.peak_flow = archetype.domestic_hot_water.peak_flow
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature _domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
cold_temperature = UsageHelper().cold_water_temperature(ground_temperature) cold_temperature = cold_water_temperature[cte.YEAR]['epw']
_domestic_hot_water.density = archetype.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY \ _domestic_hot_water.density = archetype.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY \
* (archetype.domestic_hot_water.service_temperature - cold_temperature) * (archetype.domestic_hot_water.service_temperature - cold_temperature)
_domestic_hot_water.schedules = archetype.domestic_hot_water.schedules _domestic_hot_water.schedules = archetype.domestic_hot_water.schedules

View File

@ -1,43 +0,0 @@
"""
Usage helper
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import sys
from hub.hub_logger import logger
import hub.helpers.constants as cte
from hub.helpers.configuration_helper import ConfigurationHelper as ch
class UsageHelper:
"""
UsageHelper class
"""
@staticmethod
def cold_water_temperature(ground_temperature):
keys = ground_temperature.keys()
depths = ground_temperature[keys[0]].keys()
if keys[0] == cte.YEAR:
# taking the deeper temperature available
_cold_temperature = ground_temperature[cte.YEAR][depths[len(depths-1)]]
elif keys[0] == cte.MONTH:
_cold_temperature = 0
for i in range(0, 12):
# taking the deeper temperature available
_cold_temperature += ground_temperature[cte.MONTH][depths[len(depths-1)]] / 12
elif keys[0] == cte.HOUR:
_cold_temperature = 0
for i in range(0, 8760):
# taking the deeper temperature available
_cold_temperature += ground_temperature[cte.HOUR][depths[len(depths-1)]] / 8760
else:
_cold_temperature = ch().cold_water_temperature
logger.error(f'Cold water temperature could not be calculated. Assigned default value = '
f'{ch().cold_water_temperature} degrees Celsius\n')
sys.stderr.write(f'Cold water temperature could not be calculated. Assigned default value = '
f'{ch().cold_water_temperature} degrees Celsius\n')
return _cold_temperature

View File

@ -111,10 +111,24 @@ class EpwWeatherParameters:
building.beam[cte.HOUR] = new_value building.beam[cte.HOUR] = new_value
else: else:
pd.concat([building.beam[cte.HOUR], new_value], axis=1) pd.concat([building.beam[cte.HOUR], new_value], axis=1)
new_value = wh().cold_water_temperature(building.external_temperature[cte.HOUR]['epw'])
if cte.HOUR not in building.cold_water_temperature:
building.cold_water_temperature[cte.HOUR] = new_value
else:
pd.concat([building.cold_water_temperature[cte.HOUR], new_value], axis=1)
# create the monthly and yearly values out of the hourly # create the monthly and yearly values out of the hourly
for building in self._city.buildings: for building in self._city.buildings:
if cte.MONTH not in building.external_temperature: if cte.MONTH not in building.external_temperature:
building.external_temperature[cte.MONTH] = wh().get_monthly_mean_values(building.external_temperature[cte.HOUR][['epw']]) building.external_temperature[cte.MONTH] = \
wh().get_monthly_mean_values(building.external_temperature[cte.HOUR][['epw']])
if cte.YEAR not in building.external_temperature: if cte.YEAR not in building.external_temperature:
building.external_temperature[cte.YEAR] = wh(). get_yearly_mean_values(building.external_temperature[cte.HOUR][['epw']]) building.external_temperature[cte.YEAR] = \
wh(). get_yearly_mean_values(building.external_temperature[cte.HOUR][['epw']])
if cte.MONTH not in building.cold_water_temperature:
building.cold_water_temperature[cte.MONTH] = wh().get_monthly_mean_values(
building.cold_water_temperature[cte.HOUR][['epw']])
if cte.YEAR not in building.cold_water_temperature:
building.cold_water_temperature[cte.YEAR] = wh().get_yearly_mean_values(
building.cold_water_temperature[cte.HOUR][['epw']])
self._city.level_of_detail.weather = 2 self._city.level_of_detail.weather = 2

View File

@ -4,6 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import math import math
import hub.helpers.constants as cte import hub.helpers.constants as cte
import pandas as pd import pandas as pd
@ -20,7 +21,7 @@ class Weather:
def sky_temperature(ambient_temperature): def sky_temperature(ambient_temperature):
""" """
Get sky temperature from ambient temperature in Celsius Get sky temperature from ambient temperature in Celsius
:return: float :return: List[float]
""" """
# Swinbank - Source sky model approximation(1963) based on cloudiness statistics(32 %) in United States # Swinbank - Source sky model approximation(1963) based on cloudiness statistics(32 %) in United States
# ambient temperatures( in °C) # ambient temperatures( in °C)
@ -32,6 +33,37 @@ class Weather:
values.append(value) values.append(value)
return values return values
@staticmethod
def cold_water_temperature(ambient_temperature):
"""
Get cold water temperature from ambient temperature in Celsius
:return: dict
"""
# Equation from "TOWARDS DEVELOPMENT OF AN ALGORITHM FOR MAINS WATER TEMPERATURE", 2004, Jay Burch
# and Craig Christensen, National Renewable Energy Laboratory
# ambient temperatures( in °C)
# cold water temperatures( in °C)
ambient_temperature_fahrenheit = []
average_temperature = 0
maximum_temperature = -1000
minimum_temperature = 1000
for temperature in ambient_temperature:
value = temperature * 9 / 5 + 32
ambient_temperature_fahrenheit.append(value)
average_temperature += value / 8760
if value > maximum_temperature:
maximum_temperature = value
if value < minimum_temperature:
minimum_temperature = value
delta_temperature = maximum_temperature - minimum_temperature
ratio = 0.4 + 0.01 * (average_temperature - 44)
lag = 35 - 1 * (average_temperature - 44)
cold_temperature = []
for temperature in ambient_temperature_fahrenheit:
radians = (0.986 * (temperature-15-lag) - 90) * math.pi / 180
cold_temperature.append((average_temperature + 6 + ratio * (delta_temperature/2) * math.sin(radians) - 32) * 5/9)
return pd.DataFrame(cold_temperature, columns=['epw'])
def get_monthly_mean_values(self, values): def get_monthly_mean_values(self, values):
out = None out = None
if values is not None: if values is not None:
@ -41,7 +73,8 @@ class Weather:
del out['month'] del out['month']
return out return out
def get_yearly_mean_values(self, values): @staticmethod
def get_yearly_mean_values(values):
return values.mean() return values.mean()
def get_total_month(self, values): def get_total_month(self, values):