Merge remote-tracking branch 'origin/master' into usage_catalog
This commit is contained in:
commit
fbf6005748
|
@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class Content:
|
||||
def __init__(self, vegetations, plants, soils):
|
||||
self._vegetations = vegetations
|
||||
|
|
|
@ -5,7 +5,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
|
||||
from catalog_factories.data_models.greenery.soil import Soil as libs_soil
|
||||
from catalog_factories.data_models.greenery.soil import Soil as hub_soil
|
||||
|
||||
|
||||
class Plant:
|
||||
|
@ -20,12 +20,13 @@ class Plant:
|
|||
self._co2_sequestration = plant.co2Sequestration
|
||||
self._grows_on = []
|
||||
for soil in plant.growsOn:
|
||||
self._grows_on.append(libs_soil(soil))
|
||||
self._grows_on.append(hub_soil(soil))
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Get plant name
|
||||
:return: string
|
||||
"""
|
||||
return self._name
|
||||
|
||||
|
@ -33,13 +34,15 @@ class Plant:
|
|||
def category(self):
|
||||
"""
|
||||
Get plant category name
|
||||
:return: string
|
||||
"""
|
||||
return self._category
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
"""
|
||||
Get plant height
|
||||
Get plant height in m
|
||||
:return: float
|
||||
"""
|
||||
return self._height
|
||||
|
||||
|
@ -47,6 +50,7 @@ class Plant:
|
|||
def leaf_area_index(self):
|
||||
"""
|
||||
Get plant leaf area index
|
||||
:return: float
|
||||
"""
|
||||
return self._leaf_area_index
|
||||
|
||||
|
@ -54,6 +58,7 @@ class Plant:
|
|||
def leaf_reflectivity(self):
|
||||
"""
|
||||
Get plant leaf area index
|
||||
:return: float
|
||||
"""
|
||||
return self._leaf_reflectivity
|
||||
|
||||
|
@ -61,26 +66,30 @@ class Plant:
|
|||
def leaf_emissivity(self):
|
||||
"""
|
||||
Get plant leaf emissivity
|
||||
:return: float
|
||||
"""
|
||||
return self._leaf_emissivity
|
||||
|
||||
@property
|
||||
def minimal_stomatal_resistance(self):
|
||||
"""
|
||||
Get plant minimal stomatal resistance
|
||||
Get plant minimal stomatal resistance in s/m
|
||||
:return: float
|
||||
"""
|
||||
return self._minimal_stomatal_resistance
|
||||
|
||||
@property
|
||||
def co2_sequestration(self):
|
||||
"""
|
||||
Get plant co2 sequestration capacity
|
||||
Get plant co2 sequestration capacity in kg CO2 equivalent
|
||||
:return: float
|
||||
"""
|
||||
return self._co2_sequestration
|
||||
|
||||
@property
|
||||
def grows_on(self) -> [libs_soil]:
|
||||
def grows_on(self) -> [hub_soil]:
|
||||
"""
|
||||
Get plant compatible soils
|
||||
:return: [Soil]
|
||||
"""
|
||||
return self._grows_on
|
||||
|
|
|
@ -7,6 +7,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|||
|
||||
from catalog_factories.data_models.greenery.plant import Plant as libs_plant
|
||||
|
||||
|
||||
class PlantPercentage(libs_plant):
|
||||
|
||||
def __init__(self, percentage, plant_category, plant):
|
||||
|
@ -15,4 +16,8 @@ class PlantPercentage(libs_plant):
|
|||
|
||||
@property
|
||||
def percentage(self):
|
||||
"""
|
||||
Get plant percentage
|
||||
:return: float
|
||||
"""
|
||||
return self._percentage
|
||||
|
|
|
@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class Soil:
|
||||
def __init__(self, soil):
|
||||
self._name = soil.name
|
||||
|
@ -23,6 +24,7 @@ class Soil:
|
|||
def name(self):
|
||||
"""
|
||||
Get soil name
|
||||
:return: string
|
||||
"""
|
||||
return self._name
|
||||
|
||||
|
@ -30,27 +32,31 @@ class Soil:
|
|||
def roughness(self):
|
||||
"""
|
||||
Get soil roughness
|
||||
:return: string
|
||||
"""
|
||||
return self._roughness
|
||||
|
||||
@property
|
||||
def dry_conductivity(self):
|
||||
"""
|
||||
Get soil dry conductivity
|
||||
Get soil dry conductivity in W/mK
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_conductivity
|
||||
|
||||
@property
|
||||
def dry_density(self):
|
||||
"""
|
||||
Get soil dry density
|
||||
Get soil dry density in kg/m3
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_density
|
||||
|
||||
@property
|
||||
def dry_specific_heat(self):
|
||||
"""
|
||||
Get soil dry specific heat
|
||||
Get soil dry specific heat in J/kgK
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_specific_heat
|
||||
|
||||
|
@ -58,6 +64,7 @@ class Soil:
|
|||
def thermal_absorptance(self):
|
||||
"""
|
||||
Get soil thermal absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._thermal_absorptance
|
||||
|
||||
|
@ -65,6 +72,7 @@ class Soil:
|
|||
def solar_absorptance(self):
|
||||
"""
|
||||
Get soil solar absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._solar_absorptance
|
||||
|
||||
|
@ -72,6 +80,7 @@ class Soil:
|
|||
def visible_absorptance(self):
|
||||
"""
|
||||
Get soil visible absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._visible_absorptance
|
||||
|
||||
|
@ -79,6 +88,7 @@ class Soil:
|
|||
def saturation_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil saturation volumetric moisture content
|
||||
:return: float
|
||||
"""
|
||||
return self._saturation_volumetric_moisture_content
|
||||
|
||||
|
@ -86,6 +96,7 @@ class Soil:
|
|||
def residual_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil residual volumetric moisture content
|
||||
:return: float
|
||||
"""
|
||||
return self._residual_volumetric_moisture_content
|
||||
|
||||
|
@ -93,5 +104,6 @@ class Soil:
|
|||
def initial_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil initial volumetric moisture content
|
||||
:return: float
|
||||
"""
|
||||
return self._initial_volumetric_moisture_content
|
||||
|
|
|
@ -7,6 +7,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|||
|
||||
from catalog_factories.data_models.greenery.plant_percentage import PlantPercentage
|
||||
|
||||
|
||||
class Vegetation:
|
||||
def __init__(self, category, vegetation, plant_percentages):
|
||||
self._name = vegetation.name
|
||||
|
@ -31,6 +32,7 @@ class Vegetation:
|
|||
def name(self):
|
||||
"""
|
||||
Get vegetation name
|
||||
:return: string
|
||||
"""
|
||||
return self._name
|
||||
|
||||
|
@ -38,13 +40,15 @@ class Vegetation:
|
|||
def category(self):
|
||||
"""
|
||||
Get vegetation category
|
||||
:return: string
|
||||
"""
|
||||
return self._category
|
||||
|
||||
@property
|
||||
def soil_thickness(self):
|
||||
"""
|
||||
Get soil thickness
|
||||
Get soil thickness in m
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_thickness
|
||||
|
||||
|
@ -52,13 +56,15 @@ class Vegetation:
|
|||
def management(self):
|
||||
"""
|
||||
Get management
|
||||
:return: string
|
||||
"""
|
||||
return self._management
|
||||
|
||||
@property
|
||||
def air_gap(self):
|
||||
"""
|
||||
Get air gap
|
||||
Get air gap in m
|
||||
:return: float
|
||||
"""
|
||||
return self._air_gap
|
||||
|
||||
|
@ -66,6 +72,7 @@ class Vegetation:
|
|||
def plant_percentages(self) -> [PlantPercentage]:
|
||||
"""
|
||||
Get plant percentages
|
||||
:return: [PlantPercentage]
|
||||
"""
|
||||
percentage = 0.0
|
||||
for plant_percentage in self._plant_percentages:
|
||||
|
@ -78,6 +85,7 @@ class Vegetation:
|
|||
def soil_name(self):
|
||||
"""
|
||||
Get soil name
|
||||
:return: string
|
||||
"""
|
||||
return self._soil_name
|
||||
|
||||
|
@ -85,27 +93,31 @@ class Vegetation:
|
|||
def soil_roughness(self):
|
||||
"""
|
||||
Get soil roughness
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_roughness
|
||||
|
||||
@property
|
||||
def dry_soil_conductivity(self):
|
||||
"""
|
||||
Get soil dry conductivity
|
||||
Get soil dry conductivity in W/mK
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_soil_conductivity
|
||||
|
||||
@property
|
||||
def dry_soil_density(self):
|
||||
"""
|
||||
Get soil dry density
|
||||
Get soil dry density in kg/m3
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_soil_density
|
||||
|
||||
@property
|
||||
def dry_soil_specific_heat(self):
|
||||
"""
|
||||
Get soil dry specific heat
|
||||
Get soil dry specific heat in J/kgK
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_soil_specific_heat
|
||||
|
||||
|
@ -113,6 +125,7 @@ class Vegetation:
|
|||
def soil_thermal_absorptance(self):
|
||||
"""
|
||||
Get soil thermal absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_thermal_absorptance
|
||||
|
||||
|
@ -120,6 +133,7 @@ class Vegetation:
|
|||
def soil_solar_absorptance(self):
|
||||
"""
|
||||
Get soil solar absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_solar_absorptance
|
||||
|
||||
|
@ -127,6 +141,7 @@ class Vegetation:
|
|||
def soil_visible_absorptance(self):
|
||||
"""
|
||||
Get soil visible absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_visible_absorptance
|
||||
|
||||
|
@ -134,6 +149,7 @@ class Vegetation:
|
|||
def soil_saturation_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil saturation volumetric moisture content
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_saturation_volumetric_moisture_content
|
||||
|
||||
|
@ -141,6 +157,7 @@ class Vegetation:
|
|||
def soil_residual_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil residual volumetric moisture content
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_residual_volumetric_moisture_content
|
||||
|
||||
|
@ -148,5 +165,6 @@ class Vegetation:
|
|||
def soil_initial_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil initial volumetric moisture content
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_initial_volumetric_moisture_content
|
||||
|
|
|
@ -32,7 +32,7 @@ class Edge:
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get edge id, an universally unique identifier randomly generated
|
||||
Get edge id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
|
@ -34,7 +34,7 @@ class Node:
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get node id, an universally unique identifier randomly generated
|
||||
Get node id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
|
@ -26,7 +26,7 @@ class Schedule:
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get schedule id, an universally unique identifier randomly generated
|
||||
Get schedule id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
|
@ -30,7 +30,7 @@ class InternalZone:
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get internal zone id, an universally unique identifier randomly generated
|
||||
Get internal zone id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
|
@ -21,7 +21,7 @@ class Layer:
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get layer id, an universally unique identifier randomly generated
|
||||
Get layer id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
|
@ -40,8 +40,7 @@ class Surface:
|
|||
self._solid_polygon = solid_polygon
|
||||
self._pv_system_installed = None
|
||||
self._inverse = None
|
||||
# todo: do I need it???
|
||||
self._associated_thermal_boundaries = None
|
||||
# todo: create self._associated_thermal_boundaries and bring the vegetation here instead of in thermal_boundary
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
|
|
@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from typing import List, Union
|
||||
from helpers.configuration_helper import ConfigurationHelper as ch
|
||||
|
@ -12,6 +13,7 @@ from city_model_structure.building_demand.layer import Layer
|
|||
from city_model_structure.building_demand.thermal_opening import ThermalOpening
|
||||
from city_model_structure.building_demand.thermal_zone import ThermalZone
|
||||
from city_model_structure.building_demand.surface import Surface
|
||||
from city_model_structure.greenery.vegetation import Vegetation
|
||||
|
||||
|
||||
class ThermalBoundary:
|
||||
|
@ -41,12 +43,13 @@ class ThermalBoundary:
|
|||
self._alpha_coefficient = None
|
||||
self._radiative_coefficient = None
|
||||
self._window_ratio = None
|
||||
self._calculated = False
|
||||
self._window_ration_is_calculated = False
|
||||
self._vegetation = None
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get thermal zone id, an universally unique identifier randomly generated
|
||||
Get thermal zone id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
@ -249,7 +252,7 @@ class ThermalBoundary:
|
|||
:return: float
|
||||
"""
|
||||
if self.windows_areas is not None:
|
||||
if not self._calculated:
|
||||
if not self._window_ration_is_calculated:
|
||||
_calculated = True
|
||||
if len(self.windows_areas) == 0:
|
||||
self._window_ratio = 0
|
||||
|
@ -266,7 +269,7 @@ class ThermalBoundary:
|
|||
Set thermal boundary window ratio
|
||||
:param value: str
|
||||
"""
|
||||
if self._calculated:
|
||||
if self._window_ration_is_calculated:
|
||||
raise ValueError('Window ratio cannot be assigned when the windows are defined in the geometry.')
|
||||
self._window_ratio = float(value)
|
||||
|
||||
|
@ -421,3 +424,19 @@ class ThermalBoundary:
|
|||
"""
|
||||
if value is not None:
|
||||
self._radiative_coefficient = float(value)
|
||||
|
||||
@property
|
||||
def vegetation(self) -> Union[None, Vegetation]:
|
||||
"""
|
||||
Get the vegetation construction at the external surface of the thermal boundary
|
||||
:return: None or Vegetation
|
||||
"""
|
||||
return self._vegetation
|
||||
|
||||
@vegetation.setter
|
||||
def vegetation(self, value):
|
||||
"""
|
||||
Set the vegetation construction at the external surface of the thermal boundary
|
||||
:param value: Vegetation
|
||||
"""
|
||||
self._vegetation = value
|
||||
|
|
|
@ -37,7 +37,7 @@ class ThermalOpening:
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get thermal zone id, an universally unique identifier randomly generated
|
||||
Get thermal zone id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
|
@ -5,14 +5,15 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import uuid, sys
|
||||
|
||||
import uuid
|
||||
import sys
|
||||
import copy
|
||||
from typing import List, Union, TypeVar
|
||||
from city_model_structure.building_demand.occupancy import Occupancy
|
||||
from city_model_structure.building_demand.appliances import Appliances
|
||||
from city_model_structure.building_demand.lighting import Lighting
|
||||
from city_model_structure.building_demand.internal_gain import InternalGain
|
||||
from city_model_structure.attributes.schedule import Schedule
|
||||
from city_model_structure.building_demand.thermal_control import ThermalControl
|
||||
from city_model_structure.energy_systems.hvac_system import HvacSystem
|
||||
import helpers.constants as cte
|
||||
|
@ -54,7 +55,7 @@ class ThermalZone:
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get thermal zone id, an universally unique identifier randomly generated
|
||||
Get thermal zone id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
|
@ -12,17 +12,18 @@ from city_model_structure.building_demand.occupancy import Occupancy
|
|||
from city_model_structure.building_demand.lighting import Lighting
|
||||
from city_model_structure.building_demand.appliances import Appliances
|
||||
from city_model_structure.building_demand.thermal_control import ThermalControl
|
||||
import helpers.constants as cte
|
||||
|
||||
|
||||
class UsageZone:
|
||||
"""
|
||||
UsageZone class
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, not_detailed_source_mean_annual_internal_gains=None):
|
||||
self._id = None
|
||||
self._usage = None
|
||||
self._percentage = None
|
||||
self._not_detailed_source_mean_annual_internal_gains = None
|
||||
self._not_detailed_source_mean_annual_internal_gains = not_detailed_source_mean_annual_internal_gains
|
||||
self._hours_day = None
|
||||
self._days_year = None
|
||||
# self._electrical_app_average_consumption_sqm_year = None
|
||||
|
@ -31,11 +32,12 @@ class UsageZone:
|
|||
self._lighting = None
|
||||
self._appliances = None
|
||||
self._thermal_control = None
|
||||
self._internal_gains = None
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get usage zone id, an universally unique identifier randomly generated
|
||||
Get usage zone id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
@ -76,22 +78,6 @@ class UsageZone:
|
|||
if value is not None:
|
||||
self._percentage = float(value)
|
||||
|
||||
@property
|
||||
def not_detailed_source_mean_annual_internal_gains(self) -> List[InternalGain]:
|
||||
"""
|
||||
Get usage zone internal gains with unknown energy source
|
||||
:return: [InternalGain]
|
||||
"""
|
||||
return self._not_detailed_source_mean_annual_internal_gains
|
||||
|
||||
@not_detailed_source_mean_annual_internal_gains.setter
|
||||
def not_detailed_source_mean_annual_internal_gains(self, value):
|
||||
"""
|
||||
Set usage zone internal gains with unknown energy source
|
||||
:param value: [InternalGain]
|
||||
"""
|
||||
self._not_detailed_source_mean_annual_internal_gains = value
|
||||
|
||||
@property
|
||||
def hours_day(self) -> Union[None, float]:
|
||||
"""
|
||||
|
@ -143,23 +129,6 @@ class UsageZone:
|
|||
if value is not None:
|
||||
self._mechanical_air_change = float(value)
|
||||
|
||||
@property
|
||||
def electrical_app_average_consumption_sqm_year(self) -> Union[None, float]:
|
||||
"""
|
||||
Get average consumption of electrical appliances in Joules hour per square meter and year (J/m2yr)
|
||||
:return: None or float
|
||||
"""
|
||||
return self._electrical_app_average_consumption_sqm_year
|
||||
|
||||
@electrical_app_average_consumption_sqm_year.setter
|
||||
def electrical_app_average_consumption_sqm_year(self, value):
|
||||
"""
|
||||
Set average consumption of electrical appliances in Joules per square meter and year (J/m2yr)
|
||||
:param value: float
|
||||
"""
|
||||
if value is not None:
|
||||
self._electrical_app_average_consumption_sqm_year = float(value)
|
||||
|
||||
@property
|
||||
def occupancy(self) -> Union[None, Occupancy]:
|
||||
"""
|
||||
|
@ -223,3 +192,64 @@ class UsageZone:
|
|||
:param value: ThermalControl
|
||||
"""
|
||||
self._thermal_control = value
|
||||
|
||||
@property
|
||||
def internal_gains(self) -> List[InternalGain]:
|
||||
"""
|
||||
Calculates and returns the list of all internal gains defined
|
||||
:return: [InternalGain]
|
||||
"""
|
||||
if self._not_detailed_source_mean_annual_internal_gains is not None:
|
||||
self._internal_gains = []
|
||||
for _internal_gain in self._not_detailed_source_mean_annual_internal_gains:
|
||||
self._internal_gains.append(_internal_gain)
|
||||
|
||||
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
|
||||
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
|
||||
else:
|
||||
_internal_gain.latent_fraction = 0
|
||||
_internal_gain.radiative_fraction = 0
|
||||
_internal_gain.convective_fraction = 0
|
||||
_internal_gain.schedules = self.occupancy.occupancy_schedules
|
||||
if self._internal_gains is not None:
|
||||
self._internal_gains.append(_internal_gain)
|
||||
else:
|
||||
self._internal_gains = [_internal_gain]
|
||||
|
||||
if self.lighting is not None:
|
||||
_internal_gain = InternalGain()
|
||||
_internal_gain.type = cte.LIGHTING
|
||||
self._add_internal_gain(self.lighting, _internal_gain)
|
||||
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
|
||||
self._add_internal_gain(self.appliances, _internal_gain)
|
||||
if self._internal_gains is not None:
|
||||
self._internal_gains.append(_internal_gain)
|
||||
else:
|
||||
self._internal_gains = [_internal_gain]
|
||||
|
||||
return self._internal_gains
|
||||
|
||||
@staticmethod
|
||||
def _add_internal_gain(internal_gain_type, _internal_gain):
|
||||
_internal_gain.average_internal_gain = internal_gain_type.density
|
||||
_internal_gain.latent_fraction = internal_gain_type.latent_fraction
|
||||
_internal_gain.radiative_fraction = internal_gain_type.radiative_fraction
|
||||
_internal_gain.convective_fraction = internal_gain_type.convective_fraction
|
||||
_internal_gain.schedules = internal_gain_type.schedules
|
||||
|
|
103
city_model_structure/greenery/plant.py
Normal file
103
city_model_structure/greenery/plant.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
"""
|
||||
Plant class
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from typing import List
|
||||
from city_model_structure.greenery.soil import Soil
|
||||
|
||||
|
||||
class Plant:
|
||||
def __init__(self, name, height, leaf_area_index, leaf_reflectivity, leaf_emissivity, minimal_stomatal_resistance,
|
||||
co2_sequestration, grows_on_soils):
|
||||
self._name = name
|
||||
self._percentage = None
|
||||
self._height = height
|
||||
self._leaf_area_index = leaf_area_index
|
||||
self._leaf_reflectivity = leaf_reflectivity
|
||||
self._leaf_emissivity = leaf_emissivity
|
||||
self._minimal_stomatal_resistance = minimal_stomatal_resistance
|
||||
self._co2_sequestration = co2_sequestration
|
||||
self._grows_on = grows_on_soils
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Get plant name
|
||||
:return: string
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def percentage(self):
|
||||
"""
|
||||
Get percentage of plant in vegetation
|
||||
:return: float
|
||||
"""
|
||||
return self._percentage
|
||||
|
||||
@percentage.setter
|
||||
def percentage(self, value):
|
||||
"""
|
||||
Set percentage of plant in vegetation
|
||||
:param value: float
|
||||
"""
|
||||
self._percentage = value
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
"""
|
||||
Get plant height in m
|
||||
:return: float
|
||||
"""
|
||||
return self._height
|
||||
|
||||
@property
|
||||
def leaf_area_index(self):
|
||||
"""
|
||||
Get plant leaf area index
|
||||
:return: float
|
||||
"""
|
||||
return self._leaf_area_index
|
||||
|
||||
@property
|
||||
def leaf_reflectivity(self):
|
||||
"""
|
||||
Get plant leaf area index
|
||||
:return: float
|
||||
"""
|
||||
return self._leaf_reflectivity
|
||||
|
||||
@property
|
||||
def leaf_emissivity(self):
|
||||
"""
|
||||
Get plant leaf emissivity
|
||||
:return: float
|
||||
"""
|
||||
return self._leaf_emissivity
|
||||
|
||||
@property
|
||||
def minimal_stomatal_resistance(self):
|
||||
"""
|
||||
Get plant minimal stomatal resistance in s/m
|
||||
:return: float
|
||||
"""
|
||||
return self._minimal_stomatal_resistance
|
||||
|
||||
@property
|
||||
def co2_sequestration(self):
|
||||
"""
|
||||
Get plant co2 sequestration capacity in kg CO2 equivalent
|
||||
:return: float
|
||||
"""
|
||||
return self._co2_sequestration
|
||||
|
||||
@property
|
||||
def grows_on(self) -> List[Soil]:
|
||||
"""
|
||||
Get plant compatible soils
|
||||
:return: [Soil]
|
||||
"""
|
||||
return self._grows_on
|
127
city_model_structure/greenery/soil.py
Normal file
127
city_model_structure/greenery/soil.py
Normal file
|
@ -0,0 +1,127 @@
|
|||
"""
|
||||
Soil class
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class Soil:
|
||||
def __init__(self, name, roughness, dry_conductivity, dry_density, dry_specific_heat, thermal_absorptance,
|
||||
solar_absorptance, visible_absorptance, saturation_volumetric_moisture_content,
|
||||
residual_volumetric_moisture_content):
|
||||
self._name = name
|
||||
self._roughness = roughness
|
||||
self._dry_conductivity = dry_conductivity
|
||||
self._dry_density = dry_density
|
||||
self._dry_specific_heat = dry_specific_heat
|
||||
self._thermal_absorptance = thermal_absorptance
|
||||
self._solar_absorptance = solar_absorptance
|
||||
self._visible_absorptance = visible_absorptance
|
||||
self._saturation_volumetric_moisture_content = saturation_volumetric_moisture_content
|
||||
self._residual_volumetric_moisture_content = residual_volumetric_moisture_content
|
||||
self._initial_volumetric_moisture_content = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Get soil name
|
||||
:return: string
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def roughness(self):
|
||||
"""
|
||||
Get soil roughness
|
||||
:return: string
|
||||
"""
|
||||
return self._roughness
|
||||
|
||||
@property
|
||||
def dry_conductivity(self):
|
||||
"""
|
||||
Get soil dry conductivity in W/mK
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_conductivity
|
||||
|
||||
@property
|
||||
def dry_density(self):
|
||||
"""
|
||||
Get soil dry density in kg/m3
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_density
|
||||
|
||||
@property
|
||||
def dry_specific_heat(self):
|
||||
"""
|
||||
Get soil dry specific heat in J/kgK
|
||||
:return: float
|
||||
"""
|
||||
return self._dry_specific_heat
|
||||
|
||||
@property
|
||||
def thermal_absorptance(self):
|
||||
"""
|
||||
Get soil thermal absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._thermal_absorptance
|
||||
|
||||
@property
|
||||
def solar_absorptance(self):
|
||||
"""
|
||||
Get soil solar absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._solar_absorptance
|
||||
|
||||
@property
|
||||
def visible_absorptance(self):
|
||||
"""
|
||||
Get soil visible absortance
|
||||
:return: float
|
||||
"""
|
||||
return self._visible_absorptance
|
||||
|
||||
@property
|
||||
def saturation_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil saturation volumetric moisture content
|
||||
:return: float
|
||||
"""
|
||||
return self._saturation_volumetric_moisture_content
|
||||
|
||||
@property
|
||||
def residual_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil residual volumetric moisture content
|
||||
:return: None or float
|
||||
"""
|
||||
return self._residual_volumetric_moisture_content
|
||||
|
||||
@residual_volumetric_moisture_content.setter
|
||||
def residual_volumetric_moisture_content(self, value):
|
||||
"""
|
||||
Set soil residual volumetric moisture content
|
||||
:param value: float
|
||||
"""
|
||||
self._residual_volumetric_moisture_content = value
|
||||
|
||||
@property
|
||||
def initial_volumetric_moisture_content(self):
|
||||
"""
|
||||
Get soil initial volumetric moisture content
|
||||
:return: None or float
|
||||
"""
|
||||
return self._initial_volumetric_moisture_content
|
||||
|
||||
@initial_volumetric_moisture_content.setter
|
||||
def initial_volumetric_moisture_content(self, value):
|
||||
"""
|
||||
Set soil initial volumetric moisture content
|
||||
:param value: float
|
||||
"""
|
||||
self._initial_volumetric_moisture_content = value
|
84
city_model_structure/greenery/vegetation.py
Normal file
84
city_model_structure/greenery/vegetation.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
"""
|
||||
Vegetation class
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from typing import List
|
||||
from city_model_structure.greenery.soil import Soil
|
||||
from city_model_structure.greenery.plant import Plant
|
||||
|
||||
|
||||
class Vegetation:
|
||||
def __init__(self, name, soil, soil_thickness, plants):
|
||||
self._name = name
|
||||
self._management = None
|
||||
self._air_gap = None
|
||||
self._soil = soil
|
||||
self._soil_thickness = soil_thickness
|
||||
self._plants = plants
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Get vegetation name
|
||||
:return: string
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def management(self):
|
||||
"""
|
||||
Get management
|
||||
:return: string
|
||||
"""
|
||||
return self._management
|
||||
|
||||
@management.setter
|
||||
def management(self, value):
|
||||
"""
|
||||
Set management
|
||||
:param value: string
|
||||
"""
|
||||
self._management = value
|
||||
|
||||
@property
|
||||
def air_gap(self):
|
||||
"""
|
||||
Get air gap in m
|
||||
:return: float
|
||||
"""
|
||||
return self._air_gap
|
||||
|
||||
@air_gap.setter
|
||||
def air_gap(self, value):
|
||||
"""
|
||||
Set air gap in m
|
||||
:param value: float
|
||||
"""
|
||||
self._air_gap = value
|
||||
|
||||
@property
|
||||
def soil(self) -> Soil:
|
||||
"""
|
||||
Get soil
|
||||
:return: Soil
|
||||
"""
|
||||
return self._soil
|
||||
|
||||
@property
|
||||
def soil_thickness(self):
|
||||
"""
|
||||
Get soil thickness in m
|
||||
:return: float
|
||||
"""
|
||||
return self._soil_thickness
|
||||
|
||||
@property
|
||||
def plants(self) -> List[Plant]:
|
||||
"""
|
||||
Get list plants in the vegetation
|
||||
:return: List[Plant]
|
||||
"""
|
||||
return self._plants
|
|
@ -30,7 +30,7 @@ class Network(CityObject):
|
|||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get network id, an universally unique identifier randomly generated
|
||||
Get network id, a universally unique identifier randomly generated
|
||||
:return: str
|
||||
"""
|
||||
if self._id is None:
|
||||
|
|
Binary file not shown.
|
@ -44,6 +44,8 @@ class Idf:
|
|||
_LOCATION = 'SITE:LOCATION'
|
||||
_WINDOW_MATERIAL_SIMPLE = 'WINDOWMATERIAL:SIMPLEGLAZINGSYSTEM'
|
||||
_WINDOW = 'WINDOW'
|
||||
_MATERIAL_ROOFVEGETATION = 'MATERIAL:ROOFVEGETATION'
|
||||
_SIMPLE = 'Simple'
|
||||
|
||||
idf_surfaces = {
|
||||
# todo: make an enum for all the surface types
|
||||
|
@ -224,9 +226,12 @@ class Idf:
|
|||
|
||||
def _add_construction(self, thermal_boundary):
|
||||
for construction in self._idf.idfobjects[self._CONSTRUCTION]:
|
||||
if construction.Name == thermal_boundary.construction_name:
|
||||
return
|
||||
|
||||
if thermal_boundary.vegetation is not None:
|
||||
if construction.Name == f'{thermal_boundary.construction_name}_{thermal_boundary.vegetation.name}':
|
||||
return
|
||||
else:
|
||||
if construction.Name == thermal_boundary.construction_name:
|
||||
return
|
||||
if thermal_boundary.layers is None:
|
||||
for material in self._idf.idfobjects[self._MATERIAL]:
|
||||
if material.Name == "DefaultMaterial":
|
||||
|
@ -237,9 +242,15 @@ class Idf:
|
|||
self._add_material(layer)
|
||||
layers = thermal_boundary.layers
|
||||
# The constructions should have at least one layer
|
||||
_kwargs = {'Name': thermal_boundary.construction_name, 'Outside_Layer': layers[0].material.name}
|
||||
for i in range(1, len(layers) - 1):
|
||||
_kwargs[f'Layer_{i + 1}'] = layers[1].material.name
|
||||
if thermal_boundary.vegetation is not None:
|
||||
_kwargs = {'Name': f'{thermal_boundary.construction_name}_{thermal_boundary.vegetation.name}',
|
||||
'Outside_Layer': thermal_boundary.vegetation.name}
|
||||
for i in range(0, len(layers) - 1):
|
||||
_kwargs[f'Layer_{i + 2}'] = layers[i].material.name
|
||||
else:
|
||||
_kwargs = {'Name': thermal_boundary.construction_name, 'Outside_Layer': layers[0].material.name}
|
||||
for i in range(1, len(layers) - 1):
|
||||
_kwargs[f'Layer_{i + 1}'] = layers[i].material.name
|
||||
self._idf.newidfobject(self._CONSTRUCTION, **_kwargs)
|
||||
|
||||
def _add_window_construction_and_material(self, thermal_opening):
|
||||
|
@ -342,6 +353,8 @@ class Idf:
|
|||
for thermal_zone in internal_zone.thermal_zones:
|
||||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||
self._add_construction(thermal_boundary)
|
||||
if thermal_boundary.vegetation is not None:
|
||||
self._add_vegetation_material(thermal_boundary.vegetation)
|
||||
for thermal_opening in thermal_boundary.thermal_openings:
|
||||
self._add_window_construction_and_material(thermal_opening)
|
||||
usage = thermal_zone.usage
|
||||
|
@ -355,7 +368,6 @@ class Idf:
|
|||
self._add_heating_system(thermal_zone)
|
||||
self._add_infiltration(thermal_zone)
|
||||
self._add_occupancy(thermal_zone)
|
||||
|
||||
if self._export_type == "Surfaces":
|
||||
self._add_surfaces(building)
|
||||
else:
|
||||
|
@ -404,10 +416,13 @@ class Idf:
|
|||
for thermal_zone in internal_zone.thermal_zones:
|
||||
for boundary in thermal_zone.thermal_boundaries:
|
||||
idf_surface_type = self.idf_surfaces[boundary.parent_surface.type]
|
||||
# todo: thermal boundary vs. surfaces??
|
||||
if boundary.vegetation is not None:
|
||||
construction_name = f'{boundary.construction_name}_{boundary.vegetation.name}'
|
||||
else:
|
||||
construction_name = boundary.construction_name
|
||||
surface = self._idf.newidfobject(self._SURFACE, Name=f'{boundary.parent_surface.name}',
|
||||
Surface_Type=idf_surface_type, Zone_Name=thermal_zone.id,
|
||||
Construction_Name=boundary.construction_name)
|
||||
Construction_Name=construction_name)
|
||||
coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
|
||||
self._city.lower_corner)
|
||||
surface.setcoords(coordinates)
|
||||
|
@ -433,3 +448,44 @@ class Idf:
|
|||
material['Solar_Heat_Gain_Coefficient'] == opening.g_value:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _add_vegetation_material(self, vegetation):
|
||||
for vegetation_material in self._idf.idfobjects[self._MATERIAL_ROOFVEGETATION]:
|
||||
if vegetation_material.Name == vegetation.name:
|
||||
return
|
||||
soil = vegetation.soil
|
||||
height = 0
|
||||
leaf_area_index = 0
|
||||
leaf_reflectivity = 0
|
||||
leaf_emissivity = 0
|
||||
minimal_stomatal_resistance = 0
|
||||
for plant in vegetation.plants:
|
||||
height += plant.percentage * plant.height
|
||||
leaf_area_index += plant.percentage * plant.leaf_area_index
|
||||
leaf_reflectivity += plant.percentage * plant.leaf_reflectivity
|
||||
leaf_emissivity += plant.percentage * plant.leaf_emissivity
|
||||
minimal_stomatal_resistance += plant.percentage * plant.minimal_stomatal_resistance
|
||||
self._idf.newidfobject(self._MATERIAL_ROOFVEGETATION,
|
||||
Name=vegetation.name,
|
||||
Height_of_Plants=height,
|
||||
Leaf_Area_Index=leaf_area_index,
|
||||
Leaf_Reflectivity=leaf_reflectivity,
|
||||
Leaf_Emissivity=leaf_emissivity,
|
||||
Minimum_Stomatal_Resistance=minimal_stomatal_resistance,
|
||||
Soil_Layer_Name=soil.name,
|
||||
Roughness=soil.roughness,
|
||||
Thickness=vegetation.soil_thickness,
|
||||
Conductivity_of_Dry_Soil=soil.dry_conductivity,
|
||||
Density_of_Dry_Soil=soil.dry_density,
|
||||
Specific_Heat_of_Dry_Soil=soil.dry_specific_heat,
|
||||
Thermal_Absorptance=soil.thermal_absorptance,
|
||||
Solar_Absorptance=soil.solar_absorptance,
|
||||
Visible_Absorptance=soil.visible_absorptance,
|
||||
Saturation_Volumetric_Moisture_Content_of_the_Soil_Layer=
|
||||
soil.saturation_volumetric_moisture_content,
|
||||
Residual_Volumetric_Moisture_Content_of_the_Soil_Layer=
|
||||
soil.residual_volumetric_moisture_content,
|
||||
Initial_Volumetric_Moisture_Content_of_the_Soil_Layer=
|
||||
soil.initial_volumetric_moisture_content,
|
||||
Moisture_Diffusion_Calculation_Method=self._SIMPLE
|
||||
)
|
||||
|
|
|
@ -9,14 +9,9 @@ import sys
|
|||
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
||||
from imports.usage.hft_usage_interface import HftUsageInterface
|
||||
from imports.usage.helpers.usage_helper import UsageHelper
|
||||
from city_model_structure.building_demand.usage_zone import UsageZone
|
||||
from city_model_structure.building_demand.internal_gain import InternalGain
|
||||
from city_model_structure.building_demand.occupancy import Occupancy
|
||||
from city_model_structure.building_demand.appliances import Appliances
|
||||
from city_model_structure.building_demand.thermal_control import ThermalControl
|
||||
|
||||
|
||||
class CaUsageParameters(HftUsageInterface):
|
||||
class HftUsageParameters(HftUsageInterface):
|
||||
"""
|
||||
CaUsageParameters class
|
||||
"""
|
||||
|
@ -36,48 +31,11 @@ class CaUsageParameters(HftUsageInterface):
|
|||
archetype = self._search_archetype(usage)
|
||||
except KeyError:
|
||||
sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
|
||||
f' {building.function}\n')
|
||||
f' {building.function}, that assigns building usage as '
|
||||
f'{GeometryHelper().libs_usage_from_libs_function(building.function)}\n')
|
||||
return
|
||||
|
||||
for internal_zone in building.internal_zones:
|
||||
usage_zone = UsageZone()
|
||||
usage_zone.usage = building.function
|
||||
usage_zone = self._assign_values(building.function, archetype)
|
||||
usage_zone.percentage = 1
|
||||
self._assign_values_usage_zone(usage_zone, archetype)
|
||||
internal_zone.usage_zones = [usage_zone]
|
||||
|
||||
def _search_archetype(self, libs_usage):
|
||||
building_usage = UsageHelper().hft_from_libs_usage(libs_usage)
|
||||
for building_archetype in self._usage_archetypes:
|
||||
if building_archetype.usage == building_usage:
|
||||
return building_archetype
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _assign_values_usage_zone(usage_zone, archetype):
|
||||
# Due to the fact that python is not a typed language, the wrong object type is assigned to
|
||||
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
|
||||
# Therefore, this walk around has been done.
|
||||
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|
||||
_occupancy = Occupancy()
|
||||
_occupancy.occupancy_density = archetype.occupancy.occupancy_density
|
||||
usage_zone.occupancy = _occupancy
|
||||
usage_zone.hours_day = archetype.hours_day
|
||||
usage_zone.days_year = archetype.days_year
|
||||
_appliances = Appliances()
|
||||
_appliances.density = archetype.appliances.density
|
||||
usage_zone.appliances = _appliances
|
||||
_control = ThermalControl()
|
||||
_control.mean_heating_set_point = archetype.thermal_control.mean_heating_set_point
|
||||
_control.heating_set_back = archetype.thermal_control.heating_set_back
|
||||
_control.mean_cooling_set_point = archetype.thermal_control.mean_cooling_set_point
|
||||
usage_zone.thermal_control = _control
|
||||
_internal_gains = []
|
||||
for archetype_internal_gain in archetype.not_detailed_source_mean_annual_internal_gains:
|
||||
_internal_gain = InternalGain()
|
||||
_internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain
|
||||
_internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
|
||||
_internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
|
||||
_internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
|
||||
_internal_gains.append(_internal_gain)
|
||||
usage_zone.not_detailed_source_mean_annual_internal_gains = _internal_gains
|
||||
|
|
|
@ -14,6 +14,7 @@ from city_model_structure.building_demand.appliances import Appliances
|
|||
from city_model_structure.building_demand.thermal_control import ThermalControl
|
||||
from city_model_structure.attributes.schedule import Schedule
|
||||
import helpers.constants as cte
|
||||
from imports.usage.helpers.usage_helper import UsageHelper
|
||||
|
||||
|
||||
class HftUsageInterface:
|
||||
|
@ -38,15 +39,9 @@ class HftUsageInterface:
|
|||
|
||||
@staticmethod
|
||||
def _parse_zone_usage_type(usage, zone_usage_type):
|
||||
usage_zone_archetype = UsageZone()
|
||||
usage_zone_archetype.usage = usage
|
||||
|
||||
if 'occupancy' in zone_usage_type:
|
||||
_occupancy = Occupancy()
|
||||
_occupancy.occupancy_density = zone_usage_type['occupancy']['occupancyDensity'] #todo: check units
|
||||
usage_zone_archetype.hours_day = zone_usage_type['occupancy']['usageHoursPerDay']
|
||||
usage_zone_archetype.days_year = zone_usage_type['occupancy']['usageDaysPerYear']
|
||||
usage_zone_archetype.occupancy = _occupancy
|
||||
|
||||
if 'internGains' in zone_usage_type['occupancy']:
|
||||
_internal_gain = InternalGain()
|
||||
|
@ -72,7 +67,18 @@ class HftUsageInterface:
|
|||
_schedule.values = _values_float
|
||||
_internal_gain.schedules = [_schedule]
|
||||
|
||||
usage_zone_archetype.not_detailed_source_mean_annual_internal_gains = [_internal_gain]
|
||||
_not_detailed_source_mean_annual_internal_gains = [_internal_gain]
|
||||
usage_zone_archetype = UsageZone(_not_detailed_source_mean_annual_internal_gains)
|
||||
else:
|
||||
usage_zone_archetype = UsageZone()
|
||||
|
||||
usage_zone_archetype.hours_day = zone_usage_type['occupancy']['usageHoursPerDay']
|
||||
usage_zone_archetype.days_year = zone_usage_type['occupancy']['usageDaysPerYear']
|
||||
usage_zone_archetype.occupancy = _occupancy
|
||||
|
||||
else:
|
||||
usage_zone_archetype = UsageZone()
|
||||
usage_zone_archetype.usage = usage
|
||||
|
||||
if 'endUses' in zone_usage_type:
|
||||
_thermal_control = ThermalControl()
|
||||
|
@ -256,3 +262,24 @@ class HftUsageInterface:
|
|||
usage_zone_archetype.appliances = _appliances
|
||||
|
||||
return usage_zone_archetype
|
||||
|
||||
def _search_archetype(self, libs_usage):
|
||||
building_usage = UsageHelper().hft_from_libs_usage(libs_usage)
|
||||
for building_archetype in self._usage_archetypes:
|
||||
if building_archetype.usage == building_usage:
|
||||
return building_archetype
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _assign_values(usage, archetype):
|
||||
_not_detailed_source_mean_annual_internal_gains = \
|
||||
copy.deepcopy(archetype.internal_gains)
|
||||
usage_zone = UsageZone(_not_detailed_source_mean_annual_internal_gains)
|
||||
usage_zone.usage = usage
|
||||
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|
||||
usage_zone.occupancy = copy.deepcopy(archetype.occupancy)
|
||||
usage_zone.appliances = copy.deepcopy(archetype.appliances)
|
||||
usage_zone.thermal_control = copy.deepcopy(archetype.thermal_control)
|
||||
usage_zone.days_year = archetype.days_year
|
||||
usage_zone.hours_day = archetype.hours_day
|
||||
return usage_zone
|
||||
|
|
|
@ -5,12 +5,10 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import sys
|
||||
import copy
|
||||
|
||||
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
||||
from imports.usage.hft_usage_interface import HftUsageInterface
|
||||
from imports.usage.helpers.usage_helper import UsageHelper
|
||||
from city_model_structure.building_demand.usage_zone import UsageZone
|
||||
|
||||
|
||||
class HftUsageParameters(HftUsageInterface):
|
||||
|
@ -38,58 +36,7 @@ class HftUsageParameters(HftUsageInterface):
|
|||
return
|
||||
|
||||
for internal_zone in building.internal_zones:
|
||||
usage_zone = UsageZone()
|
||||
libs_usage = GeometryHelper().libs_usage_from_libs_function(building.function)
|
||||
usage_zone.usage = UsageHelper().hft_from_libs_usage(libs_usage)
|
||||
self._assign_values(usage_zone, archetype)
|
||||
usage_zone = self._assign_values(UsageHelper().hft_from_libs_usage(libs_usage), archetype)
|
||||
usage_zone.percentage = 1
|
||||
internal_zone.usage_zones = [usage_zone]
|
||||
|
||||
def _search_archetype(self, libs_usage):
|
||||
building_usage = UsageHelper().hft_from_libs_usage(libs_usage)
|
||||
for building_archetype in self._usage_archetypes:
|
||||
if building_archetype.usage == building_usage:
|
||||
return building_archetype
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _assign_values(usage_zone, archetype):
|
||||
""" # Due to the fact that python is not a typed language, the wrong object type is assigned to
|
||||
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
|
||||
# Therefore, this walk around has been done.
|
||||
# Due to the fact that python is not a typed language, the wrong object type is assigned to
|
||||
# usage_zone.occupancy when writing usage_zone.occupancy = archetype.occupancy.
|
||||
# Same happens for lighting and appliances. Therefore, this walk around has been done.
|
||||
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|
||||
_occupancy = Occupancy()
|
||||
_occupancy.occupancy_density = archetype.occupancy.occupancy_density
|
||||
usage_zone.occupancy = _occupancy
|
||||
_appliances = Appliances()
|
||||
_appliances.appliances_density = archetype.appliances.appliances_density
|
||||
usage_zone.appliances = _appliances
|
||||
_control = ThermalControl()
|
||||
_control.mean_heating_set_point = archetype.thermal_control.mean_heating_set_point
|
||||
_control.heating_set_back = archetype.thermal_control.heating_set_back
|
||||
_control.mean_cooling_set_point = archetype.thermal_control.mean_cooling_set_point
|
||||
_control.cooling_set_point_schedules = archetype.thermal_control.cooling_set_point_schedules
|
||||
_control.heating_set_point_schedules = archetype.thermal_control.heating_set_point_schedules
|
||||
usage_zone.thermal_control = _control
|
||||
_internal_gains = []
|
||||
for archetype_internal_gain in archetype.not_detailed_source_mean_annual_internal_gains:
|
||||
_internal_gain = InternalGain()
|
||||
_internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain
|
||||
_internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
|
||||
_internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
|
||||
_internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
|
||||
_internal_gain.schedules = archetype_internal_gain.schedules
|
||||
_internal_gains.append(_internal_gain)
|
||||
usage_zone.not_detailed_source_mean_annual_internal_gains = _internal_gains
|
||||
"""
|
||||
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|
||||
usage_zone.occupancy = copy.deepcopy(archetype.occupancy)
|
||||
usage_zone.appliances = copy.deepcopy(archetype.appliances)
|
||||
usage_zone.thermal_control = copy.deepcopy(archetype.thermal_control)
|
||||
usage_zone.not_detailed_source_mean_annual_internal_gains = \
|
||||
copy.deepcopy(archetype.not_detailed_source_mean_annual_internal_gains)
|
||||
usage_zone.days_year = archetype.days_year
|
||||
usage_zone.hours_day = archetype.hours_day
|
||||
|
|
|
@ -8,9 +8,7 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
|||
"""
|
||||
from pathlib import Path
|
||||
from imports.usage.hft_usage_parameters import HftUsageParameters
|
||||
from imports.usage.ca_usage_parameters import CaUsageParameters
|
||||
from imports.usage.comnet_usage_parameters import ComnetUsageParameters
|
||||
# todo: handle missing lambda and rise error.
|
||||
|
||||
|
||||
class UsageFactory:
|
||||
|
@ -30,12 +28,6 @@ class UsageFactory:
|
|||
"""
|
||||
return HftUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||
|
||||
def _ca(self):
|
||||
"""
|
||||
Enrich the city with Canada usage library
|
||||
"""
|
||||
return CaUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||
|
||||
def _comnet(self):
|
||||
"""
|
||||
Enrich the city with COMNET usage library
|
||||
|
|
103
unittests/test_greenery_in_idf.py
Normal file
103
unittests/test_greenery_in_idf.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
"""
|
||||
Greenery in idf test
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
from pathlib import Path
|
||||
import csv
|
||||
import helpers.constants as cte
|
||||
from unittest import TestCase
|
||||
from imports.geometry_factory import GeometryFactory
|
||||
from imports.usage_factory import UsageFactory
|
||||
from imports.construction_factory import ConstructionFactory
|
||||
from exports.exports_factory import ExportsFactory
|
||||
from city_model_structure.greenery.vegetation import Vegetation
|
||||
from city_model_structure.greenery.soil import Soil
|
||||
from city_model_structure.greenery.plant import Plant
|
||||
|
||||
|
||||
class GreeneryInIdf(TestCase):
|
||||
"""
|
||||
GreeneryInIdf TestCase 1
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def test_greenery_in_idf():
|
||||
city_file = "../unittests/tests_data/one_building_in_kelowna.gml"
|
||||
output_path = Path('../unittests/tests_outputs/').resolve()
|
||||
|
||||
city = GeometryFactory('citygml', city_file).city
|
||||
for building in city.buildings:
|
||||
building.year_of_construction = 2006
|
||||
ConstructionFactory('nrel', city).enrich()
|
||||
UsageFactory('comnet', city).enrich()
|
||||
vegetation_name = 'BaseEco'
|
||||
soil_thickness = 0.18
|
||||
soil_name = 'EcoRoofSoil'
|
||||
roughness = 'MediumSmooth'
|
||||
dry_conductivity = 0.4
|
||||
dry_density = 641
|
||||
dry_specific_heat = 1100
|
||||
thermal_absorptance = 0.95
|
||||
solar_absorptance = 0.8
|
||||
visible_absorptance = 0.7
|
||||
saturation_volumetric_moisture_content = 0.4
|
||||
residual_volumetric_moisture_content = 0.01
|
||||
soil = Soil(soil_name, roughness, dry_conductivity, dry_density, dry_specific_heat, thermal_absorptance,
|
||||
solar_absorptance, visible_absorptance, saturation_volumetric_moisture_content,
|
||||
residual_volumetric_moisture_content)
|
||||
soil.initial_volumetric_moisture_content = 0.2
|
||||
plant_name = 'plant'
|
||||
height = 0.5
|
||||
leaf_area_index = 5
|
||||
leaf_reflectivity = 0.2
|
||||
leaf_emissivity = 0.95
|
||||
minimal_stomatal_resistance = 180
|
||||
co2_sequestration = 0
|
||||
grows_on_soils = [soil]
|
||||
plant = Plant(plant_name, height, leaf_area_index, leaf_reflectivity, leaf_emissivity, minimal_stomatal_resistance,
|
||||
co2_sequestration, grows_on_soils)
|
||||
plant.percentage = 1
|
||||
plants = [plant]
|
||||
vegetation = Vegetation(vegetation_name, soil, soil_thickness, plants)
|
||||
for building in city.buildings:
|
||||
for internal_zone in building.internal_zones:
|
||||
for thermal_zone in internal_zone.thermal_zones:
|
||||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||
if thermal_boundary.type == cte.ROOF:
|
||||
thermal_boundary.vegetation = vegetation
|
||||
|
||||
_idf_2 = ExportsFactory('idf', city, output_path).export_debug()
|
||||
_idf_2.run()
|
||||
with open((output_path / f'{city.name}_out.csv').resolve()) as f:
|
||||
reader = csv.reader(f, delimiter=',')
|
||||
heating = 0
|
||||
cooling = 0
|
||||
for row in reader:
|
||||
if '00:00' in row[0]:
|
||||
heating += float(row[8]) / 3600000
|
||||
cooling += float(row[9]) / 3600000
|
||||
|
||||
print('With greenery')
|
||||
print(f'heating: {heating} MWh/yr, cooling: {cooling} MWh/yr')
|
||||
|
||||
city = GeometryFactory('citygml', city_file).city
|
||||
for building in city.buildings:
|
||||
building.year_of_construction = 2006
|
||||
ConstructionFactory('nrel', city).enrich()
|
||||
UsageFactory('comnet', city).enrich()
|
||||
_idf = ExportsFactory('idf', city, output_path).export()
|
||||
_idf.run()
|
||||
with open((output_path / f'{city.name}_out.csv').resolve()) as f:
|
||||
reader = csv.reader(f, delimiter=',')
|
||||
heating = 0
|
||||
cooling = 0
|
||||
for row in reader:
|
||||
if '00:00' in row[0]:
|
||||
heating += float(row[8]) / 3600000
|
||||
cooling += float(row[9]) / 3600000
|
||||
|
||||
print('Without greenery')
|
||||
print(f'heating: {heating} MWh/yr, cooling: {cooling} MWh/yr')
|
||||
|
|
@ -127,23 +127,6 @@ class TestUsageFactory(TestCase):
|
|||
self.assertIsNotNone(usage_zone.thermal_control.hvac_availability_schedules,
|
||||
'control hvac availability is none')
|
||||
|
||||
def test_import_ca(self):
|
||||
"""
|
||||
Enrich the city with the usage information from canada and verify it
|
||||
"""
|
||||
file = 'one_building_in_kelowna.gml'
|
||||
city = self._get_citygml(file)
|
||||
UsageFactory('ca', city).enrich()
|
||||
self._check_buildings(city)
|
||||
for building in city.buildings:
|
||||
for internal_zone in building.internal_zones:
|
||||
self.assertIsNot(len(internal_zone.usage_zones), 0, 'no building usage_zones defined')
|
||||
for usage_zone in internal_zone.usage_zones:
|
||||
self._check_usage_zone(usage_zone)
|
||||
self.assertIsNotNone(usage_zone.mechanical_air_change, 'mechanical air change is none')
|
||||
self.assertIsNotNone(usage_zone.not_detailed_source_mean_annual_internal_gains,
|
||||
'not detailed internal gains is none')
|
||||
|
||||
def test_import_hft(self):
|
||||
"""
|
||||
Enrich the city with the usage information from hft and verify it
|
||||
|
|
Loading…
Reference in New Issue
Block a user