created customized imports factory and correspondent test

This commit is contained in:
Pilar 2021-10-25 18:05:51 -04:00 committed by guille
parent beec608229
commit 2af8bf5db3
4 changed files with 83 additions and 13 deletions

View File

@ -3,9 +3,11 @@ SanamCustomizedUsageParameters add two parameters to usage properties from ASHRA
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import sys
import sys
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 city_model_structure.building_demand.usage_zone import UsageZone from city_model_structure.building_demand.usage_zone import UsageZone
@ -14,9 +16,17 @@ class SanamCustomizedUsageParameters:
SanamCustomizedUsageParameters class SanamCustomizedUsageParameters class
""" """
def __init__(self, city, base_path): def __init__(self, city, base_path):
super().__init__(base_path, 'ashrae_archetypes.xml') file = 'ashrae_archetypes.xml'
path = str(base_path / file)
self._usage_archetypes = []
with open(path) as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list=('zoneUsageVariant', 'zoneUsageType'))
for zone_usage_type in self._archetypes['buildingUsageLibrary']['zoneUsageType']:
usage = zone_usage_type['id']
usage_archetype = self._parse_zone_usage_type(usage, zone_usage_type)
self._usage_archetypes.append(usage_archetype)
self._city = city self._city = city
self._usage_archetypes = None
def enrich_buildings(self): def enrich_buildings(self):
""" """
@ -25,20 +35,19 @@ class SanamCustomizedUsageParameters:
""" """
city = self._city city = self._city
for building in city.buildings: for building in city.buildings:
archetype = self._search_archetype(building.function) archetype = self._search_archetype(building.function) # todo: building.function or other translation???????
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 '
f'{gh.usage_from_function(building.function)}\n') f'{gh.usage_from_function(building.function)}\n')
continue continue
# todo: what to do with mix-usage usage from gml?
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 thermal_zone in building.thermal_zones:
usage_zone = UsageZone() usage_zone = UsageZone()
usage_zone.volume = thermal_zone.volume
self._assign_values(usage_zone, archetype) self._assign_values(usage_zone, archetype)
usage_zone.volume = thermal_zone.volume
thermal_zone.usage_zones = [usage_zone] thermal_zone.usage_zones = [usage_zone]
def _search_archetype(self, building_usage): def _search_archetype(self, building_usage):
@ -50,6 +59,18 @@ class SanamCustomizedUsageParameters:
@staticmethod @staticmethod
def _assign_values(usage_zone, archetype): def _assign_values(usage_zone, archetype):
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
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
# Therefore, this walk around has been done.
usage_zone.occupancy_density = archetype.occupancy_density usage_zone.occupancy_density = archetype.occupancy_density
# todo: should I use this value: self._min_air_change?? usage_zone.mechanical_air_change = archetype.mechanical_air_change
usage_zone.minimum_ventilation_rate = archetype.minimum_ventilation_rate
@staticmethod
def _parse_zone_usage_type(usage, zone_usage_type):
occupancy_density = None
if 'occupancy' in zone_usage_type:
occupancy_density = zone_usage_type['occupancy']['occupancyDensity']
mechanical_air_change = zone_usage_type['endUses']['ventilation']['minimumVentilationRate']
usage_zone_archetype = huza(usage=usage, occupancy_density=occupancy_density,
mechanical_air_change=mechanical_air_change)
return usage_zone_archetype

View File

@ -11,11 +11,11 @@ class CustomizedImportsFactory:
""" """
CustomizedImportsFactory class CustomizedImportsFactory class
""" """
def __init__(self, city, importer_class, base_path): def __init__(self, importer_class, city, base_path=None):
if base_path is None: if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/customized_imports') base_path = Path(Path(__file__).parent.parent / 'data/customized_imports')
self._city = city
self._importer_class = importer_class self._importer_class = importer_class
self._city = city
self._base_path = base_path self._base_path = base_path
for building in city.buildings: for building in city.buildings:
if len(building.thermal_zones) == 0: if len(building.thermal_zones) == 0:
@ -24,6 +24,8 @@ class CustomizedImportsFactory:
def enrich(self): def enrich(self):
""" """
Enrich the city given to the class using the given importer class Returns the class that will enrich the city given
:return: None :return: Class
""" """
importer = self._importer_class(self._city, self._base_path)
return importer.enrich_buildings()

View File

@ -41,8 +41,8 @@ class CaUsageParameters(HftUsageInterface):
# just one usage_zone # just one usage_zone
for thermal_zone in building.thermal_zones: for thermal_zone in building.thermal_zones:
usage_zone = UsageZone() usage_zone = UsageZone()
usage_zone.volume = thermal_zone.volume
self._assign_values(usage_zone, archetype) self._assign_values(usage_zone, archetype)
usage_zone.volume = thermal_zone.volume
thermal_zone.usage_zones = [usage_zone] thermal_zone.usage_zones = [usage_zone]
def _search_archetype(self, building_usage): def _search_archetype(self, building_usage):

View File

@ -0,0 +1,47 @@
"""
TestCustomizedImportsFactory tests and validates the factory to import customized data
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from pathlib import Path
from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.construction_factory import ConstructionFactory
from imports.customized_imports_factory import CustomizedImportsFactory
from imports.customized_imports.sanam_customized_usage_parameters import SanamCustomizedUsageParameters as scp
class TestCustomizedImportsFactory(TestCase):
"""
TestCustomizedImportsFactory TestCase
"""
def setUp(self) -> None:
"""
Configure test environment
:return:
"""
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
_city = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(_city, 'city is none')
ConstructionFactory('nrel', _city).enrich()
return _city
def test_city_with_customized_data(self):
"""
Enrich the city with the usage information and verify it
:return: None
"""
file = 'one_building_in_kelowna.gml'
city = self._get_citygml(file)
CustomizedImportsFactory(scp, city).enrich()
for building in city.buildings:
self.assertIsNot(len(building.usage_zones), 0, 'no building usage_zones defined')
for usage_zone in building.usage_zones:
self.assertIsNotNone(usage_zone.mechanical_air_change, 'usage is none')