Merge remote-tracking branch 'origin/master'

# Conflicts:
#	city_model_structure/building_demand/usage_zone.py
#	unittests/test_usage_factory.py
This commit is contained in:
Pilar 2022-04-07 16:52:34 -04:00
commit 5e51947d6a
20 changed files with 571 additions and 728 deletions

View File

@ -6,27 +6,27 @@ Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
class Catalog: class Catalog:
""" """
Catalog name Catalogs base class not implemented instance of the Catalog base class, catalogs will inherit from this class.
""" """
@property @property
def names(self): def names(self, category=None):
""" """
Base property to return the catalog entries names Base property to return the catalog entries names
:return: not implemented error :return: Catalog names filter by category if provided
""" """
raise NotImplementedError raise NotImplementedError
def entries(self, category=None): def entries(self, category=None):
""" """
Base property to return the catalog entries Base property to return the catalog entries
:return: not implemented error :return: Catalog content filter by category if provided
""" """
raise NotImplementedError raise NotImplementedError
def get_entry(self, name): def get_entry(self, name):
""" """
Base property to return the catalog entry matching the given name Base property to return the catalog entry matching the given name
:return: not implemented error :return: Catalog entry with the matching name
""" """
raise NotImplementedError raise NotImplementedError

View File

@ -5,8 +5,9 @@ Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
""" """
from pathlib import Path from pathlib import Path
from typing import TypeVar
from catalogs.greenery.greenery_catalog import GreeneryCatalog from catalogs.greenery.greenery_catalog import GreeneryCatalog
Catalog = TypeVar('Catalog')
class GreeneryCatalogFactory: class GreeneryCatalogFactory:
""" """
@ -19,25 +20,17 @@ class GreeneryCatalogFactory:
self._path = base_path self._path = base_path
@property @property
def _nrel(self) -> GreeneryCatalog: def _nrel(self):
""" """
Return a greenery catalog using ecore as datasource Return a greenery catalog based in NREL using ecore as datasource
:return: GreeneryCatalog :return: GreeneryCatalog
""" """
return GreeneryCatalog((self._path / 'ecore_greenery_catalog.xml').resolve()) return GreeneryCatalog((self._path / 'ecore_greenery_catalog.xml').resolve())
@property @property
def catalog(self) -> GreeneryCatalog: def catalog(self) -> Catalog:
""" """
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: Catalog
""" """
return getattr(self, self._file_type, lambda: None) return getattr(self, self._file_type, lambda: None)
@property
def catalog_debug(self) -> GreeneryCatalog:
"""
Enrich the city given to the class using the class given handler
:return: City
"""
return GreeneryCatalog((self._path / 'ecore_greenery_catalog.xml').resolve())

View File

@ -104,7 +104,6 @@ class Polygon:
if module != 0: if module != 0:
angle = abs(np.arcsin(scalar_product / module)) angle = abs(np.arcsin(scalar_product / module))
angle_sum += angle angle_sum += angle
print(angle_sum)
return abs(angle_sum - math.pi*2) < cte.EPSILON return abs(angle_sum - math.pi*2) < cte.EPSILON
def contains_polygon(self, polygon): def contains_polygon(self, polygon):
@ -112,13 +111,10 @@ class Polygon:
Determines if the given polygon is contained by the current polygon Determines if the given polygon is contained by the current polygon
:return: boolean :return: boolean
""" """
print('contains')
for point in polygon.points:
print(point.coordinates, self.contains_point(point))
for point in polygon.points:
if not self.contains_point(point): if not self.contains_point(point):
return False return False
print('Belong!')
return True return True
@property @property

View File

@ -31,6 +31,7 @@ class ThermalOpening:
self._inside_emissivity = None self._inside_emissivity = None
self._alpha_coefficient = None self._alpha_coefficient = None
self._radiative_coefficient = None self._radiative_coefficient = None
self._construction_name = None
@property @property
def id(self): def id(self):
@ -290,3 +291,17 @@ class ThermalOpening:
""" """
if value is not None: if value is not None:
self._radiative_coefficient = float(value) self._radiative_coefficient = float(value)
@property
def construction_name(self):
"""
Get thermal opening construction name
"""
return self._construction_name
@construction_name.setter
def construction_name(self, value):
"""
Set thermal opening construction name
"""
self._construction_name = value

View File

@ -8,8 +8,9 @@ from __future__ import annotations
import sys import sys
import pickle import pickle
import math import math
from typing import List, Union import copy
import pyproj import pyproj
from typing import List, Union
from pyproj import Transformer from pyproj import Transformer
from pathlib import Path from pathlib import Path
@ -18,6 +19,7 @@ from city_model_structure.city_object import CityObject
from city_model_structure.city_objects_cluster import CityObjectsCluster from city_model_structure.city_objects_cluster import CityObjectsCluster
from city_model_structure.buildings_cluster import BuildingsCluster from city_model_structure.buildings_cluster import BuildingsCluster
from city_model_structure.fuel import Fuel from city_model_structure.fuel import Fuel
from city_model_structure.iot.station import Station
from city_model_structure.machine import Machine from city_model_structure.machine import Machine
from city_model_structure.parts_consisting_building import PartsConsistingBuilding from city_model_structure.parts_consisting_building import PartsConsistingBuilding
from city_model_structure.subway_entrance import SubwayEntrance from city_model_structure.subway_entrance import SubwayEntrance
@ -433,3 +435,9 @@ class City:
return lca_material return lca_material
return None return None
@property
def copy(self) -> City:
"""
Get a copy of the current city
"""
return copy.deepcopy(self)

View File

@ -44,6 +44,14 @@ class CityObject:
""" """
return self._name return self._name
@name.setter
def name(self, value):
"""
Set building name
:return: str
"""
self._name = value
@property @property
def lod(self) -> int: def lod(self) -> int:
""" """

View File

@ -1,45 +0,0 @@
"""
Energy Sensor module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import pandas as pd
from city_model_structure.iot.sensor import Sensor
class ConcordiaEnergySensor(Sensor):
"""
Concordia energy sensor.
"""
def __init__(self, name):
super().__init__()
self._name = name
self._interval = 5
self._interval_units = 'minutes'
self._type = 'ConcordiaEnergySensor'
self._units = 'kW'
self._measures = pd.DataFrame(columns=["Date time", "Energy consumption"])
@property
def measures(self) -> pd.DataFrame:
"""
Get sensor measures [yyyy-mm-dd, hh:mm:ss kW]
:return: DataFrame["Date time", "Energy consumption"]
"""
return self._measures
@measures.deleter
def measures(self):
"""
Delete sensor measures
"""
self._measures.drop = None
def add_period(self, measures):
"""
Add or update a period measures to the dataframe
"""
measures = self._measures.append(measures, ignore_index=True)
self._measures = measures.drop_duplicates('Date time', keep='last')

View File

@ -1,45 +0,0 @@
"""
Gas Flow Sensor module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import pandas as pd
from city_model_structure.iot.sensor import Sensor
class ConcordiaGasFlowSensor(Sensor):
"""
Concordia gas flow sensor.
"""
def __init__(self, name):
super().__init__()
self._name = name
self._interval = 5
self._interval_units = 'minutes'
self._type = 'ConcordiaGasFlowSensor'
self._units = 'm3'
self._measures = pd.DataFrame(columns=["Date time", "Gas Flow Cumulative Monthly"])
@property
def measures(self) -> pd.DataFrame:
"""
Get sensor measures [yyyy-mm-dd, hh:mm:ss m3]
:return: DataFrame["Date time", "Gas Flow Cumulative Monthly"]
"""
return self._measures
@measures.deleter
def measures(self):
"""
Delete sensor measures
"""
self._measures.drop = None
def add_period(self, measures):
"""
Add or update a period measures to the dataframe
"""
measures = self._measures.append(measures, ignore_index=True)
self._measures = measures.drop_duplicates('Date time', keep='last')

View File

@ -1,45 +0,0 @@
"""
Temperature Sensor module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import pandas as pd
from city_model_structure.iot.sensor import Sensor
class ConcordiaTemperatureSensor(Sensor):
"""
Concordia temperature sensor.
"""
def __init__(self, name):
super().__init__()
self._name = name
self._interval = 5
self._interval_units = 'minutes'
self._type = 'ConcordiaTemperatureSensor'
self._units = 'Celsius'
self._measures = pd.DataFrame(columns=["Date time", "Temperature"])
@property
def measures(self) -> pd.DataFrame:
"""
Get sensor measures [yyyy-mm-dd, hh:mm:ss Celsius]
:return: DataFrame["Date time", "Temperature"]
"""
return self._measures
@measures.deleter
def measures(self):
"""
Delete sensor measures
"""
self._measures.drop = None
def add_period(self, measures):
"""
Add or update a period measures to the dataframe
"""
measures = self._measures.append(measures, ignore_index=True)
self._measures = measures.drop_duplicates('Date time', keep='last')

View File

@ -5,6 +5,8 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
""" """
from helpers.location import Location from helpers.location import Location
from city_model_structure.iot.sensor_measure import SensorMeasure
from city_model_structure.iot.sensor_type import SensorType
class Sensor: class Sensor:
@ -37,7 +39,7 @@ class Sensor:
self._name = str(value) self._name = str(value)
@property @property
def type(self): def type(self) -> SensorType:
""" """
Get sensor type Get sensor type
:return: str :return: str
@ -69,7 +71,7 @@ class Sensor:
self._location = value self._location = value
@property @property
def measures(self): def measures(self) -> [SensorMeasure]:
""" """
Raises not implemented error Raises not implemented error
""" """

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,8 @@ class ThermalOpeningArchetype:
def __init__(self, conductivity=None, frame_ratio=None, g_value=None, thickness=None, def __init__(self, conductivity=None, frame_ratio=None, g_value=None, thickness=None,
back_side_solar_transmittance_at_normal_incidence=None, back_side_solar_transmittance_at_normal_incidence=None,
front_side_solar_transmittance_at_normal_incidence=None, overall_u_value=None, front_side_solar_transmittance_at_normal_incidence=None, overall_u_value=None,
openable_ratio=None, inside_emissivity=None, alpha_coefficient=None, radiative_coefficient=None): openable_ratio=None, inside_emissivity=None, alpha_coefficient=None, radiative_coefficient=None,
construction_name=None):
self._conductivity = conductivity self._conductivity = conductivity
self._frame_ratio = frame_ratio self._frame_ratio = frame_ratio
self._g_value = g_value self._g_value = g_value
@ -24,6 +25,7 @@ class ThermalOpeningArchetype:
self._inside_emissivity = inside_emissivity self._inside_emissivity = inside_emissivity
self._alpha_coefficient = alpha_coefficient self._alpha_coefficient = alpha_coefficient
self._radiative_coefficient = radiative_coefficient self._radiative_coefficient = radiative_coefficient
self._construction_name = construction_name
@property @property
def conductivity(self): def conductivity(self):
@ -112,3 +114,17 @@ class ThermalOpeningArchetype:
:return: float :return: float
""" """
return self._radiative_coefficient return self._radiative_coefficient
@property
def construction_name(self):
"""
Get thermal opening construction name
"""
return self._construction_name
@construction_name.setter
def construction_name(self, value):
"""
Set thermal opening construction name
"""
self._construction_name = value

View File

@ -109,6 +109,7 @@ class NrelPhysicsInterface:
if 'window' in construction and construction['window'] is not None: if 'window' in construction and construction['window'] is not None:
window_ratio = construction['window_ratio']['#text'] window_ratio = construction['window_ratio']['#text']
w_lib = self._search_construction_type('window', construction['window']) w_lib = self._search_construction_type('window', construction['window'])
window_construction_name = w_lib['@name']
frame_ratio = w_lib['frame_ratio']['#text'] frame_ratio = w_lib['frame_ratio']['#text']
if 'conductivity' in w_lib: if 'conductivity' in w_lib:
conductivity = w_lib['conductivity']['#text'] conductivity = w_lib['conductivity']['#text']
@ -128,7 +129,8 @@ class NrelPhysicsInterface:
thickness=thickness, back_side_solar_transmittance_at_normal_incidence= thickness=thickness, back_side_solar_transmittance_at_normal_incidence=
back_side_solar_transmittance_at_normal_incidence, back_side_solar_transmittance_at_normal_incidence,
front_side_solar_transmittance_at_normal_incidence= front_side_solar_transmittance_at_normal_incidence=
front_side_solar_transmittance_at_normal_incidence) front_side_solar_transmittance_at_normal_incidence,
construction_name=window_construction_name)
else: else:
overall_u_value = w_lib['overall_u_value']['#text'] overall_u_value = w_lib['overall_u_value']['#text']
units = w_lib['overall_u_value']['@units'] units = w_lib['overall_u_value']['@units']

View File

@ -99,6 +99,7 @@ class UsPhysicsParameters(NrelPhysicsInterface):
for thermal_opening in thermal_boundary.thermal_openings: for thermal_opening in thermal_boundary.thermal_openings:
if thermal_boundary_archetype.thermal_opening_archetype is not None: if thermal_boundary_archetype.thermal_opening_archetype is not None:
thermal_opening_archetype = thermal_boundary_archetype.thermal_opening_archetype thermal_opening_archetype = thermal_boundary_archetype.thermal_opening_archetype
thermal_opening.construction_name = thermal_opening_archetype.construction_name
thermal_opening.frame_ratio = thermal_opening_archetype.frame_ratio thermal_opening.frame_ratio = thermal_opening_archetype.frame_ratio
thermal_opening.g_value = thermal_opening_archetype.g_value thermal_opening.g_value = thermal_opening_archetype.g_value
thermal_opening.conductivity = thermal_opening_archetype.conductivity thermal_opening.conductivity = thermal_opening_archetype.conductivity

View File

@ -28,7 +28,7 @@ class ConstructionFactory:
def _nrcan(self): def _nrcan(self):
""" """
Enrich the city by using NRCAN information Enrich the city by using NRCAN information
:alert: NRCAN handler only contains simplified construction information :alert: NRCAN handler only contains simplified construction information (residential)
""" """
CaPhysicsParameters(self._city, self._base_path).enrich_buildings() CaPhysicsParameters(self._city, self._base_path).enrich_buildings()

View File

@ -4,8 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
from numpy import inf from numpy import inf
#from rhino3dm import * from rhino3dm import *
#from rhino3dm._rhino3dm import MeshType from rhino3dm._rhino3dm import MeshType
from city_model_structure.attributes.point import Point from city_model_structure.attributes.point import Point
import numpy as np import numpy as np
@ -14,7 +15,6 @@ from city_model_structure.attributes.polygon import Polygon
from city_model_structure.building import Building from city_model_structure.building import Building
from city_model_structure.city import City from city_model_structure.city import City
from city_model_structure.building_demand.surface import Surface as LibsSurface from city_model_structure.building_demand.surface import Surface as LibsSurface
from helpers.constants import EPSILON
from imports.geometry.helpers.geometry_helper import GeometryHelper from imports.geometry.helpers.geometry_helper import GeometryHelper
@ -29,7 +29,6 @@ class Rhino:
@staticmethod @staticmethod
def _in_perimeter(wall, corner): def _in_perimeter(wall, corner):
res = wall.contains_point(Point(corner)) res = wall.contains_point(Point(corner))
print(f'belong: {res} wall:({wall.coordinates}) corner: ({corner})')
return res return res
@staticmethod @staticmethod
@ -96,7 +95,6 @@ class Rhino:
windows.append(Polygon(surface.perimeter_polygon.inverse)) windows.append(Polygon(surface.perimeter_polygon.inverse))
else: else:
buildings.append(rhino_object) buildings.append(rhino_object)
print(f'windows: {len(windows)}')
# todo: this method will be pretty inefficient # todo: this method will be pretty inefficient
for hole in windows: for hole in windows:
corner = hole.coordinates[0] corner = hole.coordinates[0]

View File

@ -6,7 +6,7 @@ Contributor Mohammad Reza mohammad.seyedabadi@mail.concordia.ca
""" """
import xmltodict import xmltodict
from pathlib import Path from pathlib import Path
from city_model_structure.building_demand.material import Material from city_model_structure.lca_material import LcaMaterial as LMaterial
class LcaMaterial: class LcaMaterial:
def __init__(self, city, base_path): def __init__(self, city, base_path):
@ -15,14 +15,14 @@ class LcaMaterial:
self._lca = None self._lca = None
def enrich(self): def enrich(self):
self._city.materials = [] self._city.lca_materials = []
path = Path(self._base_path / 'lca_data.xml').resolve() path = Path(self._base_path / 'lca_data.xml').resolve()
with open(path) as xml: with open(path) as xml:
self._lca = xmltodict.parse(xml.read()) self._lca = xmltodict.parse(xml.read())
for material in self._lca["library"]["building_materials"]['material']: for material in self._lca["library"]["building_materials"]['material']:
_material = Material() _material = LMaterial()
_material.type = material['@type'] _material.type = material['@type']
_material.id = material['@id'] _material.id = material['@id']
_material.name = material['@name'] _material.name = material['@name']
@ -37,4 +37,4 @@ class LcaMaterial:
_material.cost=material['cost']['#text'] _material.cost=material['cost']['#text']
_material._cost_unit=material['cost']['@unit'] _material._cost_unit=material['cost']['@unit']
self._city.materials.append(_material) self._city.lca_materials.append(_material)

View File

@ -5,9 +5,6 @@ Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
Contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from pathlib import Path from pathlib import Path
from imports.sensors.concordia_energy_consumption import ConcordiaEnergyConsumption
from imports.sensors.concordia_gas_flow import ConcordiaGasFlow
from imports.sensors.concordia_temperature import ConcordiaTemperature
class SensorsFactory: class SensorsFactory:
@ -26,19 +23,19 @@ class SensorsFactory:
""" """
Enrich the city by using concordia energy consumption sensors as data source Enrich the city by using concordia energy consumption sensors as data source
""" """
ConcordiaEnergyConsumption(self._city, self._end_point, self._base_path) raise NotImplementedError('need to be reimplemented')
def _cgf(self): def _cgf(self):
""" """
Enrich the city by using concordia gas flow sensors as data source Enrich the city by using concordia gas flow sensors as data source
""" """
ConcordiaGasFlow(self._city, self._end_point, self._base_path) raise NotImplementedError('need to be reimplemented')
def _ct(self): def _ct(self):
""" """
Enrich the city by using concordia temperature sensors as data source Enrich the city by using concordia temperature sensors as data source
""" """
ConcordiaTemperature(self._city, self._end_point, self._base_path) raise NotImplementedError('need to be reimplemented')
def enrich(self): def enrich(self):
""" """

View File

@ -1,58 +0,0 @@
"""
TestSensorsFactory test and validate the city model structure schedules
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
from unittest import TestCase
from city_model_structure.building import Building
from city_model_structure.buildings_cluster import BuildingsCluster
from city_model_structure.city import City
from imports.sensors_factory import SensorsFactory
class TestSensorsFactory(TestCase):
"""
TestSchedulesFactory TestCase
"""
def setUp(self) -> None:
"""
Configure test environment
:return:
"""
self._city = TestSensorsFactory._mockup_city()
self._end_point = (Path(__file__).parent /
'tests_data/EV-GM energy demand weekly report_01-26-20_04-30.csv').resolve()
@staticmethod
def _mockup_city():
lower_corner = [0, 0, 0]
upper_corner = [10, 10, 10]
srs_name = 'Mockup_city'
buildings = []
lod = 2
surfaces = []
year_of_construction = 2021
function = "office"
city = City(lower_corner, upper_corner, srs_name)
buildings.append(Building("EV", lod, surfaces, year_of_construction, function, lower_corner))
buildings.append(Building("GM", lod, surfaces, year_of_construction, function, lower_corner))
buildings.append(Building("MB", lod, surfaces, year_of_construction, function, lower_corner))
for building in buildings:
city.add_city_object(building)
buildings_cluster = BuildingsCluster("GM_MB_EV", buildings)
city.add_city_objects_cluster(buildings_cluster)
return city
def test_city_with_sensors(self):
"""
Load concordia sensors and verify it
"""
SensorsFactory('cec', self._city, self._end_point).enrich()
SensorsFactory('cgf', self._city, self._end_point).enrich()
SensorsFactory('ct', self._city, self._end_point).enrich()
for city_object in self._city.city_objects:
print(city_object.name, len(city_object.sensors))
for sensor in city_object.sensors:
print(sensor.name)