greenery added to idf exporter and unittest created

This commit is contained in:
Pilar 2022-05-16 09:35:19 -04:00
parent 43aaf79cb6
commit 1aeca13e01
14 changed files with 564 additions and 55 deletions

View File

@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
class Content: class Content:
def __init__(self, vegetations, plants, soils): def __init__(self, vegetations, plants, soils):
self._vegetations = vegetations self._vegetations = vegetations

View File

@ -5,7 +5,7 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca 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: class Plant:
@ -20,12 +20,13 @@ class Plant:
self._co2_sequestration = plant.co2Sequestration self._co2_sequestration = plant.co2Sequestration
self._grows_on = [] self._grows_on = []
for soil in plant.growsOn: for soil in plant.growsOn:
self._grows_on.append(libs_soil(soil)) self._grows_on.append(hub_soil(soil))
@property @property
def name(self): def name(self):
""" """
Get plant name Get plant name
:return: string
""" """
return self._name return self._name
@ -33,13 +34,15 @@ class Plant:
def category(self): def category(self):
""" """
Get plant category name Get plant category name
:return: string
""" """
return self._category return self._category
@property @property
def height(self): def height(self):
""" """
Get plant height Get plant height in m
:return: float
""" """
return self._height return self._height
@ -47,6 +50,7 @@ class Plant:
def leaf_area_index(self): def leaf_area_index(self):
""" """
Get plant leaf area index Get plant leaf area index
:return: float
""" """
return self._leaf_area_index return self._leaf_area_index
@ -54,6 +58,7 @@ class Plant:
def leaf_reflectivity(self): def leaf_reflectivity(self):
""" """
Get plant leaf area index Get plant leaf area index
:return: float
""" """
return self._leaf_reflectivity return self._leaf_reflectivity
@ -61,26 +66,30 @@ class Plant:
def leaf_emissivity(self): def leaf_emissivity(self):
""" """
Get plant leaf emissivity Get plant leaf emissivity
:return: float
""" """
return self._leaf_emissivity return self._leaf_emissivity
@property @property
def minimal_stomatal_resistance(self): 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 return self._minimal_stomatal_resistance
@property @property
def co2_sequestration(self): def co2_sequestration(self):
""" """
Get plant co2 sequestration capacity Get plant co2 sequestration capacity in kg CO2 equivalent
:return: float
""" """
return self._co2_sequestration return self._co2_sequestration
@property @property
def grows_on(self) -> [libs_soil]: def grows_on(self) -> [hub_soil]:
""" """
Get plant compatible soils Get plant compatible soils
:return: [Soil]
""" """
return self._grows_on return self._grows_on

View File

@ -7,6 +7,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from catalog_factories.data_models.greenery.plant import Plant as libs_plant from catalog_factories.data_models.greenery.plant import Plant as libs_plant
class PlantPercentage(libs_plant): class PlantPercentage(libs_plant):
def __init__(self, percentage, plant_category, plant): def __init__(self, percentage, plant_category, plant):
@ -15,4 +16,8 @@ class PlantPercentage(libs_plant):
@property @property
def percentage(self): def percentage(self):
"""
Get plant percentage
:return: float
"""
return self._percentage return self._percentage

View File

@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
class Soil: class Soil:
def __init__(self, soil): def __init__(self, soil):
self._name = soil.name self._name = soil.name
@ -23,6 +24,7 @@ class Soil:
def name(self): def name(self):
""" """
Get soil name Get soil name
:return: string
""" """
return self._name return self._name
@ -30,27 +32,31 @@ class Soil:
def roughness(self): def roughness(self):
""" """
Get soil roughness Get soil roughness
:return: string
""" """
return self._roughness return self._roughness
@property @property
def dry_conductivity(self): def dry_conductivity(self):
""" """
Get soil dry conductivity Get soil dry conductivity in W/mK
:return: float
""" """
return self._dry_conductivity return self._dry_conductivity
@property @property
def dry_density(self): def dry_density(self):
""" """
Get soil dry density Get soil dry density in kg/m3
:return: float
""" """
return self._dry_density return self._dry_density
@property @property
def dry_specific_heat(self): 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 return self._dry_specific_heat
@ -58,6 +64,7 @@ class Soil:
def thermal_absorptance(self): def thermal_absorptance(self):
""" """
Get soil thermal absortance Get soil thermal absortance
:return: float
""" """
return self._thermal_absorptance return self._thermal_absorptance
@ -65,6 +72,7 @@ class Soil:
def solar_absorptance(self): def solar_absorptance(self):
""" """
Get soil solar absortance Get soil solar absortance
:return: float
""" """
return self._solar_absorptance return self._solar_absorptance
@ -72,6 +80,7 @@ class Soil:
def visible_absorptance(self): def visible_absorptance(self):
""" """
Get soil visible absortance Get soil visible absortance
:return: float
""" """
return self._visible_absorptance return self._visible_absorptance
@ -79,6 +88,7 @@ class Soil:
def saturation_volumetric_moisture_content(self): def saturation_volumetric_moisture_content(self):
""" """
Get soil saturation volumetric moisture content Get soil saturation volumetric moisture content
:return: float
""" """
return self._saturation_volumetric_moisture_content return self._saturation_volumetric_moisture_content
@ -86,6 +96,7 @@ class Soil:
def residual_volumetric_moisture_content(self): def residual_volumetric_moisture_content(self):
""" """
Get soil residual volumetric moisture content Get soil residual volumetric moisture content
:return: float
""" """
return self._residual_volumetric_moisture_content return self._residual_volumetric_moisture_content
@ -93,5 +104,6 @@ class Soil:
def initial_volumetric_moisture_content(self): def initial_volumetric_moisture_content(self):
""" """
Get soil initial volumetric moisture content Get soil initial volumetric moisture content
:return: float
""" """
return self._initial_volumetric_moisture_content return self._initial_volumetric_moisture_content

View File

@ -7,6 +7,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from catalog_factories.data_models.greenery.plant_percentage import PlantPercentage from catalog_factories.data_models.greenery.plant_percentage import PlantPercentage
class Vegetation: class Vegetation:
def __init__(self, category, vegetation, plant_percentages): def __init__(self, category, vegetation, plant_percentages):
self._name = vegetation.name self._name = vegetation.name
@ -31,6 +32,7 @@ class Vegetation:
def name(self): def name(self):
""" """
Get vegetation name Get vegetation name
:return: string
""" """
return self._name return self._name
@ -38,13 +40,15 @@ class Vegetation:
def category(self): def category(self):
""" """
Get vegetation category Get vegetation category
:return: string
""" """
return self._category return self._category
@property @property
def soil_thickness(self): def soil_thickness(self):
""" """
Get soil thickness Get soil thickness in m
:return: float
""" """
return self._soil_thickness return self._soil_thickness
@ -52,13 +56,15 @@ class Vegetation:
def management(self): def management(self):
""" """
Get management Get management
:return: string
""" """
return self._management return self._management
@property @property
def air_gap(self): def air_gap(self):
""" """
Get air gap Get air gap in m
:return: float
""" """
return self._air_gap return self._air_gap
@ -66,6 +72,7 @@ class Vegetation:
def plant_percentages(self) -> [PlantPercentage]: def plant_percentages(self) -> [PlantPercentage]:
""" """
Get plant percentages Get plant percentages
:return: [PlantPercentage]
""" """
percentage = 0.0 percentage = 0.0
for plant_percentage in self._plant_percentages: for plant_percentage in self._plant_percentages:
@ -78,6 +85,7 @@ class Vegetation:
def soil_name(self): def soil_name(self):
""" """
Get soil name Get soil name
:return: string
""" """
return self._soil_name return self._soil_name
@ -85,27 +93,31 @@ class Vegetation:
def soil_roughness(self): def soil_roughness(self):
""" """
Get soil roughness Get soil roughness
:return: float
""" """
return self._soil_roughness return self._soil_roughness
@property @property
def dry_soil_conductivity(self): def dry_soil_conductivity(self):
""" """
Get soil dry conductivity Get soil dry conductivity in W/mK
:return: float
""" """
return self._dry_soil_conductivity return self._dry_soil_conductivity
@property @property
def dry_soil_density(self): def dry_soil_density(self):
""" """
Get soil dry density Get soil dry density in kg/m3
:return: float
""" """
return self._dry_soil_density return self._dry_soil_density
@property @property
def dry_soil_specific_heat(self): 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 return self._dry_soil_specific_heat
@ -113,6 +125,7 @@ class Vegetation:
def soil_thermal_absorptance(self): def soil_thermal_absorptance(self):
""" """
Get soil thermal absortance Get soil thermal absortance
:return: float
""" """
return self._soil_thermal_absorptance return self._soil_thermal_absorptance
@ -120,6 +133,7 @@ class Vegetation:
def soil_solar_absorptance(self): def soil_solar_absorptance(self):
""" """
Get soil solar absortance Get soil solar absortance
:return: float
""" """
return self._soil_solar_absorptance return self._soil_solar_absorptance
@ -127,6 +141,7 @@ class Vegetation:
def soil_visible_absorptance(self): def soil_visible_absorptance(self):
""" """
Get soil visible absortance Get soil visible absortance
:return: float
""" """
return self._soil_visible_absorptance return self._soil_visible_absorptance
@ -134,6 +149,7 @@ class Vegetation:
def soil_saturation_volumetric_moisture_content(self): def soil_saturation_volumetric_moisture_content(self):
""" """
Get soil saturation volumetric moisture content Get soil saturation volumetric moisture content
:return: float
""" """
return self._soil_saturation_volumetric_moisture_content return self._soil_saturation_volumetric_moisture_content
@ -141,6 +157,7 @@ class Vegetation:
def soil_residual_volumetric_moisture_content(self): def soil_residual_volumetric_moisture_content(self):
""" """
Get soil residual volumetric moisture content Get soil residual volumetric moisture content
:return: float
""" """
return self._soil_residual_volumetric_moisture_content return self._soil_residual_volumetric_moisture_content
@ -148,5 +165,6 @@ class Vegetation:
def soil_initial_volumetric_moisture_content(self): def soil_initial_volumetric_moisture_content(self):
""" """
Get soil initial volumetric moisture content Get soil initial volumetric moisture content
:return: float
""" """
return self._soil_initial_volumetric_moisture_content return self._soil_initial_volumetric_moisture_content

View File

@ -40,8 +40,7 @@ class Surface:
self._solid_polygon = solid_polygon self._solid_polygon = solid_polygon
self._pv_system_installed = None self._pv_system_installed = None
self._inverse = None self._inverse = None
# todo: do I need it??? # todo: create self._associated_thermal_boundaries and bring the vegetation here instead of in thermal_boundary
self._associated_thermal_boundaries = None
@property @property
def name(self): def name(self):

View File

@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import uuid import uuid
from typing import List, Union from typing import List, Union
from helpers.configuration_helper import ConfigurationHelper as ch 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_opening import ThermalOpening
from city_model_structure.building_demand.thermal_zone import ThermalZone from city_model_structure.building_demand.thermal_zone import ThermalZone
from city_model_structure.building_demand.surface import Surface from city_model_structure.building_demand.surface import Surface
from city_model_structure.greenery.vegetation import Vegetation
class ThermalBoundary: class ThermalBoundary:
@ -41,12 +43,13 @@ class ThermalBoundary:
self._alpha_coefficient = None self._alpha_coefficient = None
self._radiative_coefficient = None self._radiative_coefficient = None
self._window_ratio = None self._window_ratio = None
self._calculated = False self._window_ration_is_calculated = False
self._vegetation = None
@property @property
def id(self): 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 :return: str
""" """
if self._id is None: if self._id is None:
@ -249,7 +252,7 @@ class ThermalBoundary:
:return: float :return: float
""" """
if self.windows_areas is not None: if self.windows_areas is not None:
if not self._calculated: if not self._window_ration_is_calculated:
_calculated = True _calculated = True
if len(self.windows_areas) == 0: if len(self.windows_areas) == 0:
self._window_ratio = 0 self._window_ratio = 0
@ -266,7 +269,7 @@ class ThermalBoundary:
Set thermal boundary window ratio Set thermal boundary window ratio
:param value: str :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.') raise ValueError('Window ratio cannot be assigned when the windows are defined in the geometry.')
self._window_ratio = float(value) self._window_ratio = float(value)
@ -421,3 +424,19 @@ class ThermalBoundary:
""" """
if value is not None: if value is not None:
self._radiative_coefficient = float(value) 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

View File

@ -5,14 +5,15 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import uuid, sys
import uuid
import sys
import copy import copy
from typing import List, Union, TypeVar from typing import List, Union, TypeVar
from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.occupancy import Occupancy
from city_model_structure.building_demand.appliances import Appliances from city_model_structure.building_demand.appliances import Appliances
from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.lighting import Lighting
from city_model_structure.building_demand.internal_gain import InternalGain 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.building_demand.thermal_control import ThermalControl
from city_model_structure.energy_systems.hvac_system import HvacSystem from city_model_structure.energy_systems.hvac_system import HvacSystem
import helpers.constants as cte import helpers.constants as cte

View 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

View 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

View 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

View File

@ -44,8 +44,8 @@ class Idf:
_LOCATION = 'SITE:LOCATION' _LOCATION = 'SITE:LOCATION'
_WINDOW_MATERIAL_SIMPLE = 'WINDOWMATERIAL:SIMPLEGLAZINGSYSTEM' _WINDOW_MATERIAL_SIMPLE = 'WINDOWMATERIAL:SIMPLEGLAZINGSYSTEM'
_WINDOW = 'WINDOW' _WINDOW = 'WINDOW'
_ROOFIRRIGATION = 'ROOFIRRIGATION'
_MATERIAL_ROOFVEGETATION = 'MATERIAL:ROOFVEGETATION' _MATERIAL_ROOFVEGETATION = 'MATERIAL:ROOFVEGETATION'
_SIMPLE = 'Simple'
idf_surfaces = { idf_surfaces = {
# todo: make an enum for all the surface types # todo: make an enum for all the surface types
@ -226,9 +226,12 @@ class Idf:
def _add_construction(self, thermal_boundary): def _add_construction(self, thermal_boundary):
for construction in self._idf.idfobjects[self._CONSTRUCTION]: for construction in self._idf.idfobjects[self._CONSTRUCTION]:
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: if construction.Name == thermal_boundary.construction_name:
return return
if thermal_boundary.layers is None: if thermal_boundary.layers is None:
for material in self._idf.idfobjects[self._MATERIAL]: for material in self._idf.idfobjects[self._MATERIAL]:
if material.Name == "DefaultMaterial": if material.Name == "DefaultMaterial":
@ -239,9 +242,15 @@ class Idf:
self._add_material(layer) self._add_material(layer)
layers = thermal_boundary.layers layers = thermal_boundary.layers
# The constructions should have at least one layer # The constructions should have at least one layer
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} _kwargs = {'Name': thermal_boundary.construction_name, 'Outside_Layer': layers[0].material.name}
for i in range(1, len(layers) - 1): for i in range(1, len(layers) - 1):
_kwargs[f'Layer_{i + 1}'] = layers[1].material.name _kwargs[f'Layer_{i + 1}'] = layers[i].material.name
self._idf.newidfobject(self._CONSTRUCTION, **_kwargs) self._idf.newidfobject(self._CONSTRUCTION, **_kwargs)
def _add_window_construction_and_material(self, thermal_opening): def _add_window_construction_and_material(self, thermal_opening):
@ -344,6 +353,8 @@ class Idf:
for thermal_zone in internal_zone.thermal_zones: for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self._add_construction(thermal_boundary) 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: for thermal_opening in thermal_boundary.thermal_openings:
self._add_window_construction_and_material(thermal_opening) self._add_window_construction_and_material(thermal_opening)
usage = thermal_zone.usage usage = thermal_zone.usage
@ -357,7 +368,6 @@ class Idf:
self._add_heating_system(thermal_zone) self._add_heating_system(thermal_zone)
self._add_infiltration(thermal_zone) self._add_infiltration(thermal_zone)
self._add_occupancy(thermal_zone) self._add_occupancy(thermal_zone)
if self._export_type == "Surfaces": if self._export_type == "Surfaces":
self._add_surfaces(building) self._add_surfaces(building)
else: else:
@ -406,10 +416,13 @@ class Idf:
for thermal_zone in internal_zone.thermal_zones: for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries: for boundary in thermal_zone.thermal_boundaries:
idf_surface_type = self.idf_surfaces[boundary.parent_surface.type] 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 = self._idf.newidfobject(self._SURFACE, Name=f'{boundary.parent_surface.name}',
Surface_Type=idf_surface_type, Zone_Name=thermal_zone.id, 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, coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
self._city.lower_corner) self._city.lower_corner)
surface.setcoords(coordinates) surface.setcoords(coordinates)
@ -436,28 +449,43 @@ class Idf:
return True return True
return False return False
def _add_vegetation_material(self, vegetation_layer): def _add_vegetation_material(self, vegetation):
for vegetation_material in self._idf.idfobjects[self._MATERIAL_ROOFVEGETATION]: for vegetation_material in self._idf.idfobjects[self._MATERIAL_ROOFVEGETATION]:
if vegetation_material.Name == vegetation_layer.name: if vegetation_material.Name == vegetation.name:
return 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, self._idf.newidfobject(self._MATERIAL_ROOFVEGETATION,
Name='', Name=vegetation.name,
Height_of_Plants='', Height_of_Plants=height,
Leaf_Area_Index='', Leaf_Area_Index=leaf_area_index,
Leaf_Reflectivity='', Leaf_Reflectivity=leaf_reflectivity,
Leaf_Emissivity='', Leaf_Emissivity=leaf_emissivity,
Minimum_Stomatal_Resistance='', Minimum_Stomatal_Resistance=minimal_stomatal_resistance,
Soil_Layer_Name='', Soil_Layer_Name=soil.name,
Roughness=self._ROUGHNESS, Roughness=soil.roughness,
Thickness='', Thickness=vegetation.soil_thickness,
Conductivity_of_Dry_Soil='', Conductivity_of_Dry_Soil=soil.dry_conductivity,
Density_of_Dry_Soil='', Density_of_Dry_Soil=soil.dry_density,
Specific_Heat_of_Dry_Soil='', Specific_Heat_of_Dry_Soil=soil.dry_specific_heat,
Thermal_Absorptance='', Thermal_Absorptance=soil.thermal_absorptance,
Solar_Absorptance='', Solar_Absorptance=soil.solar_absorptance,
Visible_Absorptance='', Visible_Absorptance=soil.visible_absorptance,
Saturation_Volumetric_Moisture_Content_of_the_Soil_Layer='', Saturation_Volumetric_Moisture_Content_of_the_Soil_Layer=
Residual_Volumetric_Moisture_Content_of_the_Soil_Layer='', soil.saturation_volumetric_moisture_content,
Initial_Volumetric_Moisture_Content_of_the_Soil_Layer='', Residual_Volumetric_Moisture_Content_of_the_Soil_Layer=
Moisture_Diffusion_Calculation_Method='' soil.residual_volumetric_moisture_content,
Initial_Volumetric_Moisture_Content_of_the_Soil_Layer=
soil.initial_volumetric_moisture_content,
Moisture_Diffusion_Calculation_Method=self._SIMPLE
) )

View 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')