forked from s_ranjbar/city_retrofit
Partial correction of merge function
This commit is contained in:
parent
bd23185ca3
commit
eae26f6388
|
@ -41,7 +41,7 @@ class Building(CityObject):
|
||||||
self._roof_type = None
|
self._roof_type = None
|
||||||
self._internal_zones = None
|
self._internal_zones = None
|
||||||
self._shell = None
|
self._shell = None
|
||||||
self._aliases = None
|
self._aliases = []
|
||||||
self._type = 'building'
|
self._type = 'building'
|
||||||
self._cold_water_temperature = {}
|
self._cold_water_temperature = {}
|
||||||
self._heating_demand = {}
|
self._heating_demand = {}
|
||||||
|
@ -486,10 +486,7 @@ class Building(CityObject):
|
||||||
"""
|
"""
|
||||||
Add a new alias for the building
|
Add a new alias for the building
|
||||||
"""
|
"""
|
||||||
if self._aliases is None:
|
self._aliases.append(value)
|
||||||
self._aliases = [value]
|
|
||||||
else:
|
|
||||||
self._aliases.append(value)
|
|
||||||
if self.city is not None:
|
if self.city is not None:
|
||||||
self.city.add_building_alias(self, value)
|
self.city.add_building_alias(self, value)
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ from hub.city_model_structure.level_of_detail import LevelOfDetail
|
||||||
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
||||||
from hub.helpers.geometry_helper import GeometryHelper
|
from hub.helpers.geometry_helper import GeometryHelper
|
||||||
from hub.helpers.location import Location
|
from hub.helpers.location import Location
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class City:
|
class City:
|
||||||
|
@ -55,9 +56,7 @@ class City:
|
||||||
self._city_objects = None
|
self._city_objects = None
|
||||||
self._energy_systems = None
|
self._energy_systems = None
|
||||||
self._fuels = None
|
self._fuels = None
|
||||||
self._machines = None
|
|
||||||
self._stations = []
|
self._stations = []
|
||||||
self._lca_materials = None
|
|
||||||
self._level_of_detail = LevelOfDetail()
|
self._level_of_detail = LevelOfDetail()
|
||||||
self._city_objects_dictionary = {}
|
self._city_objects_dictionary = {}
|
||||||
self._city_objects_alias_dictionary = {}
|
self._city_objects_alias_dictionary = {}
|
||||||
|
@ -462,7 +461,26 @@ class City:
|
||||||
Return a merged city combining the current city and the given one
|
Return a merged city combining the current city and the given one
|
||||||
:return: City
|
:return: City
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('This method needs to be reimplemented')
|
merged_city = self.copy
|
||||||
|
for building in city.buildings:
|
||||||
|
if merged_city.city_object(building.name) is None:
|
||||||
|
# building is new so added to the city
|
||||||
|
merged_city.add_city_object(copy.deepcopy(building))
|
||||||
|
else:
|
||||||
|
# keep the one with less radiation
|
||||||
|
parameter_city_building_total_radiation = 0
|
||||||
|
for surface in building.surfaces:
|
||||||
|
if surface.global_irradiance:
|
||||||
|
parameter_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
||||||
|
merged_city_building_total_radiation = 0
|
||||||
|
for surface in merged_city.city_object(building.name).surfaces:
|
||||||
|
if surface.global_irradiance:
|
||||||
|
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
||||||
|
if merged_city_building_total_radiation < parameter_city_building_total_radiation:
|
||||||
|
merged_city.remove_city_object(merged_city.city_object(building.name))
|
||||||
|
merged_city.add_city_object(building)
|
||||||
|
|
||||||
|
return merged_city
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def level_of_detail(self) -> LevelOfDetail:
|
def level_of_detail(self) -> LevelOfDetail:
|
||||||
|
|
|
@ -451,10 +451,6 @@ class Idf:
|
||||||
if zone.Name == f'{zone_name}_infiltration':
|
if zone.Name == f'{zone_name}_infiltration':
|
||||||
return
|
return
|
||||||
schedule = f'Infiltration schedules {thermal_zone.usage_name}'
|
schedule = f'Infiltration schedules {thermal_zone.usage_name}'
|
||||||
# todo: if the schedule doesn't exist, does the idf notices??
|
|
||||||
# We shouldn't check this because the schedules could be written later
|
|
||||||
# if schedule not in self._idf.idfobjects[self._COMPACT_SCHEDULE]:
|
|
||||||
# return
|
|
||||||
self._idf.newidfobject(self._INFILTRATION,
|
self._idf.newidfobject(self._INFILTRATION,
|
||||||
Name=f'{zone_name}_infiltration',
|
Name=f'{zone_name}_infiltration',
|
||||||
Zone_or_ZoneList_Name=zone_name,
|
Zone_or_ZoneList_Name=zone_name,
|
||||||
|
@ -468,10 +464,6 @@ class Idf:
|
||||||
if zone.Name == f'{zone_name}_ventilation':
|
if zone.Name == f'{zone_name}_ventilation':
|
||||||
return
|
return
|
||||||
schedule = f'Ventilation schedules {thermal_zone.usage_name}'
|
schedule = f'Ventilation schedules {thermal_zone.usage_name}'
|
||||||
# todo: if the schedule doesn't exist, does the idf notices??
|
|
||||||
# We shouldn't check this because the schedules could be written later
|
|
||||||
# if schedule not in self._idf.idfobjects[self._COMPACT_SCHEDULE]:
|
|
||||||
# return
|
|
||||||
self._idf.newidfobject(self._VENTILATION,
|
self._idf.newidfobject(self._VENTILATION,
|
||||||
Name=f'{zone_name}_ventilation',
|
Name=f'{zone_name}_ventilation',
|
||||||
Zone_or_ZoneList_Name=zone_name,
|
Zone_or_ZoneList_Name=zone_name,
|
||||||
|
|
|
@ -17,11 +17,7 @@ class ExportsFactory:
|
||||||
"""
|
"""
|
||||||
Exports factory class
|
Exports factory class
|
||||||
"""
|
"""
|
||||||
def __init__(self, handler, city, path,
|
def __init__(self, handler, city, path,target_buildings=None,adjacent_buildings=None):
|
||||||
target_buildings=None,
|
|
||||||
adjacent_buildings=None,
|
|
||||||
weather_file=None,
|
|
||||||
weather_format=None):
|
|
||||||
self._city = city
|
self._city = city
|
||||||
self._handler = '_' + handler.lower()
|
self._handler = '_' + handler.lower()
|
||||||
validate_import_export_type(ExportsFactory, handler)
|
validate_import_export_type(ExportsFactory, handler)
|
||||||
|
@ -30,8 +26,6 @@ class ExportsFactory:
|
||||||
self._path = path
|
self._path = path
|
||||||
self._target_buildings = target_buildings
|
self._target_buildings = target_buildings
|
||||||
self._adjacent_buildings = adjacent_buildings
|
self._adjacent_buildings = adjacent_buildings
|
||||||
self._weather_file = weather_file
|
|
||||||
self._weather_format = weather_format
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _citygml(self):
|
def _citygml(self):
|
||||||
|
@ -69,8 +63,6 @@ class ExportsFactory:
|
||||||
"""
|
"""
|
||||||
return SimplifiedRadiosityAlgorithm(self._city,
|
return SimplifiedRadiosityAlgorithm(self._city,
|
||||||
(self._path / f'{self._city.name}_sra.xml'),
|
(self._path / f'{self._city.name}_sra.xml'),
|
||||||
self._weather_file,
|
|
||||||
self._weather_format,
|
|
||||||
target_buildings=self._target_buildings)
|
target_buildings=self._target_buildings)
|
||||||
|
|
||||||
def export(self):
|
def export(self):
|
||||||
|
|
|
@ -21,8 +21,6 @@ class SimplifiedRadiosityAlgorithm:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
city,
|
city,
|
||||||
file_name,
|
file_name,
|
||||||
weather_file,
|
|
||||||
weather_format,
|
|
||||||
target_buildings=None,
|
target_buildings=None,
|
||||||
begin_month=1,
|
begin_month=1,
|
||||||
begin_day=1,
|
begin_day=1,
|
||||||
|
@ -37,9 +35,6 @@ class SimplifiedRadiosityAlgorithm:
|
||||||
self._city.climate_file = str((Path(file_name).parent / f'{city.name}.cli').resolve())
|
self._city.climate_file = str((Path(file_name).parent / f'{city.name}.cli').resolve())
|
||||||
self._city.climate_reference_city = city.location
|
self._city.climate_reference_city = city.location
|
||||||
self._target_buildings = target_buildings
|
self._target_buildings = target_buildings
|
||||||
self._weather_format = weather_format
|
|
||||||
self._weather_file = weather_file
|
|
||||||
|
|
||||||
self._export()
|
self._export()
|
||||||
|
|
||||||
def _correct_point(self, point):
|
def _correct_point(self, point):
|
||||||
|
@ -56,7 +51,7 @@ class SimplifiedRadiosityAlgorithm:
|
||||||
def _export_sra_cli(self):
|
def _export_sra_cli(self):
|
||||||
file = self._city.climate_file
|
file = self._city.climate_file
|
||||||
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||||
WeatherFactory(self._weather_format, self._city).enrich()
|
WeatherFactory('epw', self._city).enrich()
|
||||||
content = self._city.name + '\n'
|
content = self._city.name + '\n'
|
||||||
content += str(self._city.latitude) + ',' + str(self._city.longitude) + ',0.0,' + str(self._city.time_zone) + '\n'
|
content += str(self._city.latitude) + ',' + str(self._city.longitude) + ',0.0,' + str(self._city.time_zone) + '\n'
|
||||||
content += '\ndm m h G_Dh G_Bn\n'
|
content += '\ndm m h G_Dh G_Bn\n'
|
||||||
|
|
|
@ -4,11 +4,17 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
import copy
|
||||||
|
import distutils.spawn
|
||||||
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from hub.city_model_structure.city import City
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
|
from hub.imports.results_factory import ResultFactory
|
||||||
|
from hub.exports.exports_factory import ExportsFactory
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class TestCityMerge(TestCase):
|
class TestCityMerge(TestCase):
|
||||||
|
@ -24,14 +30,58 @@ class TestCityMerge(TestCase):
|
||||||
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
|
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
|
||||||
self._executable = 'sra'
|
self._executable = 'sra'
|
||||||
|
|
||||||
def _get_citygml(self, file):
|
|
||||||
file_path = (self._example_path / file).resolve()
|
|
||||||
city = GeometryFactory('citygml', path=file_path).city
|
|
||||||
self.assertIsNotNone(city, 'city is none')
|
|
||||||
return city
|
|
||||||
|
|
||||||
def test_merge(self):
|
def test_merge(self):
|
||||||
self.assertTrue(False, 'This test needs to be reimplemented')
|
file_path = Path('./tests_data/test.geojson').resolve()
|
||||||
|
full_city = GeometryFactory('geojson', file_path, height_field='citygml_me').city
|
||||||
|
self.assertEqual(17, len(full_city.buildings), 'Wrong number of buildings')
|
||||||
|
odd_city = City(full_city.lower_corner, full_city.upper_corner, full_city.srs_name)
|
||||||
|
par_city = City(full_city.lower_corner, full_city.upper_corner, full_city.srs_name)
|
||||||
|
for building in full_city.buildings:
|
||||||
|
if int(building.name) % 2 == 0:
|
||||||
|
par_city.add_city_object(copy.deepcopy(building))
|
||||||
|
else:
|
||||||
|
odd_city.add_city_object(copy.deepcopy(building))
|
||||||
|
self.assertEqual(8, len(odd_city.buildings), 'Wrong number of odd buildings')
|
||||||
|
self.assertEqual(9, len(par_city.buildings), 'Wrong number of par buildings')
|
||||||
|
merged_city = odd_city.merge(par_city)
|
||||||
|
self.assertEqual(17, len(merged_city.buildings), 'Wrong number of buildings in merged city')
|
||||||
|
merged_city = par_city.merge(odd_city)
|
||||||
|
self.assertEqual(17, len(merged_city.buildings), 'Wrong number of buildings in merged city')
|
||||||
|
merged_city = full_city.merge(odd_city).merge(par_city)
|
||||||
|
self.assertEqual(17, len(merged_city.buildings), 'Wrong number of buildings in merged city')
|
||||||
|
|
||||||
def test_merge_with_radiation(self):
|
def test_merge_with_radiation(self):
|
||||||
self.assertTrue(False, 'This test needs to be reimplemented')
|
sra = distutils.spawn.find_executable('sra')
|
||||||
|
file_path = Path('./tests_data/test.geojson').resolve()
|
||||||
|
output_path = Path('./tests_outputs/')
|
||||||
|
full_city = GeometryFactory('geojson', file_path, height_field='citygml_me').city
|
||||||
|
par_city = City(full_city.lower_corner, full_city.upper_corner, full_city.srs_name)
|
||||||
|
for building in full_city.buildings:
|
||||||
|
if int(building.name) % 2 == 0:
|
||||||
|
par_city.add_city_object(copy.deepcopy(building))
|
||||||
|
ExportsFactory('sra', full_city, output_path).export()
|
||||||
|
sra_file = str((output_path / f'{full_city.name}_sra.xml').resolve())
|
||||||
|
subprocess.run([sra, sra_file], stdout=subprocess.DEVNULL)
|
||||||
|
ResultFactory('sra', full_city, output_path).enrich()
|
||||||
|
self.assertEqual(17, len(full_city.buildings), 'Wrong number of buildings')
|
||||||
|
merged_city = full_city.merge(par_city)
|
||||||
|
buildings_with_radiation = 0
|
||||||
|
for building in merged_city.buildings:
|
||||||
|
radiation = True
|
||||||
|
for surface in building.surfaces:
|
||||||
|
if not surface.global_irradiance:
|
||||||
|
radiation = False
|
||||||
|
if radiation:
|
||||||
|
buildings_with_radiation += 1
|
||||||
|
self.assertEqual(17, buildings_with_radiation, 'Some buildings have radiation')
|
||||||
|
merged_city = par_city.merge(full_city)
|
||||||
|
buildings_with_radiation = 0
|
||||||
|
for building in merged_city.buildings:
|
||||||
|
radiation = True
|
||||||
|
for surface in building.surfaces:
|
||||||
|
if not surface.global_irradiance:
|
||||||
|
radiation = False
|
||||||
|
if radiation:
|
||||||
|
buildings_with_radiation += 1
|
||||||
|
self.assertEqual(17, buildings_with_radiation, 'Some buildings have radiation')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user