created customized imports factory and correspondent test

This commit is contained in:
Pilar 2021-11-05 10:16:35 -04:00 committed by guille
parent 2af8bf5db3
commit 3adf8c9604
9 changed files with 116 additions and 51 deletions

View File

@ -174,6 +174,8 @@ class Building(CityObject):
:return: [ThermalZone] :return: [ThermalZone]
""" """
if len(self._thermal_zones) == 0: if len(self._thermal_zones) == 0:
if self.storeys is None:
return []
for storey in self.storeys: for storey in self.storeys:
self._thermal_zones.append(storey.thermal_zone) self._thermal_zones.append(storey.thermal_zone)
return self._thermal_zones return self._thermal_zones
@ -194,6 +196,15 @@ class Building(CityObject):
""" """
return self._year_of_construction return self._year_of_construction
@year_of_construction.setter
def year_of_construction(self, value):
"""
Set building year of construction
:param value: int
"""
if value is not None:
self._year_of_construction = value
@property @property
def function(self) -> Union[None, str]: def function(self) -> Union[None, str]:
""" """

View File

@ -5,99 +5,99 @@
<zoneUsageType> <zoneUsageType>
<id>assembly</id> <id>assembly</id>
<occupancy> <occupancy>
<occupancyDensity>0.15</occupancyDensity> <occupancyDensity units="persons/m2">0.15</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>5</minimumVentilationRate> <minimumVentilationRate units="cfm/person">5</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>health</id> <id>health</id>
<occupancy> <occupancy>
<occupancyDensity>0.1</occupancyDensity> <occupancyDensity units="persons/m2">0.1</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>20</minimumVentilationRate> <minimumVentilationRate units="cfm/person">20</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>hotel</id> <id>hotel</id>
<occupancy> <occupancy>
<occupancyDensity>0.11</occupancyDensity> <occupancyDensity units="persons/m2">0.11</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>5</minimumVentilationRate> <minimumVentilationRate units="cfm/person">5</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>manufacturing</id> <id>manufacturing</id>
<occupancy> <occupancy>
<occupancyDensity>0.07</occupancyDensity> <occupancyDensity units="persons/m2">0.07</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>10</minimumVentilationRate> <minimumVentilationRate units="cfm/person">10</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>office</id> <id>office</id>
<occupancy> <occupancy>
<occupancyDensity>0.05</occupancyDensity> <occupancyDensity units="persons/m2">0.05</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>5</minimumVentilationRate> <minimumVentilationRate units="cfm/person">5</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>restaurant</id> <id>restaurant</id>
<occupancy> <occupancy>
<occupancyDensity>0.7</occupancyDensity> <occupancyDensity units="persons/m2">0.7</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>7.5</minimumVentilationRate> <minimumVentilationRate units="cfm/person">7.5</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>retail</id> <id>retail</id>
<occupancy> <occupancy>
<occupancyDensity>0.2</occupancyDensity> <occupancyDensity units="persons/m2">0.2</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>7.5</minimumVentilationRate> <minimumVentilationRate units="cfm/person">7.5</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>school</id> <id>school</id>
<occupancy> <occupancy>
<occupancyDensity>0.25</occupancyDensity> <occupancyDensity units="persons/m2">0.25</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>10</minimumVentilationRate> <minimumVentilationRate units="cfm/person">10</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>lab</id> <id>lab</id>
<occupancy> <occupancy>
<occupancyDensity>0.25</occupancyDensity> <occupancyDensity units="persons/m2">0.25</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>10</minimumVentilationRate> <minimumVentilationRate units="cfm/person">10</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
@ -105,18 +105,18 @@
<id>residential</id> <id>residential</id>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>5</minimumVentilationRate> <minimumVentilationRate units="cfm/person">5</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>
<zoneUsageType> <zoneUsageType>
<id>gymnasium</id> <id>gymnasium</id>
<occupancy> <occupancy>
<occupancyDensity>0.3</occupancyDensity> <occupancyDensity units="persons/m2">0.3</occupancyDensity>
</occupancy> </occupancy>
<endUses> <endUses>
<ventilation> <ventilation>
<minimumVentilationRate>7.5</minimumVentilationRate> <minimumVentilationRate units="cfm/person">7.5</minimumVentilationRate>
</ventilation> </ventilation>
</endUses> </endUses>
</zoneUsageType> </zoneUsageType>

View File

@ -7,6 +7,10 @@ Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.mons
# universal constants # universal constants
KELVIN = 273.15 KELVIN = 273.15
# converters
HOUR_TO_MINUTES = 60
METERS_TO_FEET = 3.28084
# time # time
SECOND = 'second' SECOND = 'second'
MINUTE = 'minute' MINUTE = 'minute'

View File

@ -55,10 +55,13 @@ class EnrichCity:
def _construction(self, construction_format): def _construction(self, construction_format):
ConstructionFactory(construction_format, self._city).enrich() ConstructionFactory(construction_format, self._city).enrich()
for building in self._city.buildings: for building in self._city.buildings:
# infiltration_rate_system_off is a mandatory parameter. # infiltration_rate_system_off is a mandatory parameter.
# If it is not returned, extract the building from the calculation list # If it is not returned, extract the building from the calculation list
if building.thermal_zones[0].infiltration_rate_system_off is None: if len(building.thermal_zones) == 0:
self._city.remove_city_object(building)
elif building.thermal_zones[0].infiltration_rate_system_off is None:
self._city.remove_city_object(building) self._city.remove_city_object(building)
if self._city.buildings is None: if self._city.buildings is None:
self._errors.append('no archetype found per construction') self._errors.append('no archetype found per construction')

View File

@ -31,6 +31,7 @@ class UsPhysicsParameters(NrelPhysicsInterface):
# it is assumed that all buildings have the same archetypes' keys # it is assumed that all buildings have the same archetypes' keys
for building in city.buildings: for building in city.buildings:
building_type = ConstructionHelper.nrel_from_function(building.function) building_type = ConstructionHelper.nrel_from_function(building.function)
print(building_type)
if building_type is None: if building_type is None:
return return
archetype = self._search_archetype(building_type, archetype = self._search_archetype(building_type,

View File

@ -0,0 +1,38 @@
"""
Sanam's customized importer Usage helper
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import sys
import helpers.constants as cte
class SanamCustomizedUsageHelper:
"""
SanamCustomizedUsage class
"""
usage_to_customized = {
cte.RESIDENTIAL: 'residential',
cte.INDUSTRY: 'manufacturing',
cte.OFFICE_ADMINISTRATION: 'office',
cte.HOTEL: 'hotel',
cte.HEALTH_CARE: 'health',
cte.RETAIL: 'retail',
cte.HALL: 'assembly',
cte.RESTAURANT: 'restaurant',
cte.EDUCATION: 'school'
}
customized_default_value = 'residential'
@staticmethod
def customized_from_usage(usage):
"""
Get customized usage from the given internal usage key
:param usage: str
:return: str
"""
try:
return SanamCustomizedUsageHelper.usage_to_customized[usage]
except KeyError:
sys.stderr.write('Error: keyword not found. Returned default HfT usage "residential"\n')
return SanamCustomizedUsageHelper.customized_default_value

View File

@ -8,7 +8,7 @@ import sys
import xmltodict import xmltodict
from imports.geometry.helpers.geometry_helper import GeometryHelper as gh from imports.geometry.helpers.geometry_helper import GeometryHelper as gh
from imports.usage.data_classes.hft_usage_zone_archetype import HftUsageZoneArchetype as huza from imports.usage.data_classes.hft_usage_zone_archetype import HftUsageZoneArchetype as huza
from city_model_structure.building_demand.usage_zone import UsageZone import helpers.constants as cte
class SanamCustomizedUsageParameters: class SanamCustomizedUsageParameters:
@ -36,6 +36,11 @@ class SanamCustomizedUsageParameters:
city = self._city city = self._city
for building in city.buildings: for building in city.buildings:
archetype = self._search_archetype(building.function) # todo: building.function or other translation??????? archetype = self._search_archetype(building.function) # todo: building.function or other translation???????
height = building.average_storey_height
if height is None:
raise Exception('Average storey height not defined, ACH cannot be calculated')
if height <= 0:
raise Exception('Average storey height is zero, ACH cannot be calculated')
if archetype is None: if archetype is None:
sys.stderr.write(f'Building {building.name} has unknown archetype for building function:' sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
f' {building.function}, that assigns building usage as ' f' {building.function}, that assigns building usage as '
@ -44,11 +49,8 @@ class SanamCustomizedUsageParameters:
mix_usage = False mix_usage = False
if not mix_usage: if not mix_usage:
# just one usage_zone # just one usage_zone
for thermal_zone in building.thermal_zones: for usage_zone in building.usage_zones:
usage_zone = UsageZone() self._assign_values(usage_zone, archetype, height)
self._assign_values(usage_zone, archetype)
usage_zone.volume = thermal_zone.volume
thermal_zone.usage_zones = [usage_zone]
def _search_archetype(self, building_usage): def _search_archetype(self, building_usage):
for building_archetype in self._usage_archetypes: for building_archetype in self._usage_archetypes:
@ -57,20 +59,24 @@ class SanamCustomizedUsageParameters:
return None return None
@staticmethod @staticmethod
def _assign_values(usage_zone, archetype): def _assign_values(usage_zone, archetype, height):
usage_zone.usage = archetype.usage usage_zone.usage = archetype.usage
# Due to the fact that python is not a typed language, the wrong object type is assigned to # Due to the fact that python is not a typed language, the wrong object type is assigned to
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains. # usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
# Therefore, this walk around has been done. # Therefore, this walk around has been done.
if archetype.occupancy_density is not None:
usage_zone.occupancy_density = archetype.occupancy_density usage_zone.occupancy_density = archetype.occupancy_density
usage_zone.mechanical_air_change = archetype.mechanical_air_change archetype_mechanical_air_change = float(archetype.mechanical_air_change) * float(usage_zone.occupancy_density) \
* cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET**3 / height
usage_zone.mechanical_air_change = archetype_mechanical_air_change
@staticmethod @staticmethod
def _parse_zone_usage_type(usage, zone_usage_type): def _parse_zone_usage_type(usage, zone_usage_type):
occupancy_density = None mechanical_air_change = zone_usage_type['endUses']['ventilation']['minimumVentilationRate']['#text']
if 'occupancy' in zone_usage_type: if 'occupancy' in zone_usage_type:
occupancy_density = zone_usage_type['occupancy']['occupancyDensity'] occupancy_density = zone_usage_type['occupancy']['occupancyDensity']['#text']
mechanical_air_change = zone_usage_type['endUses']['ventilation']['minimumVentilationRate']
usage_zone_archetype = huza(usage=usage, occupancy_density=occupancy_density, usage_zone_archetype = huza(usage=usage, occupancy_density=occupancy_density,
mechanical_air_change=mechanical_air_change) mechanical_air_change=mechanical_air_change)
else:
usage_zone_archetype = huza(usage=usage, mechanical_air_change=mechanical_air_change)
return usage_zone_archetype return usage_zone_archetype

View File

@ -8,7 +8,7 @@ from city_model_structure.city import City
from imports.geometry.citygml import CityGml from imports.geometry.citygml import CityGml
from imports.geometry.obj import Obj from imports.geometry.obj import Obj
from imports.geometry.osm_subway import OsmSubway from imports.geometry.osm_subway import OsmSubway
from imports.geometry.rhino import Rhino #from imports.geometry.rhino import Rhino
class GeometryFactory: class GeometryFactory:
@ -43,13 +43,13 @@ class GeometryFactory:
""" """
return OsmSubway(self._path).city return OsmSubway(self._path).city
@property # @property
def _rhino(self) -> City: # def _rhino(self) -> City:
""" # """
Enrich the city by using OpenStreetMap information as data source # Enrich the city by using OpenStreetMap information as data source
:return: City # :return: City
""" # """
return Rhino(self._path).city # return Rhino(self._path).city
@property @property
def city(self) -> City: def city(self) -> City:
@ -59,10 +59,10 @@ class GeometryFactory:
""" """
return getattr(self, self._file_type, lambda: None) return getattr(self, self._file_type, lambda: None)
@property # @property
def city_debug(self) -> City: # def city_debug(self) -> City:
""" # """
Enrich the city given to the class using the class given handler # Enrich the city given to the class using the class given handler
:return: City # :return: City
""" # """
return Rhino(self._path).city # return Rhino(self._path).city

View File

@ -8,6 +8,7 @@ from unittest import TestCase
from imports.geometry_factory import GeometryFactory from imports.geometry_factory import GeometryFactory
from imports.construction_factory import ConstructionFactory from imports.construction_factory import ConstructionFactory
from imports.usage_factory import UsageFactory
from imports.customized_imports_factory import CustomizedImportsFactory from imports.customized_imports_factory import CustomizedImportsFactory
from imports.customized_imports.sanam_customized_usage_parameters import SanamCustomizedUsageParameters as scp from imports.customized_imports.sanam_customized_usage_parameters import SanamCustomizedUsageParameters as scp
@ -28,6 +29,7 @@ class TestCustomizedImportsFactory(TestCase):
_city = GeometryFactory('citygml', file_path).city _city = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(_city, 'city is none') self.assertIsNotNone(_city, 'city is none')
ConstructionFactory('nrel', _city).enrich() ConstructionFactory('nrel', _city).enrich()
UsageFactory('hft', _city).enrich()
return _city return _city