diff --git a/catalog_factories/data_models/greenery/content.py b/catalog_factories/data_models/greenery/content.py index b9849d5d..e5160c61 100644 --- a/catalog_factories/data_models/greenery/content.py +++ b/catalog_factories/data_models/greenery/content.py @@ -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 diff --git a/catalog_factories/data_models/greenery/plant.py b/catalog_factories/data_models/greenery/plant.py index c9102387..db7a0d6a 100644 --- a/catalog_factories/data_models/greenery/plant.py +++ b/catalog_factories/data_models/greenery/plant.py @@ -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 diff --git a/catalog_factories/data_models/greenery/plant_percentage.py b/catalog_factories/data_models/greenery/plant_percentage.py index 38819f53..7501e186 100644 --- a/catalog_factories/data_models/greenery/plant_percentage.py +++ b/catalog_factories/data_models/greenery/plant_percentage.py @@ -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 diff --git a/catalog_factories/data_models/greenery/soil.py b/catalog_factories/data_models/greenery/soil.py index d63d11e5..c6e8266b 100644 --- a/catalog_factories/data_models/greenery/soil.py +++ b/catalog_factories/data_models/greenery/soil.py @@ -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 diff --git a/catalog_factories/data_models/greenery/vegetation.py b/catalog_factories/data_models/greenery/vegetation.py index eb234b13..87a80c40 100644 --- a/catalog_factories/data_models/greenery/vegetation.py +++ b/catalog_factories/data_models/greenery/vegetation.py @@ -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 diff --git a/city_model_structure/building_demand/surface.py b/city_model_structure/building_demand/surface.py index 1778354d..8c3e8a1f 100644 --- a/city_model_structure/building_demand/surface.py +++ b/city_model_structure/building_demand/surface.py @@ -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): diff --git a/city_model_structure/building_demand/thermal_boundary.py b/city_model_structure/building_demand/thermal_boundary.py index 5afb36a9..b058f4ff 100644 --- a/city_model_structure/building_demand/thermal_boundary.py +++ b/city_model_structure/building_demand/thermal_boundary.py @@ -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 diff --git a/city_model_structure/building_demand/thermal_zone.py b/city_model_structure/building_demand/thermal_zone.py index 36b6d9c3..c062d3c3 100644 --- a/city_model_structure/building_demand/thermal_zone.py +++ b/city_model_structure/building_demand/thermal_zone.py @@ -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 diff --git a/city_model_structure/greenery/plant.py b/city_model_structure/greenery/plant.py new file mode 100644 index 00000000..8962d8ee --- /dev/null +++ b/city_model_structure/greenery/plant.py @@ -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 diff --git a/city_model_structure/greenery/soil.py b/city_model_structure/greenery/soil.py new file mode 100644 index 00000000..b938d0b2 --- /dev/null +++ b/city_model_structure/greenery/soil.py @@ -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 diff --git a/city_model_structure/greenery/vegetation.py b/city_model_structure/greenery/vegetation.py new file mode 100644 index 00000000..3889b885 --- /dev/null +++ b/city_model_structure/greenery/vegetation.py @@ -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 diff --git a/data/schedules/comnet_archetypes.xlsx b/data/schedules/comnet_archetypes.xlsx deleted file mode 100644 index 8fce488c..00000000 Binary files a/data/schedules/comnet_archetypes.xlsx and /dev/null differ diff --git a/exports/formats/idf.py b/exports/formats/idf.py index c635cb86..6625990b 100644 --- a/exports/formats/idf.py +++ b/exports/formats/idf.py @@ -44,8 +44,8 @@ class Idf: _LOCATION = 'SITE:LOCATION' _WINDOW_MATERIAL_SIMPLE = 'WINDOWMATERIAL:SIMPLEGLAZINGSYSTEM' _WINDOW = 'WINDOW' - _ROOFIRRIGATION = 'ROOFIRRIGATION' _MATERIAL_ROOFVEGETATION = 'MATERIAL:ROOFVEGETATION' + _SIMPLE = 'Simple' idf_surfaces = { # todo: make an enum for all the surface types @@ -226,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": @@ -239,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): @@ -344,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 @@ -357,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: @@ -406,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) @@ -436,28 +449,43 @@ class Idf: return True 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]: - if vegetation_material.Name == vegetation_layer.name: + if vegetation_material.Name == vegetation.name: return - self._idf.newidfobject(self._MATERIAL_ROOFVEGETATION, - Name='', - Height_of_Plants='', - Leaf_Area_Index='', - Leaf_Reflectivity='', - Leaf_Emissivity='', - Minimum_Stomatal_Resistance='', - Soil_Layer_Name='', - Roughness=self._ROUGHNESS, - Thickness='', - Conductivity_of_Dry_Soil='', - Density_of_Dry_Soil='', - Specific_Heat_of_Dry_Soil='', - Thermal_Absorptance='', - Solar_Absorptance='', - Visible_Absorptance='', - Saturation_Volumetric_Moisture_Content_of_the_Soil_Layer='', - Residual_Volumetric_Moisture_Content_of_the_Soil_Layer='', - Initial_Volumetric_Moisture_Content_of_the_Soil_Layer='', - Moisture_Diffusion_Calculation_Method='' - ) + 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 + ) diff --git a/unittests/test_greenery_in_idf.py b/unittests/test_greenery_in_idf.py new file mode 100644 index 00000000..d230356b --- /dev/null +++ b/unittests/test_greenery_in_idf.py @@ -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') +