diff --git a/city_model_structure/attributes/edge.py b/city_model_structure/attributes/edge.py
index 2235f096..3a156ed8 100644
--- a/city_model_structure/attributes/edge.py
+++ b/city_model_structure/attributes/edge.py
@@ -1,7 +1,7 @@
"""
Node module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
"""
import uuid
diff --git a/city_model_structure/attributes/node.py b/city_model_structure/attributes/node.py
index 65e769fd..86e6b514 100644
--- a/city_model_structure/attributes/node.py
+++ b/city_model_structure/attributes/node.py
@@ -1,13 +1,13 @@
"""
Node module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
"""
import uuid
from typing import List, TypeVar
-
+from city_model_structure.attributes.time_series import TimeSeries
Edge = TypeVar('Edge')
@@ -21,6 +21,7 @@ class Node:
self._name = name
self._id = None
self._edges = edges
+ self._time_series = None
@property
def name(self):
@@ -43,7 +44,15 @@ class Node:
@property
def edges(self) -> List[Edge]:
"""
- get edges delimited by the node
+ Get edges delimited by the node
:return: [Edge]
"""
return self._edges
+
+ @property
+ def time_series(self) -> TimeSeries:
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._time_series
diff --git a/city_model_structure/attributes/record.py b/city_model_structure/attributes/record.py
new file mode 100644
index 00000000..e7261ddb
--- /dev/null
+++ b/city_model_structure/attributes/record.py
@@ -0,0 +1,40 @@
+"""
+Record module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+
+class Record:
+ """
+ Record class
+ """
+
+ def __init__(self, time=None, value=None, flag=None):
+ self._time = time
+ self._value = value
+ self._flag = flag
+
+ @property
+ def time(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._time
+
+ @property
+ def value(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._value
+
+ @property
+ def flag(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._flag
diff --git a/city_model_structure/attributes/time_series.py b/city_model_structure/attributes/time_series.py
new file mode 100644
index 00000000..20c4d5dd
--- /dev/null
+++ b/city_model_structure/attributes/time_series.py
@@ -0,0 +1,34 @@
+"""
+Time series module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from typing import List
+from city_model_structure.attributes.record import Record
+
+
+class TimeSeries:
+ """
+ TimeSeries class
+ """
+
+ def __init__(self, time_series_type=None, records=None):
+ self._time_series_type = time_series_type
+ self._records = records
+
+ @property
+ def time_series_type(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._time_series_type
+
+ @property
+ def records(self) -> List[Record]:
+ """
+ Add explanation here
+ :return: List[Record]
+ """
+ return self._records
diff --git a/city_model_structure/building.py b/city_model_structure/building.py
index 9e144141..423d5ab8 100644
--- a/city_model_structure/building.py
+++ b/city_model_structure/building.py
@@ -174,6 +174,8 @@ class Building(CityObject):
:return: [ThermalZone]
"""
if len(self._thermal_zones) == 0:
+ if self.storeys is None:
+ return []
for storey in self.storeys:
self._thermal_zones.append(storey.thermal_zone)
return self._thermal_zones
@@ -194,6 +196,15 @@ class Building(CityObject):
"""
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
def function(self) -> Union[None, str]:
"""
diff --git a/city_model_structure/building_demand/internal_gains.py b/city_model_structure/building_demand/internal_gains.py
index d2342a98..75e60cb7 100644
--- a/city_model_structure/building_demand/internal_gains.py
+++ b/city_model_structure/building_demand/internal_gains.py
@@ -13,11 +13,29 @@ class InternalGains:
"""
def __init__(self):
+ self._type = None
self._average_internal_gain = None
self._convective_fraction = None
self._radiative_fraction = None
self._latent_fraction = None
+ @property
+ def type(self) -> Union[None, str]:
+ """
+ Get internal gains type
+ :return: None or string
+ """
+ return self._type
+
+ @type.setter
+ def type(self, value):
+ """
+ Set internal gains type
+ :param value: string
+ """
+ if value is not None:
+ self._type = str(value)
+
@property
def average_internal_gain(self) -> Union[None, float]:
"""
@@ -30,7 +48,7 @@ class InternalGains:
def average_internal_gain(self, value):
"""
Set internal gains average internal gain in W/m2
- :param value:float
+ :param value: float
"""
if value is not None:
self._average_internal_gain = float(value)
diff --git a/city_model_structure/bus_system.py b/city_model_structure/bus_system.py
new file mode 100644
index 00000000..c254a55e
--- /dev/null
+++ b/city_model_structure/bus_system.py
@@ -0,0 +1,56 @@
+"""
+Bus system module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from typing import List
+from city_model_structure.city_object import CityObject
+from city_model_structure.attributes.polygon import Polygon
+from city_model_structure.transport.bus_network import BusNetwork
+from city_model_structure.transport.bus_node import BusNode
+from city_model_structure.transport.bus import Bus
+
+
+class BusSystem(CityObject):
+ """
+ BusSystem(CityObject) class
+ """
+ def __init__(self, name, lod, surfaces, city_lower_corner):
+ super().__init__(name, lod, surfaces, city_lower_corner)
+ self._bus_routes = None
+ self._bus_network = None
+ self._buses = None
+ self._restricted_polygons = None
+
+ @property
+ def bus_routes(self) -> List[BusNode]:
+ """
+ Add explanation here
+ :return: [BusNode]
+ """
+ return self._bus_routes
+
+ @property
+ def bus_network(self) -> BusNetwork:
+ """
+ Add explanation here
+ :return: BusNetwork
+ """
+ return self._bus_network
+
+ @property
+ def buses(self) -> List[Bus]:
+ """
+ Add explanation here
+ :return: [Bus]
+ """
+ return self._buses
+
+ @property
+ def restricted_polygons(self) -> List[Polygon]:
+ """
+ Add explanation here
+ :return: [Polygon]
+ """
+ return self._restricted_polygons
diff --git a/city_model_structure/city.py b/city_model_structure/city.py
index 9f6b0e0a..9465f368 100644
--- a/city_model_structure/city.py
+++ b/city_model_structure/city.py
@@ -2,7 +2,6 @@
City module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
-Contributor Peter Yefi peteryefi@gmail.com
"""
from __future__ import annotations
import sys
@@ -19,361 +18,372 @@ from city_model_structure.city_objects_cluster import CityObjectsCluster
from city_model_structure.buildings_cluster import BuildingsCluster
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
from city_model_structure.subway_entrance import SubwayEntrance
+from city_model_structure.fuel import Fuel
from helpers.geometry_helper import GeometryHelper
from helpers.location import Location
from city_model_structure.energy_system import EnergySystem
class City:
- """
+ """
City class
"""
- def __init__(self, lower_corner, upper_corner, srs_name):
- self._name = None
- self._lower_corner = lower_corner
- self._upper_corner = upper_corner
- self._buildings = None
- self._subway_entrances = None
- self._srs_name = srs_name
- self._geometry = GeometryHelper()
- # todo: right now extracted at city level, in the future should be extracted also at building level if exist
- self._location = None
- self._country_code = None
- self._climate_reference_city = None
- self._climate_file = None
- self._latitude = None
- self._longitude = None
- self._time_zone = None
- self._buildings_clusters = None
- self._parts_consisting_buildings = None
- self._city_objects_clusters = None
- self._city_objects = None
- self._energy_systems = None
+ def __init__(self, lower_corner, upper_corner, srs_name):
+ self._name = None
+ self._lower_corner = lower_corner
+ self._upper_corner = upper_corner
+ self._buildings = None
+ self._subway_entrances = None
+ self._srs_name = srs_name
+ self._geometry = GeometryHelper()
+ # todo: right now extracted at city level, in the future should be extracted also at building level if exist
+ self._location = None
+ self._country_code = None
+ self._climate_reference_city = None
+ self._climate_file = None
+ self._latitude = None
+ self._longitude = None
+ self._time_zone = None
+ self._buildings_clusters = None
+ self._parts_consisting_buildings = None
+ self._city_objects_clusters = None
+ self._city_objects = None
+ self._energy_systems = None
+ self._fuels = None
- def _get_location(self) -> Location:
- if self._location is None:
- gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
- try:
- input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data
- except pyproj.exceptions.CRSError:
- sys.stderr.write('Invalid projection reference system, please check the input data. '
- '(e.g. in CityGML files: srs_name)\n')
- sys.exit()
- transformer = Transformer.from_crs(input_reference, gps)
- coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1])
- self._location = GeometryHelper.get_location(coordinates[0], coordinates[1])
- return self._location
+ @property
+ def fuels(self) -> [Fuel]:
+ return self._fuels
- @property
- def country_code(self):
- """
+ @fuels.setter
+ def fuels(self, value):
+ self._fuels = value
+
+
+ def _get_location(self) -> Location:
+ if self._location is None:
+ gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
+ try:
+ input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data
+ except pyproj.exceptions.CRSError:
+ sys.stderr.write('Invalid projection reference system, please check the input data. '
+ '(e.g. in CityGML files: srs_name)\n')
+ sys.exit()
+ transformer = Transformer.from_crs(input_reference, gps)
+ coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1])
+ self._location = GeometryHelper.get_location(coordinates[0], coordinates[1])
+ return self._location
+
+ @property
+ def country_code(self):
+ """
Get city country code
:return: str
"""
- return self._get_location().country
+ return self._get_location().country
- @property
- def name(self):
- """
+ @property
+ def name(self):
+ """
Get city name
:return: str
"""
- return self._get_location().city
+ return self._get_location().city
- @property
- def climate_reference_city(self) -> Union[None, str]:
- """
+ @property
+ def climate_reference_city(self) -> Union[None, str]:
+ """
Get the name for the climatic information reference city
:return: None or str
"""
- return self._climate_reference_city
+ return self._climate_reference_city
- @climate_reference_city.setter
- def climate_reference_city(self, value):
- """
+ @climate_reference_city.setter
+ def climate_reference_city(self, value):
+ """
Set the name for the climatic information reference city
:param value: str
"""
- if value is not None:
- self._climate_reference_city = str(value)
+ if value is not None:
+ self._climate_reference_city = str(value)
- @property
- def climate_file(self) -> Union[None, Path]:
- """
+ @property
+ def climate_file(self) -> Union[None, Path]:
+ """
Get the climate file full path
:return: None or Path
"""
- return self._climate_file
+ return self._climate_file
- @climate_file.setter
- def climate_file(self, value):
- """
+ @climate_file.setter
+ def climate_file(self, value):
+ """
Set the climate file full path
:param value: Path
"""
- if value is not None:
- self._climate_file = Path(value)
+ if value is not None:
+ self._climate_file = Path(value)
- @property
- def city_objects(self) -> Union[List[CityObject], None]:
- """
+ @property
+ def city_objects(self) -> Union[List[CityObject], None]:
+ """
Get the city objects belonging to the city
:return: None or [CityObject]
"""
- if self._city_objects is None:
- if self.city_objects_clusters is None:
- self._city_objects = []
- else:
- self._city_objects = self.city_objects_clusters
- if self.buildings is not None:
- for building in self.buildings:
- self._city_objects.append(building)
- if self.subway_entrances is not None:
- for subway_entrance in self.subway_entrances:
- self._city_objects.append(subway_entrance)
- if self.energy_systems is not None:
- for energy_system in self.energy_systems:
- self._city_objects.append(energy_system)
- return self._city_objects
+ if self._city_objects is None:
+ if self.city_objects_clusters is None:
+ self._city_objects = []
+ else:
+ self._city_objects = self.city_objects_clusters
+ if self.buildings is not None:
+ for building in self.buildings:
+ self._city_objects.append(building)
+ if self.subway_entrances is not None:
+ for subway_entrance in self.subway_entrances:
+ self._city_objects.append(subway_entrance)
+ if self.energy_systems is not None:
+ for energy_system in self.energy_systems:
+ self._city_objects.append(energy_system)
+ return self._city_objects
- @property
- def buildings(self) -> Union[List[Building], None]:
- """
+ @property
+ def buildings(self) -> Union[List[Building], None]:
+ """
Get the buildings belonging to the city
:return: None or [Building]
"""
- return self._buildings
+ return self._buildings
- @property
- def subway_entrances(self) -> Union[List[SubwayEntrance], None]:
- """
+ @property
+ def subway_entrances(self) -> Union[List[SubwayEntrance], None]:
+ """
Get the subway entrances belonging to the city
:return: a list of subway entrances objects or none
"""
- return self._subway_entrances
+ return self._subway_entrances
- @property
- def lower_corner(self) -> List[float]:
- """
+ @property
+ def lower_corner(self) -> List[float]:
+ """
Get city lower corner
:return: [x,y,z]
"""
- return self._lower_corner
+ return self._lower_corner
- @property
- def upper_corner(self) -> List[float]:
- """
+ @property
+ def upper_corner(self) -> List[float]:
+ """
Get city upper corner
:return: [x,y,z]
"""
- return self._upper_corner
+ return self._upper_corner
- def city_object(self, name) -> Union[CityObject, None]:
- """
+ def city_object(self, name) -> Union[CityObject, None]:
+ """
Retrieve the city CityObject with the given name
:param name:str
:return: None or CityObject
"""
- for city_object in self.buildings:
- if city_object.name == name:
- return city_object
- return None
+ for city_object in self.buildings:
+ if city_object.name == name:
+ return city_object
+ return None
- def add_city_object(self, new_city_object):
- """
+ def add_city_object(self, new_city_object):
+ """
Add a CityObject to the city
:param new_city_object:CityObject
:return: None or not implemented error
"""
- if new_city_object.type == 'building':
- if self._buildings is None:
- self._buildings = []
- self._buildings.append(new_city_object)
- elif new_city_object.type == 'subway_entrance':
- if self._subway_entrances is None:
- self._subway_entrances = []
- self._subway_entrances.append(new_city_object)
- elif new_city_object.type == 'energy_system':
- if self._energy_systems is None:
- self._energy_systems = []
- self._energy_systems.append(new_city_object)
- else:
- raise NotImplementedError(new_city_object.type)
+ if new_city_object.type == 'building':
+ if self._buildings is None:
+ self._buildings = []
+ self._buildings.append(new_city_object)
+ elif new_city_object.type == 'subway_entrance':
+ if self._subway_entrances is None:
+ self._subway_entrances = []
+ self._subway_entrances.append(new_city_object)
+ elif new_city_object.type == 'energy_system':
+ if self._energy_systems is None:
+ self._energy_systems = []
+ self._energy_systems.append(new_city_object)
+ else:
+ raise NotImplementedError(new_city_object.type)
- def remove_city_object(self, city_object):
- """
+ def remove_city_object(self, city_object):
+ """
Remove a CityObject from the city
:param city_object:CityObject
:return: None
"""
- if city_object.type != 'building':
- raise NotImplementedError(city_object.type)
- if self._buildings is None or self._buildings == []:
- sys.stderr.write('Warning: impossible to remove city_object, the city is empty\n')
- else:
- if city_object in self._buildings:
- self._buildings.remove(city_object)
+ if city_object.type != 'building':
+ raise NotImplementedError(city_object.type)
+ if self._buildings is None or self._buildings == []:
+ sys.stderr.write('Warning: impossible to remove city_object, the city is empty\n')
+ else:
+ if city_object in self._buildings:
+ self._buildings.remove(city_object)
- @property
- def srs_name(self) -> Union[None, str]:
- """
+ @property
+ def srs_name(self) -> Union[None, str]:
+ """
Get city srs name
:return: None or str
"""
- return self._srs_name
+ return self._srs_name
- @name.setter
- def name(self, value):
- """
+ @name.setter
+ def name(self, value):
+ """
Set city name
:param value:str
"""
- if value is not None:
- self._name = str(value)
+ if value is not None:
+ self._name = str(value)
- @staticmethod
- def load(city_filename) -> City:
- """
+ @staticmethod
+ def load(city_filename) -> City:
+ """
Load a city saved with city.save(city_filename)
:param city_filename: city filename
:return: City
"""
- with open(city_filename, 'rb') as file:
- return pickle.load(file)
+ with open(city_filename, 'rb') as file:
+ return pickle.load(file)
- def save(self, city_filename):
- """
+ def save(self, city_filename):
+ """
Save a city into the given filename
:param city_filename: destination city filename
:return: None
"""
- with open(city_filename, 'wb') as file:
- pickle.dump(self, file)
+ with open(city_filename, 'wb') as file:
+ pickle.dump(self, file)
- def region(self, center, radius) -> City:
- """
+ def region(self, center, radius) -> City:
+ """
Get a region from the city
:param center: specific point in space [x, y, z]
:param radius: distance to center of the sphere selected in meters
:return: selected_region_city
"""
- selected_region_lower_corner = [center[0] - radius, center[1] - radius, center[2] - radius]
- selected_region_upper_corner = [center[0] + radius, center[1] + radius, center[2] + radius]
- selected_region_city = City(selected_region_lower_corner, selected_region_upper_corner, srs_name=self.srs_name)
- selected_region_city.climate_file = self.climate_file
- # selected_region_city.climate_reference_city = self.climate_reference_city
- for city_object in self.city_objects:
- location = city_object.centroid
- if location is not None:
- distance = math.sqrt(math.pow(location[0] - center[0], 2) + math.pow(location[1] - center[1], 2)
- + math.pow(location[2] - center[2], 2))
- if distance < radius:
- selected_region_city.add_city_object(city_object)
- return selected_region_city
+ selected_region_lower_corner = [center[0] - radius, center[1] - radius, center[2] - radius]
+ selected_region_upper_corner = [center[0] + radius, center[1] + radius, center[2] + radius]
+ selected_region_city = City(selected_region_lower_corner, selected_region_upper_corner, srs_name=self.srs_name)
+ selected_region_city.climate_file = self.climate_file
+# selected_region_city.climate_reference_city = self.climate_reference_city
+ for city_object in self.city_objects:
+ location = city_object.centroid
+ if location is not None:
+ distance = math.sqrt(math.pow(location[0]-center[0], 2) + math.pow(location[1]-center[1], 2)
+ + math.pow(location[2]-center[2], 2))
+ if distance < radius:
+ selected_region_city.add_city_object(city_object)
+ return selected_region_city
- @property
- def latitude(self) -> Union[None, float]:
- """
+ @property
+ def latitude(self) -> Union[None, float]:
+ """
Get city latitude in degrees
:return: None or float
"""
- return self._latitude
+ return self._latitude
- @latitude.setter
- def latitude(self, value):
- """
+ @latitude.setter
+ def latitude(self, value):
+ """
Set city latitude in degrees
:parameter value: float
"""
- if value is not None:
- self._latitude = float(value)
+ if value is not None:
+ self._latitude = float(value)
- @property
- def longitude(self) -> Union[None, float]:
- """
+ @property
+ def longitude(self) -> Union[None, float]:
+ """
Get city longitude in degrees
:return: None or float
"""
- return self._longitude
+ return self._longitude
- @longitude.setter
- def longitude(self, value):
- """
+ @longitude.setter
+ def longitude(self, value):
+ """
Set city longitude in degrees
:parameter value: float
"""
- if value is not None:
- self._longitude = float(value)
+ if value is not None:
+ self._longitude = float(value)
- @property
- def time_zone(self) -> Union[None, float]:
- """
+ @property
+ def time_zone(self) -> Union[None, float]:
+ """
Get city time_zone
:return: None or float
"""
- return self._time_zone
+ return self._time_zone
- @time_zone.setter
- def time_zone(self, value):
- """
+ @time_zone.setter
+ def time_zone(self, value):
+ """
Set city time_zone
:parameter value: float
"""
- if value is not None:
- self._time_zone = float(value)
+ if value is not None:
+ self._time_zone = float(value)
- @property
- def buildings_clusters(self) -> Union[List[BuildingsCluster], None]:
- """
+ @property
+ def buildings_clusters(self) -> Union[List[BuildingsCluster], None]:
+ """
Get buildings clusters belonging to the city
:return: None or [BuildingsCluster]
"""
- return self._buildings_clusters
+ return self._buildings_clusters
- @property
- def parts_consisting_buildings(self) -> Union[List[PartsConsistingBuilding], None]:
- """
+ @property
+ def parts_consisting_buildings(self) -> Union[List[PartsConsistingBuilding], None]:
+ """
Get parts consisting buildings belonging to the city
:return: None or [PartsConsistingBuilding]
"""
- return self._parts_consisting_buildings
+ return self._parts_consisting_buildings
- @property
- def energy_systems(self) -> Union[List[EnergySystem], None]:
- """
- Get energy systems belonging to the city
- :return: None or [EnergySystem]
- """
- return self._energy_systems
+ @property
+ def energy_systems(self) -> Union[List[EnergySystem], None]:
+ """
+ Get energy systems belonging to the city
+ :return: None or [EnergySystem]
+ """
+ return self._energy_systems
- @property
- def city_objects_clusters(self) -> Union[List[CityObjectsCluster], None]:
- """
+ @property
+ def city_objects_clusters(self) -> Union[List[CityObjectsCluster], None]:
+ """
Get city objects clusters belonging to the city
:return: None or [CityObjectsCluster]
"""
- if self.buildings_clusters is None:
- self._city_objects_clusters = []
- else:
- self._city_objects_clusters = self.buildings_clusters
- if self.parts_consisting_buildings is not None:
- self._city_objects_clusters.append(self.parts_consisting_buildings)
- return self._city_objects_clusters
+ if self.buildings_clusters is None:
+ self._city_objects_clusters = []
+ else:
+ self._city_objects_clusters = self.buildings_clusters
+ if self.parts_consisting_buildings is not None:
+ self._city_objects_clusters.append(self.parts_consisting_buildings)
+ return self._city_objects_clusters
- def add_city_objects_cluster(self, new_city_objects_cluster):
- """
+ def add_city_objects_cluster(self, new_city_objects_cluster):
+ """
Add a CityObject to the city
:param new_city_objects_cluster:CityObjectsCluster
:return: None or NotImplementedError
"""
- if new_city_objects_cluster.type == 'buildings':
- if self._buildings_clusters is None:
- self._buildings_clusters = []
- self._buildings_clusters.append(new_city_objects_cluster)
- elif new_city_objects_cluster.type == 'building_parts':
- if self._parts_consisting_buildings is None:
- self._parts_consisting_buildings = []
- self._parts_consisting_buildings.append(new_city_objects_cluster)
- else:
- raise NotImplementedError
+ if new_city_objects_cluster.type == 'buildings':
+ if self._buildings_clusters is None:
+ self._buildings_clusters = []
+ self._buildings_clusters.append(new_city_objects_cluster)
+ elif new_city_objects_cluster.type == 'building_parts':
+ if self._parts_consisting_buildings is None:
+ self._parts_consisting_buildings = []
+ self._parts_consisting_buildings.append(new_city_objects_cluster)
+ else:
+ raise NotImplementedError
diff --git a/city_model_structure/energy_system.py b/city_model_structure/energy_system.py
index f1815bac..7fb7d2d1 100644
--- a/city_model_structure/energy_system.py
+++ b/city_model_structure/energy_system.py
@@ -1,7 +1,7 @@
"""
EnergySystem module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Peter Yefi peteryefi@gmail.com
"""
@@ -11,54 +11,54 @@ from city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP
class EnergySystem(CityObject):
- """
+ """
EnergySystem(CityObject) class
"""
- def __init__(self, name, lod, surfaces, city_lower_corner):
- super().__init__(name, lod, surfaces, city_lower_corner)
- self._air_source_hp = None
- self._water_to_water_hp = None
- self._type = 'energy_system'
+ def __init__(self, name, lod, surfaces, city_lower_corner):
+ super().__init__(name, lod, surfaces, city_lower_corner)
+ self._air_source_hp = None
+ self._water_to_water_hp = None
+ self._type = 'energy_system'
- @property
- def air_source_hp(self) -> AirSourceHP:
- """
- Heat pump energy system
- :return:
- """
- return self._air_source_hp
+ @property
+ def air_source_hp(self) -> AirSourceHP:
+ """
+ Heat pump energy system
+ :return:
+ """
+ return self._air_source_hp
- @air_source_hp.setter
- def air_source_hp(self, value):
- """
- Set heat pump for energy system
- :param value: AirSourceHP
- """
- if self._air_source_hp is None:
- self._air_source_hp = value
+ @air_source_hp.setter
+ def air_source_hp(self, value):
+ """
+ Set heat pump for energy system
+ :param value: AirSourceHP
+ """
+ if self._air_source_hp is None:
+ self._air_source_hp = value
- @property
- def water_to_water_hp(self) -> WaterToWaterHP:
- """
- Water to water heat pump energy system
- :return:
- """
- return self._water_to_water_hp
+ @property
+ def water_to_water_hp(self) -> WaterToWaterHP:
+ """
+ Water to water heat pump energy system
+ :return:
+ """
+ return self._water_to_water_hp
- @water_to_water_hp.setter
- def water_to_water_hp(self, value):
- """
- Set water to water heat pump for energy system
- :param value: WaterToWaterHP
- """
- if self._water_to_water_hp is None:
- self._water_to_water_hp = value
+ @water_to_water_hp.setter
+ def water_to_water_hp(self, value):
+ """
+ Set water to water heat pump for energy system
+ :param value: WaterToWaterHP
+ """
+ if self._water_to_water_hp is None:
+ self._water_to_water_hp = value
- @property
- def type(self) -> str:
- """
- Type of city object
- :return: str
- """
- return self._type
+ @property
+ def type(self) -> str:
+ """
+ Type of city object
+ :return: str
+ """
+ return self._type
diff --git a/city_model_structure/fuel.py b/city_model_structure/fuel.py
new file mode 100644
index 00000000..e78a9f76
--- /dev/null
+++ b/city_model_structure/fuel.py
@@ -0,0 +1,41 @@
+"""
+ConstructionFactory (before PhysicsFactory) retrieve the specific construction module for the given region
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+
+class Fuel:
+ def __init__(self, fuel_id, name, carbon_emission_factor, unit):
+ self._fuel_id = fuel_id
+ self._name = name
+ self._carbon_emission_factor = carbon_emission_factor
+ self._unit = unit
+
+ @property
+ def id(self):
+ """
+ Get fuel id
+ """
+ return self._fuel_id
+
+ @property
+ def name(self):
+ """
+ Get fuel name
+ """
+ return self._name
+
+ @property
+ def carbon_emission_factor(self):
+ """
+ Get fuel carbon emission factor
+ """
+ return self._carbon_emission_factor
+
+ @property
+ def unit(self):
+ """
+ Get fuel units
+ """
+ return self._unit
+
diff --git a/city_model_structure/lca_calculations.py b/city_model_structure/lca_calculations.py
new file mode 100644
index 00000000..032edcd6
--- /dev/null
+++ b/city_model_structure/lca_calculations.py
@@ -0,0 +1,23 @@
+"""
+LifeCycleAssessment retrieve the specific Life Cycle Assessment module for the given region
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+from city_model_structure.machine import Machine
+
+class LcaCalculations:
+ """
+ LCA Calculations class
+ """
+
+ def __init__(self):
+ print("lca calculations class")
+
+ def emission_disposal_machines(self, ):
+ return Machine.work_efficiency * Machine.energy_consumption_rate * Machine.carbon_emission_factor
+
+ def emission_transportation(self, weight, distance ):
+ return weight * distance * Machine.energy_consumption_rate * Machine.carbon_emission_factor
+
+
+
diff --git a/city_model_structure/machine.py b/city_model_structure/machine.py
new file mode 100644
index 00000000..5c25fc71
--- /dev/null
+++ b/city_model_structure/machine.py
@@ -0,0 +1,78 @@
+"""
+LifeCycleAssessment retrieve the specific Life Cycle Assessment module for the given region
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+
+class Machine:
+ """
+ Machine class
+ """
+
+ def __init__(self, machine_id, name, work_efficiency, work_efficiency_unit, energy_consumption_rate, energy_consumption_unit,
+ carbon_emission_factor, carbon_emission_unit):
+ self._machine_id = machine_id
+ self._name = name
+ self._work_efficiency = work_efficiency
+ self._work_efficiency_unit = work_efficiency_unit
+ self._energy_consumption_rate = energy_consumption_rate
+ self._energy_consumption_unit = energy_consumption_unit
+ self._carbon_emission_factor = carbon_emission_factor
+ self._carbon_emission_unit = carbon_emission_unit
+
+ @property
+ def id(self):
+ """
+ Get machine id
+ """
+ return self._machine_id
+
+ @property
+ def name(self):
+ """
+ Get machine name
+ """
+ return self._name
+
+ @property
+ def work_efficiency(self):
+ """
+ Get machine work efficiency
+ """
+ return self._work_efficiency
+
+ @property
+ def work_efficiency_unit(self):
+ """
+ Get machine work efficiency unit
+ """
+ return self._work_efficiency_unit
+
+ @property
+ def energy_consumption_rate(self):
+ """
+ Get energy consumption rate
+ """
+ return self._energy_consumption_rate
+
+ @property
+ def energy_consumption_unit(self):
+ """
+ Get energy consumption unit
+ """
+ return self._energy_consumption_unit
+
+ @property
+ def carbon_emission_factor(self):
+ """
+ Get carbon emission factor
+ """
+ return self._carbon_emission_factor
+
+ @property
+ def carbon_emission_unit(self):
+ """
+ Get carbon emission unit
+ """
+ return self._carbon_emission_unit
+
diff --git a/city_model_structure/material.py b/city_model_structure/material.py
new file mode 100644
index 00000000..d0ef2c53
--- /dev/null
+++ b/city_model_structure/material.py
@@ -0,0 +1,118 @@
+"""
+LifeCycleAssessment retrieve the specific Life Cycle Assessment module for the given region
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+
+class Material:
+ """
+ LCA Material class
+ """
+
+ def __init__(self, material_name, material_id, type, density, density_unit, embodied_carbon, embodied_carbon_unit, recycling_ratio,
+ onsite_recycling_ratio, company_recycling_ratio, landfilling_ratio, cost, cost_unit):
+ self._material_name = material_name
+ self._material_id = material_id
+ self._type = type
+ self._density = density
+ self._density_unit = density_unit
+ self._embodied_carbon = embodied_carbon
+ self._embodied_carbon_unit = embodied_carbon_unit
+ self._recycling_ratio = recycling_ratio
+ self._onsite_recycling_ratio = onsite_recycling_ratio
+ self._company_recycling_ratio = company_recycling_ratio
+ self._landfilling_ratio = landfilling_ratio
+ self._cost = cost
+ self._cost_unit = cost_unit
+
+ @property
+ def material_name(self):
+ """
+ Get material name
+ """
+ return self._material_name
+
+ @property
+ def id(self):
+ """
+ Get material id
+ """
+ return self._material_id
+
+ @property
+ def type(self):
+ """
+ Get material type
+ """
+ return self._type
+
+ @property
+ def density(self):
+ """
+ Get material density
+ """
+ return self._density
+
+ @property
+ def density_unit(self):
+ """
+ Get material density unit
+ """
+ return self._density_unit
+
+ @property
+ def embodied_carbon(self):
+ """
+ Get material embodied carbon
+ """
+ return self._embodied_carbon
+
+ @property
+ def embodied_carbon_unit(self):
+ """
+ Get material embodied carbon unit
+ """
+ return self._embodied_carbon_unit
+
+ @property
+ def recycling_ratio(self):
+ """
+ Get material recycling ratio
+ """
+ return self._recycling_ratio
+
+ @property
+ def onsite_recycling_ratio(self):
+ """
+ Get material onsite recycling ratio
+ """
+ return self._onsite_recycling_ratio
+
+ @property
+ def company_recycling_ratio(self):
+ """
+ Get material company recycling ratio
+ """
+ return self._company_recycling_ratio
+
+ @property
+ def landfilling_ratio(self):
+ """
+ Get material landfilling ratio
+ """
+ return self._landfilling_ratio
+
+ @property
+ def cost(self):
+ """
+ Get material cost
+ """
+ return self._cost
+
+ @property
+ def cost_unit(self):
+ """
+ Get material cost unit
+ """
+ return self._cost_unit
+
diff --git a/city_model_structure/network.py b/city_model_structure/network.py
index 869c7107..ae3d0186 100644
--- a/city_model_structure/network.py
+++ b/city_model_structure/network.py
@@ -1,9 +1,10 @@
"""
Network module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
"""
+
import uuid
from typing import List
diff --git a/city_model_structure/transport/bus.py b/city_model_structure/transport/bus.py
new file mode 100644
index 00000000..ea7acb47
--- /dev/null
+++ b/city_model_structure/transport/bus.py
@@ -0,0 +1,114 @@
+"""
+Bus module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from city_model_structure.attributes.schedule import Schedule
+
+
+class Bus:
+ """
+ Bus class
+ """
+
+ def __init__(self):
+ self._maintenance_time = None
+ self._charging_time = None
+ self._recovery_time = None
+ self._vehicle_type = None
+ self._energy_consumption = None
+ self._trips_schedule = None
+ self._capacity = None
+ self._maintenance_cost = None
+ self._investment_cost = None
+ self._charging_range = None
+ self._maximum_travel_range = None
+
+ @property
+ def maintenance_time(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._maintenance_time
+
+ @property
+ def charging_time(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._charging_time
+
+ @property
+ def recovery_time(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self.maintenance_time + self.charging_time
+
+ @property
+ def vehicle_type(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._vehicle_type
+
+ @property
+ def energy_consumption(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._energy_consumption
+
+ @property
+ def trips_schedule(self) -> Schedule:
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._trips_schedule
+
+ @property
+ def capacity(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._capacity
+
+ @property
+ def maintenance_cost(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._maintenance_cost
+
+ @property
+ def investment_cost(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._investment_cost
+
+ @property
+ def charging_range(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._charging_range
+
+ @property
+ def maximum_travel_range(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._maximum_travel_range
diff --git a/city_model_structure/transport/bus_depot.py b/city_model_structure/transport/bus_depot.py
new file mode 100644
index 00000000..0b617275
--- /dev/null
+++ b/city_model_structure/transport/bus_depot.py
@@ -0,0 +1,34 @@
+"""
+Bus depot module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from city_model_structure.transport.bus_node import BusNode
+
+
+class BusDepot(BusNode):
+ """
+ BusDepot class
+ """
+
+ def __init__(self, name, coordinates, edges=None):
+ super().__init__(name, coordinates, edges=edges, node_type='BusDepot')
+ self._number_of_charging_poles = None
+ self._number_of_available_buses = None
+
+ @property
+ def number_of_charging_poles(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._number_of_charging_poles
+
+ @property
+ def number_of_available_buses(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._number_of_available_buses
diff --git a/city_model_structure/transport/bus_edge.py b/city_model_structure/transport/bus_edge.py
new file mode 100644
index 00000000..98c31dc0
--- /dev/null
+++ b/city_model_structure/transport/bus_edge.py
@@ -0,0 +1,46 @@
+"""
+Bus edge module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from typing import List, TypeVar
+from city_model_structure.attributes.edge import Edge
+
+BusNode = TypeVar('BusNode')
+
+
+class BusEdge(Edge):
+ """
+ BusEdge class
+ Each edge is unidirectional and starts at the "from" node and ends at the "to" node
+ """
+
+ def __init__(self, name, nodes, edge_type='BusEdge'):
+ super().__init__(name, nodes)
+ self._edge_type = edge_type
+ self._average_travel_time = None
+
+ @property
+ def edge_type(self):
+ """
+ Get the edge type
+ :return: str
+ """
+ return self._edge_type
+
+ @property
+ def nodes(self) -> List[BusNode]:
+ """
+ Get delimiting nodes for the edge
+ :return: [BusNode]
+ """
+ return self._nodes
+
+ @property
+ def average_travel_time(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._average_travel_time
diff --git a/city_model_structure/transport/bus_network.py b/city_model_structure/transport/bus_network.py
new file mode 100644
index 00000000..6f3dfbd8
--- /dev/null
+++ b/city_model_structure/transport/bus_network.py
@@ -0,0 +1,43 @@
+"""
+Bus network module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from typing import List
+from city_model_structure.network import Network
+from city_model_structure.transport.bus_edge import BusEdge
+from city_model_structure.transport.bus_node import BusNode
+
+
+class BusNetwork(Network):
+ """
+ BusNetwork(Network) class
+ """
+ def __init__(self, name, edges=None, nodes=None):
+ super().__init__(name, edges, nodes)
+ self._type = "BusNetwork"
+
+ @property
+ def type(self):
+ """
+ Get network type
+ :return: str
+ """
+ return self._type
+
+ @property
+ def edges(self) -> List[BusEdge]:
+ """
+ Get network edges
+ :return: [BusEdge]
+ """
+ return self._edges
+
+ @property
+ def nodes(self) -> List[BusNode]:
+ """
+ Get network nodes
+ :return: [BusNode]
+ """
+ return self._nodes
diff --git a/city_model_structure/transport/bus_node.py b/city_model_structure/transport/bus_node.py
new file mode 100644
index 00000000..17274a4f
--- /dev/null
+++ b/city_model_structure/transport/bus_node.py
@@ -0,0 +1,55 @@
+"""
+Bus node module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from typing import List, TypeVar
+
+from city_model_structure.attributes.node import Node
+from city_model_structure.attributes.point import Point
+
+BusEdge = TypeVar('BusEdge')
+
+
+class BusNode(Node):
+ """
+ BusNode class
+ """
+
+ def __init__(self, name, coordinates, node_type='BusNode', edges=None):
+ super().__init__(name, edges)
+ self._coordinates = coordinates
+ self._node_type = node_type
+
+ @property
+ def node_type(self):
+ """
+ Get node type
+ :return: str
+ """
+ return self._node_type
+
+ @property
+ def coordinates(self) -> Point:
+ """
+ Get node coordinates
+ :return: Point
+ """
+ return self._coordinates
+
+ @coordinates.setter
+ def coordinates(self, value):
+ """
+ Set node coordinates
+ :param value: Point
+ """
+ self._coordinates = value
+
+ @property
+ def edges(self) -> List[BusEdge]:
+ """
+ get edges delimited by the node
+ :return: [BusEdge]
+ """
+ return self._edges
diff --git a/city_model_structure/transport/bus_stop.py b/city_model_structure/transport/bus_stop.py
new file mode 100644
index 00000000..b4fccd62
--- /dev/null
+++ b/city_model_structure/transport/bus_stop.py
@@ -0,0 +1,55 @@
+"""
+Bus stop module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from typing import Union
+from city_model_structure.transport.bus_node import BusNode
+from city_model_structure.transport.fast_charging_infrastructure import FastChargingInfrastructure
+from city_model_structure.attributes.schedule import Schedule
+
+
+class BusStop(BusNode):
+ """
+ BusStop class
+ """
+
+ def __init__(self, name, coordinates, edges=None):
+ super().__init__(name, coordinates, edges=edges, node_type='BusStop')
+ self._time_table = None
+ self._average_hourly_passengers_demand = None
+ self._fast_charging_infrastructure = None
+ self._waiting_time = None
+
+ @property
+ def time_table(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._time_table
+
+ @property
+ def average_hourly_passengers_demand(self) -> Schedule:
+ """
+ Add explanation here
+ :return: Schedule
+ """
+ return self._average_hourly_passengers_demand
+
+ @property
+ def fast_charging_infrastructure(self) -> Union[None, FastChargingInfrastructure]:
+ """
+ Add explanation here
+ :return: FastChargingInfrastructure
+ """
+ return self._fast_charging_infrastructure
+
+ @property
+ def waiting_time(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._waiting_time
diff --git a/city_model_structure/transport/connection.py b/city_model_structure/transport/connection.py
index 093fb4b8..0f023cd4 100644
--- a/city_model_structure/transport/connection.py
+++ b/city_model_structure/transport/connection.py
@@ -1,7 +1,7 @@
"""
Connection module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
diff --git a/city_model_structure/transport/crossing.py b/city_model_structure/transport/crossing.py
index 9a28c8f8..0b740355 100644
--- a/city_model_structure/transport/crossing.py
+++ b/city_model_structure/transport/crossing.py
@@ -1,7 +1,7 @@
"""
Crossing module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
diff --git a/city_model_structure/transport/fast_charging_infrastructure.py b/city_model_structure/transport/fast_charging_infrastructure.py
new file mode 100644
index 00000000..a3369a91
--- /dev/null
+++ b/city_model_structure/transport/fast_charging_infrastructure.py
@@ -0,0 +1,31 @@
+"""
+Fast charging infrastructure module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+
+class FastChargingInfrastructure:
+ """
+ FastChargingInfrastructure class
+ """
+
+ def __init__(self):
+ self._electrical_demand = None
+ self._losses_in_grid = None
+
+ @property
+ def electrical_demand(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._electrical_demand
+
+ @property
+ def losses_in_grid(self):
+ """
+ Add explanation here
+ :return: add type of variable here
+ """
+ return self._losses_in_grid
diff --git a/city_model_structure/transport/join.py b/city_model_structure/transport/join.py
index a7f609b8..3e1cd143 100644
--- a/city_model_structure/transport/join.py
+++ b/city_model_structure/transport/join.py
@@ -1,7 +1,7 @@
"""
Join module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
diff --git a/city_model_structure/transport/lane.py b/city_model_structure/transport/lane.py
index d68bcca0..417f986a 100644
--- a/city_model_structure/transport/lane.py
+++ b/city_model_structure/transport/lane.py
@@ -1,7 +1,7 @@
"""
Lane module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
"""
diff --git a/city_model_structure/transport/origin_destination_edge.py b/city_model_structure/transport/origin_destination_edge.py
index c3d3f3c1..32fa7cbb 100644
--- a/city_model_structure/transport/origin_destination_edge.py
+++ b/city_model_structure/transport/origin_destination_edge.py
@@ -1,13 +1,16 @@
"""
Origin-Destination edge module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
+from typing import List, TypeVar
from city_model_structure.attributes.edge import Edge
from city_model_structure.attributes.schedule import Schedule
+OriginDestinationNode = TypeVar('OriginDestinationNode')
+
class OriginDestinationEdge(Edge):
"""
@@ -28,6 +31,14 @@ class OriginDestinationEdge(Edge):
"""
return self._edge_type
+ @property
+ def nodes(self) -> List[OriginDestinationNode]:
+ """
+ Get delimiting nodes for the edge
+ :return: [OriginDestinationNode]
+ """
+ return self._nodes
+
@property
def movement_schedule(self) -> Schedule:
"""
diff --git a/city_model_structure/transport/origin_destination_network.py b/city_model_structure/transport/origin_destination_network.py
index b23bb01c..9090f983 100644
--- a/city_model_structure/transport/origin_destination_network.py
+++ b/city_model_structure/transport/origin_destination_network.py
@@ -1,10 +1,13 @@
"""
Origin-Destination network module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
+from typing import List
from city_model_structure.network import Network
+from city_model_structure.transport.origin_destination_edge import OriginDestinationEdge
+from city_model_structure.transport.origin_destination_node import OriginDestinationNode
class OriginDestinationNetwork(Network):
@@ -22,3 +25,19 @@ class OriginDestinationNetwork(Network):
:return: str
"""
return self._type
+
+ @property
+ def edges(self) -> List[OriginDestinationEdge]:
+ """
+ Get network edges
+ :return: [OriginDestinationEdge]
+ """
+ return self._edges
+
+ @property
+ def nodes(self) -> List[OriginDestinationNode]:
+ """
+ Get network nodes
+ :return: [OriginDestinationNode]
+ """
+ return self._nodes
diff --git a/city_model_structure/transport/origin_destination_node.py b/city_model_structure/transport/origin_destination_node.py
index 5e46e92d..ea84bd5c 100644
--- a/city_model_structure/transport/origin_destination_node.py
+++ b/city_model_structure/transport/origin_destination_node.py
@@ -1,15 +1,17 @@
"""
Origin-Destination node module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
-from typing import List
+from typing import List, TypeVar
from city_model_structure.attributes.node import Node
from city_model_structure.attributes.point import Point
from city_model_structure.attributes.polygon import Polygon
from city_model_structure.city_object import CityObject
+OriginDestinationEdge = TypeVar('OriginDestinationEdge')
+
class OriginDestinationNode(Node):
"""
@@ -48,6 +50,14 @@ class OriginDestinationNode(Node):
"""
self._coordinates = value
+ @property
+ def edges(self) -> List[OriginDestinationEdge]:
+ """
+ get edges delimited by the node
+ :return: [OriginDestinationEdge]
+ """
+ return self._edges
+
@property
def polygon(self) -> Polygon:
"""
diff --git a/city_model_structure/transport/phase.py b/city_model_structure/transport/phase.py
index 559e0834..66d2d59b 100644
--- a/city_model_structure/transport/phase.py
+++ b/city_model_structure/transport/phase.py
@@ -1,7 +1,7 @@
"""
Phase module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
"""
diff --git a/city_model_structure/transport/traffic_edge.py b/city_model_structure/transport/traffic_edge.py
index 1fd77299..e507e0ba 100644
--- a/city_model_structure/transport/traffic_edge.py
+++ b/city_model_structure/transport/traffic_edge.py
@@ -1,13 +1,14 @@
"""
Traffic edge module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
from typing import List, Union
from city_model_structure.attributes.edge import Edge
+from city_model_structure.transport.traffic_node import TrafficNode
from city_model_structure.transport.lane import Lane
@@ -37,6 +38,14 @@ class TrafficEdge(Edge):
"""
return self._edge_type
+ @property
+ def nodes(self) -> List[TrafficNode]:
+ """
+ Get delimiting nodes for the edge
+ :return: [TrafficNode]
+ """
+ return self._nodes
+
@property
def lanes(self) -> List[Lane]:
"""
diff --git a/city_model_structure/transport/traffic_light.py b/city_model_structure/transport/traffic_light.py
index 7b7d4621..89827a62 100644
--- a/city_model_structure/transport/traffic_light.py
+++ b/city_model_structure/transport/traffic_light.py
@@ -1,7 +1,7 @@
"""
Traffic light module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
diff --git a/city_model_structure/transport/traffic_network.py b/city_model_structure/transport/traffic_network.py
index 27e30096..eef5a4e9 100644
--- a/city_model_structure/transport/traffic_network.py
+++ b/city_model_structure/transport/traffic_network.py
@@ -1,12 +1,15 @@
"""
Traffic network module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
+from typing import List
from city_model_structure.network import Network
+from city_model_structure.transport.traffic_edge import TrafficEdge
+from city_model_structure.transport.traffic_node import TrafficNode
class TrafficNetwork(Network):
@@ -24,3 +27,19 @@ class TrafficNetwork(Network):
:return: str
"""
return self._type
+
+ @property
+ def edges(self) -> List[TrafficEdge]:
+ """
+ Get network edges
+ :return: [TrafficEdge]
+ """
+ return self._edges
+
+ @property
+ def nodes(self) -> List[TrafficNode]:
+ """
+ Get network nodes
+ :return: [TrafficNode]
+ """
+ return self._nodes
diff --git a/city_model_structure/transport/traffic_node.py b/city_model_structure/transport/traffic_node.py
index 3008cf97..6188e6e5 100644
--- a/city_model_structure/transport/traffic_node.py
+++ b/city_model_structure/transport/traffic_node.py
@@ -1,18 +1,19 @@
"""
TrafficNode module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
-from typing import List
+
+from typing import List, TypeVar
from city_model_structure.attributes.edge import Edge
from city_model_structure.attributes.node import Node
from city_model_structure.attributes.point import Point
-
-from city_model_structure.transport.connection import Connection
+Connection = TypeVar('Connection')
+TrafficEdge = TypeVar('TrafficEdge')
class TrafficNode(Node):
@@ -55,6 +56,14 @@ class TrafficNode(Node):
"""
self._coordinates = value
+ @property
+ def edges(self) -> List[TrafficEdge]:
+ """
+ get edges delimited by the node
+ :return: [TrafficEdge]
+ """
+ return self._edges
+
@property
def prohibitions(self) -> [(Edge, Edge)]:
"""
diff --git a/city_model_structure/transport/walkway_node.py b/city_model_structure/transport/walkway_node.py
index 36ec90c6..e884f976 100644
--- a/city_model_structure/transport/walkway_node.py
+++ b/city_model_structure/transport/walkway_node.py
@@ -1,7 +1,7 @@
"""
Walkway node module
SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Contributor Milad milad.aghamohamadnia@concordia.ca
Contributor Guille guille.gutierrezmorote@concordia.ca
"""
diff --git a/city_model_structure/vehicle.py b/city_model_structure/vehicle.py
new file mode 100644
index 00000000..95aff94a
--- /dev/null
+++ b/city_model_structure/vehicle.py
@@ -0,0 +1,61 @@
+"""
+LifeCycleAssessment retrieve the specific Life Cycle Assessment module for the given region
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+
+class Vehicle:
+ """
+ Vehicle class
+ """
+
+ def __init__(self, vehicle_id, name, fuel_consumption_rate, fuel_consumption_unit, carbon_emission_factor, carbon_emission_factor_unit):
+ self._vehicle_id = vehicle_id
+ self._name = name
+ self._fuel_consumption_rate = fuel_consumption_rate
+ self._fuel_consumption_unit = fuel_consumption_unit
+ self._carbon_emission_factor = carbon_emission_factor
+ self._carbon_emission_factor_unit = carbon_emission_factor_unit
+
+ @property
+ def id(self):
+ """
+ Get vehicle id
+ """
+ return self._vehicle_id
+
+ @property
+ def name(self):
+ """
+ Get vehicle name
+ """
+ return self._name
+
+ @property
+ def fuel_consumption_rate(self):
+ """
+ Get vehicle fuel consumption rate
+ """
+ return self._fuel_consumption_rate
+
+ @property
+ def fuel_consumption_unit(self):
+ """
+ Get fuel consumption unit
+ """
+ return self._fuel_consumption_unit
+
+ @property
+ def carbon_emission_factor(self):
+ """
+ Get vehicle carbon emission factor
+ """
+ return self._carbon_emission_factor
+
+ @property
+ def carbon_emission_unit(self):
+ """
+ Get carbon emission units
+ """
+ return self._carbon_emission_unit
+
diff --git a/config/configuration.ini b/config/configuration.ini
index 394c1c61..b2ddfb04 100644
--- a/config/configuration.ini
+++ b/config/configuration.ini
@@ -3,3 +3,11 @@
max_location_distance_for_shared_walls = 5.0
min_coordinate = -1.7976931348623157e+308
max_coordinate = 1.7976931348623157e+308
+comnet_lighting_latent = 0
+comnet_lighting_convective = 0.5
+comnet_lighting_radiant = 0.5
+comnet_occupancy_sensible_convective = 0.9
+comnet_occupancy_sensible_radiant = 0.1
+comnet_plugs_latent = 0
+comnet_plugs_convective = 0.75
+comnet_plugs_radiant = 0.25
diff --git a/data/customized_imports/ashrae_archetypes.xml b/data/customized_imports/ashrae_archetypes.xml
new file mode 100644
index 00000000..df281f3a
--- /dev/null
+++ b/data/customized_imports/ashrae_archetypes.xml
@@ -0,0 +1,123 @@
+
+
+ Ashrae values
+ Library created by Sanam from ANSI/ASHRAE Standard 62-2001
+
+ assembly
+
+ 0.15
+
+
+
+ 5
+
+
+
+
+ health
+
+ 0.1
+
+
+
+ 20
+
+
+
+
+ hotel
+
+ 0.11
+
+
+
+ 5
+
+
+
+
+ manufacturing
+
+ 0.07
+
+
+
+ 10
+
+
+
+
+ office
+
+ 0.05
+
+
+
+ 5
+
+
+
+
+ restaurant
+
+ 0.7
+
+
+
+ 7.5
+
+
+
+
+ retail
+
+ 0.2
+
+
+
+ 7.5
+
+
+
+
+ school
+
+ 0.25
+
+
+
+ 10
+
+
+
+
+ lab
+
+ 0.25
+
+
+
+ 10
+
+
+
+
+ residential
+
+
+ 5
+
+
+
+
+ gymnasium
+
+ 0.3
+
+
+
+ 7.5
+
+
+
+
diff --git a/data/life_cycle_assessment/lca_data.xml b/data/life_cycle_assessment/lca_data.xml
new file mode 100644
index 00000000..bc3ab8ee
--- /dev/null
+++ b/data/life_cycle_assessment/lca_data.xml
@@ -0,0 +1,573 @@
+
+
+
+
+ 0.32
+
+
+ 0.4
+
+
+ 0.4
+
+
+ 0.5
+
+
+ 0.18
+
+
+ 0.39
+
+
+ 0.27
+
+
+ 4.16
+
+
+ 2.24
+
+
+ 0.2
+
+
+ 3.19
+
+
+ 3.53
+
+
+ 0.27
+
+
+ 0.21
+
+
+ 1.69
+
+
+ 0.21
+
+
+ 0.35
+
+
+ 0.18
+
+
+ 0.81
+
+
+ 1.21
+
+
+ 1.61
+
+
+ 0.11
+
+
+ 0.3
+
+
+ 1.16
+
+
+ 0.61
+
+
+
+
+ 0.347
+ 16.5
+ 0.918
+
+
+ 0.033
+ 25.2
+ 4.16
+
+
+ 0.027
+ 16.8
+ 2.239
+
+
+ 0.023
+ 16.8
+ 2.239
+
+
+ 0.109
+ 25.2
+ 2.239
+
+
+ 0.003
+ 16.4
+ 4.16
+
+
+ 0.002
+ 11
+ 0.918
+
+
+ 0.002
+ 90
+ 0.918
+
+
+ 0.002
+ 10
+ 0.918
+
+
+ 0.002
+ 11
+ 0.918
+
+
+ 0.002
+ 132
+ 0.918
+
+
+ 0.002
+ 15
+ 0.918
+
+
+ 0.002
+ 5.5
+ 0.918
+
+
+ 0.002
+ 22.5
+ 0.918
+
+
+
+
+ 0.0123
+ 2.239
+
+
+ 0.042
+ 0.918
+
+
+ 0.01
+ 1.00000
+
+
+ 1.3
+ 1.00000
+
+
+
+
+
+ 1.8
+ 560
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+ 1.2
+ 310
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+ 2
+ 3080
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+ 1.4
+ 300
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+
+
+ 1.6
+ 900
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.6
+ 2340
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.6
+ 1570
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.4
+ 1840
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.3
+ 410
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 160
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 170
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 230
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.4
+ 240
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.4
+ 280
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 170
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.2
+ 440
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+
+
+ 2.58
+ 2660
+ 0.95
+ 0
+ 1
+ 0.05
+ ....
+
+
+ 2.58
+ 5260
+ 0.95
+ 0
+ 1
+ 0.05
+ ....
+
+
+
+
+ 0.06
+ 1760
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.122
+ 3080
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.028
+ 3180
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.024
+ 5140
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.1
+ 6040
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.3
+ 5380
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.032
+ 2150
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+
+
+ 0.9
+ 3420
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+ 0.7
+ 1430
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+ 0.65
+ 2780
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+ 0.72
+ 2190
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+
+
+ 1.43
+ 1070
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.43
+ 240
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.43
+ 430
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.43
+ 340
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.2
+ 440
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.1
+ 1410
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.43
+ 250
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.44
+ 1480
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.44
+ 2220
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.27
+ 3960
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.15
+ 760
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+
+
+ 8
+ 3160
+ 0.98
+ 0
+ 1
+ 0.02
+ ....
+
+
+ 2.7
+ 5370
+ 0.98
+ 0
+ 1
+ 0.02
+ ....
+
+
+ 7.85
+ 3910
+ 0.98
+ 0
+ 1
+ 0.02
+ ....
+
+
+
+
\ No newline at end of file
diff --git a/data/usage/comnet_archetypes.xlsx b/data/usage/comnet_archetypes.xlsx
new file mode 100644
index 00000000..8e04fc17
Binary files /dev/null and b/data/usage/comnet_archetypes.xlsx differ
diff --git a/helpers/configuration_helper.py b/helpers/configuration_helper.py
index 0a9b2d6c..85677ceb 100644
--- a/helpers/configuration_helper.py
+++ b/helpers/configuration_helper.py
@@ -38,4 +38,70 @@ class ConfigurationHelper:
Get configured maximal coordinate value
:return: 1.7976931348623157e+308
"""
- return self._config.getfloat('buildings', 'max_coordinate')
+ return self._config.getfloat('buildings', 'max_coordinate').real
+
+ @property
+ def comnet_lighting_latent(self) -> float:
+ """
+ Get configured latent ratio of internal gains do to lighting used for Comnet (ASHRAE) standard
+ :return: 0
+ """
+ return self._config.getfloat('buildings', 'comnet_lighting_latent').real
+
+ @property
+ def comnet_lighting_convective(self) -> float:
+ """
+ Get configured convective ratio of internal gains do to lighting used for Comnet (ASHRAE) standard
+ :return: 0.5
+ """
+ return self._config.getfloat('buildings', 'comnet_lighting_convective').real
+
+ @property
+ def comnet_lighting_radiant(self) -> float:
+ """
+ Get configured radiant ratio of internal gains do to lighting used for Comnet (ASHRAE) standard
+ :return: 0.5
+ """
+ return self._config.getfloat('buildings', 'comnet_lighting_radiant').real
+
+ @property
+ def comnet_plugs_latent(self) -> float:
+ """
+ Get configured latent ratio of internal gains do to electrical appliances used for Comnet (ASHRAE) standard
+ :return: 0
+ """
+ return self._config.getfloat('buildings', 'comnet_plugs_latent').real
+
+ @property
+ def comnet_plugs_convective(self) -> float:
+ """
+ Get configured convective ratio of internal gains do to electrical appliances used for Comnet (ASHRAE) standard
+ :return: 0.75
+ """
+ return self._config.getfloat('buildings', 'comnet_plugs_convective').real
+
+ @property
+ def comnet_plugs_radiant(self) -> float:
+ """
+ Get configured radiant ratio of internal gains do to electrical appliances used for Comnet (ASHRAE) standard
+ :return: 0.25
+ """
+ return self._config.getfloat('buildings', 'comnet_plugs_radiant').real
+
+ @property
+ def comnet_occupancy_sensible_convective(self) -> float:
+ """
+ Get configured convective ratio of the sensible part of internal gains do to occupancy
+ used for Comnet (ASHRAE) standard
+ :return: 0.9
+ """
+ return self._config.getfloat('buildings', 'comnet_occupancy_sensible_convective').real
+
+ @property
+ def comnet_occupancy_sensible_radiant(self) -> float:
+ """
+ Get configured radiant ratio of the sensible part of internal gains do to occupancy
+ used for Comnet (ASHRAE) standard
+ :return: 0.1
+ """
+ return self._config.getfloat('buildings', 'comnet_occupancy_sensible_radiant').real
diff --git a/helpers/constants.py b/helpers/constants.py
index 0f571a50..00416177 100644
--- a/helpers/constants.py
+++ b/helpers/constants.py
@@ -7,6 +7,11 @@ Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.mons
# universal constants
KELVIN = 273.15
+# converters
+HOUR_TO_MINUTES = 60
+METERS_TO_FEET = 3.28084
+BTU_H_TO_WATTS = 0.29307107
+
# time
SECOND = 'second'
MINUTE = 'minute'
@@ -36,7 +41,6 @@ TEMPERATURE = 'temperature'
HUMIDITY = 'humidity'
CONTROL_TYPE = 'control_type'
-# todo: modify code to use global constants instead of hard-coded values
# surface types
WALL = 'Wall'
GROUND_WALL = 'Ground wall'
@@ -76,7 +80,10 @@ HALL = 'hall'
RESTAURANT = 'restaurant'
EDUCATION = 'education'
-
-
-
-
+LIGHTING = 'Lights'
+OCCUPANCY = 'Occupancy'
+RECEPTACLE = 'Receptacle'
+HVAC_AVAILABILITY = 'HVAC Avail'
+INFILTRATION = 'Infiltration'
+COOLING_SET_POINT = 'ClgSetPt'
+HEATING_SET_POINT = 'HtgSetPt'
diff --git a/helpers/enrich_city.py b/helpers/enrich_city.py
index e19bcf41..cc5067a1 100644
--- a/helpers/enrich_city.py
+++ b/helpers/enrich_city.py
@@ -55,10 +55,13 @@ class EnrichCity:
def _construction(self, construction_format):
ConstructionFactory(construction_format, self._city).enrich()
+
for building in self._city.buildings:
# infiltration_rate_system_off is a mandatory parameter.
# 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)
if self._city.buildings is None:
self._errors.append('no archetype found per construction')
diff --git a/helpers/yearly_from_daily_schedules.py b/helpers/yearly_from_daily_schedules.py
new file mode 100644
index 00000000..c7c3bac5
--- /dev/null
+++ b/helpers/yearly_from_daily_schedules.py
@@ -0,0 +1,44 @@
+"""
+Yearly from daily schedules module
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+import calendar as cal
+import helpers.constants as cte
+from city_model_structure.attributes.schedule import Schedule
+
+
+class YearlyFromDailySchedules:
+ """
+ YearlyFromDailySchedules class
+ """
+ def __init__(self, daily_schedules, year):
+ self._daily_schedules = daily_schedules
+ self._year = year
+
+ @property
+ def yearly_schedule(self) -> Schedule:
+ """
+ Creates a yearly schedule out of a set of daily schedules
+ :return: Schedule
+ """
+ yearly_schedule = Schedule()
+ weekly_schedules = [0, 0, 0, 0, 0, 0, 0]
+ day_types = dict({cte.MONDAY: 0, cte.TUESDAY: 1, cte.WEDNESDAY: 2, cte.THURSDAY: 3,
+ cte.FRIDAY: 4, cte.SATURDAY: 5, cte.SUNDAY: 6})
+ for daily_schedule in self._daily_schedules:
+ for day_type in daily_schedule.day_types:
+ weekly_schedules[day_types[day_type]] = daily_schedule.values
+
+ values = []
+ for month in range(1, 13):
+ for day in range(1, cal.monthlen(self._year, month)+1):
+ week_day = cal.weekday(self._year, month, day)
+ values.extend(weekly_schedules[week_day])
+ yearly_schedule.type = self._daily_schedules[0].type
+ yearly_schedule.data_type = self._daily_schedules[0].data_type
+ yearly_schedule.time_range = cte.YEAR
+ yearly_schedule.time_step = cte.HOUR
+ yearly_schedule.values = values
+
+ return yearly_schedule
diff --git a/imports/customized_imports/helpers/sanam_customized_usage_helper.py b/imports/customized_imports/helpers/sanam_customized_usage_helper.py
new file mode 100644
index 00000000..a0d981b8
--- /dev/null
+++ b/imports/customized_imports/helpers/sanam_customized_usage_helper.py
@@ -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
diff --git a/imports/customized_imports/sanam_customized_usage_parameters.py b/imports/customized_imports/sanam_customized_usage_parameters.py
new file mode 100644
index 00000000..6604a8e5
--- /dev/null
+++ b/imports/customized_imports/sanam_customized_usage_parameters.py
@@ -0,0 +1,82 @@
+"""
+SanamCustomizedUsageParameters add two parameters to usage properties from ASHRAE
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+import sys
+import xmltodict
+from imports.geometry.helpers.geometry_helper import GeometryHelper as gh
+from imports.usage.data_classes.hft_usage_zone_archetype import HftUsageZoneArchetype as huza
+import helpers.constants as cte
+
+
+class SanamCustomizedUsageParameters:
+ """
+ SanamCustomizedUsageParameters class
+ """
+ def __init__(self, city, base_path):
+ 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
+
+ def enrich_buildings(self):
+ """
+ Returns the city with the usage parameters assigned to the buildings
+ :return:
+ """
+ city = self._city
+ for building in city.buildings:
+ 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:
+ sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
+ f' {building.function}, that assigns building usage as '
+ f'{gh.usage_from_function(building.function)}\n')
+ continue
+ mix_usage = False
+ if not mix_usage:
+ # just one usage_zone
+ for usage_zone in building.usage_zones:
+ self._assign_values(usage_zone, archetype, height)
+
+ def _search_archetype(self, building_usage):
+ for building_archetype in self._usage_archetypes:
+ if building_archetype.usage == building_usage:
+ return building_archetype
+ return None
+
+ @staticmethod
+ def _assign_values(usage_zone, archetype, height):
+ 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.
+ if archetype.occupancy_density is not None:
+ usage_zone.occupancy_density = archetype.occupancy_density
+ 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
+ def _parse_zone_usage_type(usage, zone_usage_type):
+ mechanical_air_change = zone_usage_type['endUses']['ventilation']['minimumVentilationRate']['#text']
+ if 'occupancy' in zone_usage_type:
+ occupancy_density = zone_usage_type['occupancy']['occupancyDensity']['#text']
+ usage_zone_archetype = huza(usage=usage, occupancy_density=occupancy_density,
+ mechanical_air_change=mechanical_air_change)
+ else:
+ usage_zone_archetype = huza(usage=usage, mechanical_air_change=mechanical_air_change)
+ return usage_zone_archetype
diff --git a/imports/customized_imports_factory.py b/imports/customized_imports_factory.py
new file mode 100644
index 00000000..bca8a87c
--- /dev/null
+++ b/imports/customized_imports_factory.py
@@ -0,0 +1,31 @@
+"""
+CustomizedImportsFactory is used to import any information using user customized formats
+This factory can only be called after calling the construction factory.
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+from pathlib import Path
+
+
+class CustomizedImportsFactory:
+ """
+ CustomizedImportsFactory class
+ """
+ def __init__(self, importer_class, city, base_path=None):
+ if base_path is None:
+ base_path = Path(Path(__file__).parent.parent / 'data/customized_imports')
+ self._importer_class = importer_class
+ self._city = city
+ self._base_path = base_path
+ for building in city.buildings:
+ if len(building.thermal_zones) == 0:
+ raise Exception('It seems that the customized imports factory is being called before the construction factory. '
+ 'Please ensure that the construction factory is called first.')
+
+ def enrich(self):
+ """
+ Returns the class that will enrich the city given
+ :return: Class
+ """
+ importer = self._importer_class(self._city, self._base_path)
+ return importer.enrich_buildings()
diff --git a/imports/geometry/obj.py b/imports/geometry/obj.py
index 5c7fdd5b..6349921b 100644
--- a/imports/geometry/obj.py
+++ b/imports/geometry/obj.py
@@ -21,8 +21,8 @@ class Obj:
with open(path, 'r') as file:
self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene')
self._corners = self._scene.bounds_corners
- _bound_corner_min = []
- _bound_corner_max = []
+ _bound_corner_min = None
+ _bound_corner_max = None
for corner in self._corners:
if _bound_corner_min is None:
_bound_corner_min = corner
diff --git a/imports/geometry/rhino.py b/imports/geometry/rhino.py
new file mode 100644
index 00000000..66f200d8
--- /dev/null
+++ b/imports/geometry/rhino.py
@@ -0,0 +1,77 @@
+"""
+Rhino module parses rhino files and import the geometry into the city model structure
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+"""
+from rhino3dm import *
+from rhino3dm._rhino3dm import MeshType
+import numpy as np
+
+import helpers.configuration_helper
+from city_model_structure.attributes.polygon import Polygon
+from city_model_structure.building import Building
+from city_model_structure.city import City
+from city_model_structure.building_demand.surface import Surface as LibsSurface
+from imports.geometry.helpers.geometry_helper import GeometryHelper
+from helpers.configuration_helper import ConfigurationHelper
+
+
+class Rhino:
+ def __init__(self, path):
+ self._model = File3dm.Read(str(path))
+ max_float = 1.7976931348623157e+308
+ min_float = -1.7976931348623157e+308
+ self._min_x = self._min_y = self._min_z = max_float
+ self._max_x = self._max_y = self._max_z = min_float
+ print('init')
+
+ @staticmethod
+ def _solid_points(coordinates) -> np.ndarray:
+ solid_points = np.fromstring(coordinates, dtype=float, sep=' ')
+ solid_points = GeometryHelper.to_points_matrix(solid_points)
+ return solid_points
+
+ def _lower_corner(self, x, y, z):
+ if x < self._min_x:
+ self._min_x = x
+ if y < self._min_y:
+ self._min_y = y
+ if z < self._min_z:
+ self._min_z = z
+ if x > self._max_x:
+ self._max_x = x
+ if y > self._max_y:
+ self._max_y = y
+ if z > self._max_z:
+ self._max_z = z
+
+ @property
+ def city(self) -> City:
+ buildings = []
+ print('city')
+ for obj in self._model.Objects:
+ name = obj.Attributes.Id
+ surfaces = []
+ for face in obj.Geometry.Faces:
+ if face is None:
+ break
+ _mesh = face.GetMesh(MeshType.Default)
+ for i in range(0, len(_mesh.Faces)):
+ faces = _mesh.Faces[i]
+ _points = ''
+
+ for index in faces:
+ self._lower_corner(_mesh.Vertices[index].X, _mesh.Vertices[index].Y, _mesh.Vertices[index].Z)
+ _points = _points + f'{_mesh.Vertices[index].X} {_mesh.Vertices[index].Y} {_mesh.Vertices[index].Z} '
+ polygon_points = Rhino._solid_points(_points.strip())
+ print(_points)
+ surfaces.append(LibsSurface(Polygon(polygon_points), Polygon(polygon_points)))
+ buildings.append(Building(name, 3, surfaces, 'unknown', 'unknown', (self._min_x, self._min_y, self._min_z), []))
+ lower_corner = (self._min_x, self._min_y, self._min_z)
+ upper_corner = (self._max_x, self._max_y, self._max_z)
+ city = City(lower_corner, upper_corner, 'Montreal')
+ for building in buildings:
+ city.add_city_object(building)
+ return city
+
+
diff --git a/imports/geometry_factory.py b/imports/geometry_factory.py
index ae2c3e29..da35c334 100644
--- a/imports/geometry_factory.py
+++ b/imports/geometry_factory.py
@@ -8,6 +8,7 @@ from city_model_structure.city import City
from imports.geometry.citygml import CityGml
from imports.geometry.obj import Obj
from imports.geometry.osm_subway import OsmSubway
+#from imports.geometry.rhino import Rhino
class GeometryFactory:
@@ -42,6 +43,14 @@ class GeometryFactory:
"""
return OsmSubway(self._path).city
+# @property
+# def _rhino(self) -> City:
+# """
+# Enrich the city by using OpenStreetMap information as data source
+# :return: City
+# """
+# return Rhino(self._path).city
+
@property
def city(self) -> City:
"""
@@ -49,3 +58,11 @@ class GeometryFactory:
:return: City
"""
return getattr(self, self._file_type, lambda: None)
+
+# @property
+# def city_debug(self) -> City:
+# """
+# Enrich the city given to the class using the class given handler
+# :return: City
+# """
+# return Rhino(self._path).city
diff --git a/imports/life_cycle_assessment/lca_fuel.py b/imports/life_cycle_assessment/lca_fuel.py
new file mode 100644
index 00000000..c35e0749
--- /dev/null
+++ b/imports/life_cycle_assessment/lca_fuel.py
@@ -0,0 +1,24 @@
+"""
+CityGml module parses citygml_classes files and import the geometry into the city model structure
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+import xmltodict
+from pathlib import Path
+from city_model_structure.fuel import Fuel
+
+class LcaFuel:
+ def __init__(self, city, base_path):
+ self._city = city
+ self._base_path = base_path
+ self._lca = None
+
+ def enrich(self):
+ self._city.fuels = []
+ path = Path(self._base_path / 'lca_data.xml').resolve()
+
+ with open(path) as xml:
+ self._lca = xmltodict.parse(xml.read())
+ for fuel in self._lca["library"]["Fuels"]['fuel']:
+ self._city.fuels.append(Fuel(fuel['@id'], fuel['@name'], fuel['carbon_emission_factor']['#text'],
+ fuel['carbon_emission_factor']['@unit']))
diff --git a/imports/life_cycle_assessment/lca_machine.py b/imports/life_cycle_assessment/lca_machine.py
new file mode 100644
index 00000000..0ecae0c8
--- /dev/null
+++ b/imports/life_cycle_assessment/lca_machine.py
@@ -0,0 +1,26 @@
+"""
+CityGml module parses citygml_classes files and import the geometry into the city model structure
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+import xmltodict
+from pathlib import Path
+from city_model_structure.machine import Machine
+
+class LcaMachine:
+ def __init__(self, city, base_path):
+ self._city = city
+ self._base_path = base_path
+ self._lca = None
+
+ def enrich(self):
+ self._city.machines = []
+ path = Path(self._base_path / 'lca_data.xml').resolve()
+
+ with open(path) as xml:
+ self._lca = xmltodict.parse(xml.read())
+ for machine in self._lca["library"]["Machines"]['machine']:
+ self._city.machines.append(Machine(machine['@id'], machine['@name'], machine['work_efficiency']['#text'],
+ machine['work_efficiency']['@unit'], machine['energy_consumption_rate']['#text'],
+ machine['energy_consumption_rate']['@unit'], machine['carbon_emission_factor']['#text'],
+ machine['carbon_emission_factor']['@unit']))
diff --git a/imports/life_cycle_assessment/lca_vehicle.py b/imports/life_cycle_assessment/lca_vehicle.py
new file mode 100644
index 00000000..55cef922
--- /dev/null
+++ b/imports/life_cycle_assessment/lca_vehicle.py
@@ -0,0 +1,25 @@
+"""
+CityGml module parses citygml_classes files and import the geometry into the city model structure
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+import xmltodict
+from pathlib import Path
+from city_model_structure.vehicle import Vehicle
+
+class LcaVehicle:
+ def __init__(self, city, base_path):
+ self._city = city
+ self._base_path = base_path
+ self._lca = None
+
+ def enrich(self):
+ self._city.vehicles = []
+ path = Path(self._base_path / 'lca_data.xml').resolve()
+
+ with open(path) as xml:
+ self._lca = xmltodict.parse(xml.read())
+ for vehicle in self._lca["library"]["Vehicles"]['vehicle']:
+ self._city.vehicles.append(Vehicle(vehicle['@id'], vehicle['@name'], vehicle['fuel_consumption_rate']['#text'],
+ vehicle['fuel_consumption_rate']['@unit'], vehicle['carbon_emission_factor']['#text'],
+ vehicle['carbon_emission_factor']['@unit']))
diff --git a/imports/life_cycle_assessment_factory.py b/imports/life_cycle_assessment_factory.py
new file mode 100644
index 00000000..66e1f609
--- /dev/null
+++ b/imports/life_cycle_assessment_factory.py
@@ -0,0 +1,54 @@
+"""
+ConstructionFactory (before PhysicsFactory) retrieve the specific construction module for the given region
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Atiya
+"""
+
+from pathlib import Path
+from imports.life_cycle_assessment.lca_fuel import LcaFuel
+from imports.life_cycle_assessment.lca_vehicle import LcaVehicle
+from imports.life_cycle_assessment.lca_machine import LcaMachine
+# from imports.life_cycle_assessment.lca_material import LcaMaterial
+
+
+class LifeCycleAssessment:
+ """
+ Life cicle analize factory class
+ """
+ def __init__(self, handler, city, base_path=None):
+ if base_path is None:
+ base_path = Path(Path(__file__).parent.parent / 'data/life_cycle_assessment')
+ self._handler = '_' + handler.lower().replace(' ', '_')
+ self._city = city
+ self._base_path = base_path
+
+ def _fuel(self):
+ """
+ Enrich the city by adding the fuel carbon information
+ """
+ LcaFuel(self._city, self._base_path).enrich()
+
+ def _vehicle(self):
+ """
+ Enrich the city by adding the vehicle carbon information
+ """
+ LcaVehicle(self._city, self._base_path).enrich()
+
+ def _machine(self):
+ """
+ Enrich the city by adding the machine carbon information
+ """
+ LcaMachine(self._city, self._base_path).enrich()
+
+ def _material(self):
+ """
+ Enrich the city by adding the material carbon information
+ """
+ LcaMaterial(self._city, self._base_path).enrich()
+
+ def enrich(self):
+ """
+ Enrich the city given to the class using the class given handler
+ :return: None
+ """
+ getattr(self, self._handler, lambda: None)()
diff --git a/imports/schedules/helpers/schedules_helper.py b/imports/schedules/helpers/schedules_helper.py
index a36c2fa6..fa47b343 100644
--- a/imports/schedules/helpers/schedules_helper.py
+++ b/imports/schedules/helpers/schedules_helper.py
@@ -33,28 +33,26 @@ class SchedulesHelper:
# usage
function_to_usage = {
- 'full service restaurant': 'restaurant',
+ 'full service restaurant': cte.RESTAURANT,
'high-rise apartment': cte.RESIDENTIAL,
- 'hospital': 'health care',
- 'large hotel': 'hotel',
- 'large office': 'office and administration',
- 'medium office': 'office and administration',
+ 'hospital': cte.HEALTH_CARE,
+ 'large hotel': cte.HOTEL,
+ 'large office': cte.OFFICE_ADMINISTRATION,
+ 'medium office': cte.OFFICE_ADMINISTRATION,
'midrise apartment': cte.RESIDENTIAL,
- 'outpatient healthcare': 'health care',
- 'primary school': 'education',
- 'quick service restaurant': 'restaurant',
- 'secondary school': 'education',
- 'small hotel': 'hotel',
- 'small office': 'office and administration',
- 'stand-alone-retail': 'retail',
- 'strip mall': 'hall',
- 'supermarket': 'retail',
- 'warehouse': 'industry',
+ 'outpatient healthcare': cte.HEALTH_CARE,
+ 'primary school': cte.EDUCATION,
+ 'quick service restaurant': cte.RESTAURANT,
+ 'secondary school': cte.EDUCATION,
+ 'small hotel': cte.HOTEL,
+ 'small office': cte.OFFICE_ADMINISTRATION,
+ 'stand-alone-retail': cte.RETAIL,
+ 'strip mall': cte.HALL,
+ 'supermarket': cte.RETAIL,
+ 'warehouse': cte.INDUSTRY,
'residential': cte.RESIDENTIAL
}
-
-
@staticmethod
def comnet_from_usage(usage):
"""
diff --git a/imports/usage/ashrae_usage_parameters.py b/imports/usage/ashrae_usage_parameters.py
deleted file mode 100644
index 1bfb98bd..00000000
--- a/imports/usage/ashrae_usage_parameters.py
+++ /dev/null
@@ -1,55 +0,0 @@
-"""
-AshraeUsageParameters model the usage properties
-SPDX - License - Identifier: LGPL - 3.0 - or -later
-Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
-"""
-import sys
-
-from imports.geometry.helpers.geometry_helper import GeometryHelper as gh
-from city_model_structure.building_demand.usage_zone import UsageZone
-
-
-class AshraeUsageParameters:
- """
- AshraeUsageParameters class
- """
- def __init__(self, city, base_path):
- super().__init__(base_path, 'ashrae_archetypes.xml')
- self._city = city
- self._usage_archetypes = None
-
- def enrich_buildings(self):
- """
- Returns the city with the usage parameters assigned to the buildings
- :return:
- """
- city = self._city
- for building in city.buildings:
- archetype = self._search_archetype(building.function)
- if archetype is None:
- sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
- f' {building.function}, that assigns building usage as '
- f'{gh.usage_from_function(building.function)}\n')
- continue
- # todo: what to do with mix-usage usage from gml?
- mix_usage = False
- if not mix_usage:
- # just one usage_zone
- for thermal_zone in building.thermal_zones:
- usage_zone = UsageZone()
- usage_zone.volume = thermal_zone.volume
- self._assign_values(usage_zone, archetype)
- thermal_zone.usage_zones = [usage_zone]
-
- def _search_archetype(self, building_usage):
- for building_archetype in self._usage_archetypes:
- if building_archetype.usage == building_usage:
- return building_archetype
- return None
-
- @staticmethod
- def _assign_values(usage_zone, archetype):
- usage_zone.usage = archetype.usage
- usage_zone.occupancy_density = archetype.occupancy_density
- # todo: should I use this value: self._min_air_change??
- usage_zone.minimum_ventilation_rate = archetype.minimum_ventilation_rate
diff --git a/imports/usage/ca_usage_parameters.py b/imports/usage/ca_usage_parameters.py
index 1bbe5d58..01cc85a5 100644
--- a/imports/usage/ca_usage_parameters.py
+++ b/imports/usage/ca_usage_parameters.py
@@ -41,8 +41,8 @@ class CaUsageParameters(HftUsageInterface):
# just one usage_zone
for thermal_zone in building.thermal_zones:
usage_zone = UsageZone()
- usage_zone.volume = thermal_zone.volume
self._assign_values(usage_zone, archetype)
+ usage_zone.volume = thermal_zone.volume
thermal_zone.usage_zones = [usage_zone]
def _search_archetype(self, building_usage):
diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py
new file mode 100644
index 00000000..5d10312c
--- /dev/null
+++ b/imports/usage/comnet_usage_parameters.py
@@ -0,0 +1,162 @@
+"""
+ComnetUsageParameters model the usage properties
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+import sys
+from typing import Dict
+import pandas as pd
+
+import helpers.constants as cte
+from helpers.configuration_helper import ConfigurationHelper as ch
+from imports.geometry.helpers.geometry_helper import GeometryHelper
+from imports.usage.helpers.usage_helper import UsageHelper
+from city_model_structure.building_demand.usage_zone import UsageZone
+from city_model_structure.building_demand.internal_gains import InternalGains
+from imports.usage.data_classes.hft_usage_zone_archetype import HftUsageZoneArchetype as huza
+from imports.usage.data_classes.hft_internal_gains_archetype import HftInternalGainsArchetype as higa
+
+
+class ComnetUsageParameters:
+ """
+ ComnetUsageParameters class
+ """
+ def __init__(self, city, base_path):
+ self._city = city
+ self._base_path = str(base_path / 'comnet_archetypes.xlsx')
+ self._usage_archetypes = []
+ data = self._read_file()
+ for item in data['lighting']:
+ for usage in UsageHelper.usage_to_comnet:
+ comnet_usage = UsageHelper.usage_to_comnet[usage]
+ if comnet_usage == item:
+ usage_archetype = self._parse_zone_usage_type(comnet_usage, data)
+ self._usage_archetypes.append(usage_archetype)
+
+ def _read_file(self) -> Dict:
+ """
+ reads xlsx file containing usage information into a dictionary
+ :return : Dict
+ """
+ number_usage_types = 33
+ xl_file = pd.ExcelFile(self._base_path)
+ file_data = pd.read_excel(xl_file, sheet_name="Modeling Data", skiprows=[0, 1, 2],
+ nrows=number_usage_types, usecols="A:Z")
+
+ lighting_data = {}
+ plug_loads_data = {}
+ occupancy_data = {}
+ ventilation_rate = {}
+ water_heating = {}
+ process_data = {}
+
+ for j in range(0, number_usage_types):
+ usage_parameters = file_data.iloc[j]
+ usage_type = usage_parameters[0]
+ lighting_data[usage_type] = usage_parameters[1:6].values.tolist()
+ plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist()
+ occupancy_data[usage_type] = usage_parameters[17:20].values.tolist()
+ ventilation_rate[usage_type] = usage_parameters[20:21].values.tolist()
+ water_heating[usage_type] = usage_parameters[23:24].values.tolist()
+ process_data[usage_type] = usage_parameters[24:26].values.tolist()
+
+ return {'lighting': lighting_data,
+ 'plug loads': plug_loads_data,
+ 'occupancy': occupancy_data,
+ 'ventilation rate': ventilation_rate,
+ 'water heating': water_heating,
+ 'process': process_data}
+
+ @staticmethod
+ def _parse_zone_usage_type(usage, data):
+ if data['occupancy'][usage][0] <= 0:
+ occupancy_density = 0
+ else:
+ occupancy_density = 1 / data['occupancy'][usage][0]
+ mechanical_air_change = data['ventilation rate'][usage][0]
+ internal_gains = []
+ # lighting
+ latent_fraction = ch().comnet_lighting_latent
+ convective_fraction = ch().comnet_lighting_convective
+ radiative_fraction = ch().comnet_lighting_radiant
+ average_internal_gain = data['lighting'][usage][4]
+ internal_gains.append(higa(internal_gains_type=cte.LIGHTING, average_internal_gain=average_internal_gain,
+ convective_fraction=convective_fraction, radiative_fraction=radiative_fraction,
+ latent_fraction=latent_fraction))
+ # occupancy
+ latent_fraction = data['occupancy'][usage][2] / (data['occupancy'][usage][1] + data['occupancy'][usage][2])
+ sensible_fraction = float(1 - latent_fraction)
+ convective_fraction = sensible_fraction * ch().comnet_occupancy_sensible_convective
+ radiative_fraction = sensible_fraction * ch().comnet_occupancy_sensible_radiant
+ average_internal_gain = (data['occupancy'][usage][1] + data['occupancy'][usage][2]) \
+ * occupancy_density * cte.BTU_H_TO_WATTS
+ internal_gains.append(higa(internal_gains_type=cte.OCCUPANCY, average_internal_gain=average_internal_gain,
+ convective_fraction=convective_fraction, radiative_fraction=radiative_fraction,
+ latent_fraction=latent_fraction))
+ # plug loads
+ if data['plug loads'][usage][0] != 'n.a.':
+ latent_fraction = ch().comnet_plugs_latent
+ convective_fraction = ch().comnet_plugs_convective
+ radiative_fraction = ch().comnet_plugs_radiant
+ average_internal_gain = data['plug loads'][usage][0]
+ internal_gains.append(higa(internal_gains_type=cte.RECEPTACLE, average_internal_gain=average_internal_gain,
+ convective_fraction=convective_fraction, radiative_fraction=radiative_fraction,
+ latent_fraction=latent_fraction))
+
+ usage_zone_archetype = huza(usage=usage, internal_gains=internal_gains,
+ occupancy_density=occupancy_density,
+ mechanical_air_change=mechanical_air_change)
+ return usage_zone_archetype
+
+ def enrich_buildings(self):
+ """
+ Returns the city with the usage parameters assigned to the buildings
+ :return:
+ """
+ city = self._city
+ for building in city.buildings:
+ usage = GeometryHelper.usage_from_function(building.function)
+ 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')
+ archetype = self._search_archetype(UsageHelper.comnet_from_usage(usage))
+ if archetype is None:
+ sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
+ f' {building.function}, that assigns building usage as '
+ f'{GeometryHelper.usage_from_function(building.function)}\n')
+ continue
+
+ # just one usage_zone
+ for thermal_zone in building.thermal_zones:
+ usage_zone = UsageZone()
+ usage_zone.usage = usage
+ self._assign_values(usage_zone, archetype, height)
+ usage_zone.volume = thermal_zone.volume
+ thermal_zone.usage_zones = [usage_zone]
+
+ def _search_archetype(self, building_usage):
+ for building_archetype in self._usage_archetypes:
+ if building_archetype.usage == building_usage:
+ return building_archetype
+ return None
+
+ @staticmethod
+ def _assign_values(usage_zone, archetype, height):
+ # 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.
+ internal_gains = []
+ for archetype_internal_gain in archetype.internal_gains:
+ internal_gain = InternalGains()
+ internal_gain.type = archetype_internal_gain.type
+ internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain * cte.METERS_TO_FEET**2
+ internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
+ internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
+ internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
+ internal_gains.append(internal_gain)
+ usage_zone.internal_gains = internal_gains
+ usage_zone.occupancy_density = archetype.occupancy_density * cte.METERS_TO_FEET**2
+ usage_zone.mechanical_air_change = archetype.mechanical_air_change * usage_zone.occupancy_density \
+ * cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET**3 / height
diff --git a/imports/usage/data_classes/hft_internal_gains_archetype.py b/imports/usage/data_classes/hft_internal_gains_archetype.py
index c9de13b0..cc21a77a 100644
--- a/imports/usage/data_classes/hft_internal_gains_archetype.py
+++ b/imports/usage/data_classes/hft_internal_gains_archetype.py
@@ -9,13 +9,30 @@ class HftInternalGainsArchetype:
"""
HftInternalGainsArchetype class
"""
- def __init__(self, average_internal_gain=None, convective_fraction=None, radiative_fraction=None,
- latent_fraction=None):
+ def __init__(self, internal_gains_type=None, average_internal_gain=None, convective_fraction=None, \
+ radiative_fraction=None, latent_fraction=None):
+ self._type = internal_gains_type
self._average_internal_gain = average_internal_gain
self._convective_fraction = convective_fraction
self._radiative_fraction = radiative_fraction
self._latent_fraction = latent_fraction
+ @property
+ def type(self):
+ """
+ Get internal gains type
+ :return: string
+ """
+ return self._type
+
+ @type.setter
+ def type(self, value):
+ """
+ Set internal gains type
+ :param value: string
+ """
+ self._type = value
+
@property
def average_internal_gain(self):
"""
diff --git a/imports/usage/helpers/usage_helper.py b/imports/usage/helpers/usage_helper.py
index b46b08d3..310b4888 100644
--- a/imports/usage/helpers/usage_helper.py
+++ b/imports/usage/helpers/usage_helper.py
@@ -36,3 +36,29 @@ class UsageHelper:
except KeyError:
sys.stderr.write('Error: keyword not found. Returned default HfT usage "residential"\n')
return UsageHelper.hft_default_value
+
+ usage_to_comnet = {
+ cte.RESIDENTIAL: 'BA Multifamily',
+ cte.INDUSTRY: 'BA Manufacturing Facility',
+ cte.OFFICE_ADMINISTRATION: 'BA Office',
+ cte.HOTEL: 'BA Hotel',
+ cte.HEALTH_CARE: 'BA Hospital',
+ cte.RETAIL: 'BA Retail',
+ cte.HALL: 'BA Town Hall',
+ cte.RESTAURANT: 'BA Dining: Bar Lounge/Leisure',
+ cte.EDUCATION: 'BA School/University'
+ }
+ comnet_default_value = 'BA Multifamily'
+
+ @staticmethod
+ def comnet_from_usage(usage):
+ """
+ Get Comnet usage from the given internal usage key
+ :param usage: str
+ :return: str
+ """
+ try:
+ return UsageHelper.usage_to_comnet[usage]
+ except KeyError:
+ sys.stderr.write('Error: keyword not found. Returned default Comnet usage "BA Multifamily"\n')
+ return UsageHelper.comnet_default_value
diff --git a/imports/usage/hft_usage_interface.py b/imports/usage/hft_usage_interface.py
index b6223295..3da6457d 100644
--- a/imports/usage/hft_usage_interface.py
+++ b/imports/usage/hft_usage_interface.py
@@ -68,7 +68,8 @@ class HftUsageInterface:
average_internal_gain = 0
radiative_fraction = 0
- internal_gains.append(higa(average_internal_gain, convective_fraction, radiative_fraction, latent_fraction))
+ internal_gains.append(higa(average_internal_gain=average_internal_gain, convective_fraction=convective_fraction,
+ radiative_fraction=radiative_fraction, latent_fraction=latent_fraction))
usage_zone_archetype = huza(usage=usage, internal_gains=internal_gains, heating_set_point=heating_setpoint,
heating_set_back=heating_setback, cooling_set_point=cooling_setpoint,
occupancy_density=occupancy_density, hours_day=hours_day, days_year=days_year,
@@ -130,7 +131,8 @@ class HftUsageInterface:
average_internal_gain = usage_zone_variant['schedules']['internGains']['averageInternGainPerSqm']
if 'radiantFraction' in usage_zone_variant['schedules']['internGains']:
radiative_fraction = usage_zone_variant['schedules']['internGains']['radiantFraction']
- internal_gains.append(higa(average_internal_gain, convective_fraction, radiative_fraction, latent_fraction))
+ internal_gains.append(higa(average_internal_gain=average_internal_gain, convective_fraction=convective_fraction,
+ radiative_fraction=radiative_fraction, latent_fraction=latent_fraction))
usage_zone_archetype = huza(usage=usage, internal_gains=internal_gains, heating_set_point=heating_setpoint,
heating_set_back=heating_setback, cooling_set_point=cooling_setpoint,
occupancy_density=occupancy_density, hours_day=hours_day, days_year=days_year,
diff --git a/imports/usage_factory.py b/imports/usage_factory.py
index 763a6dba..0e2875de 100644
--- a/imports/usage_factory.py
+++ b/imports/usage_factory.py
@@ -8,7 +8,7 @@ Contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
from pathlib import Path
from imports.usage.hft_usage_parameters import HftUsageParameters
from imports.usage.ca_usage_parameters import CaUsageParameters
-from imports.usage.ashrae_usage_parameters import AshraeUsageParameters
+from imports.usage.comnet_usage_parameters import ComnetUsageParameters
# todo: handle missing lambda and rise error.
@@ -39,11 +39,11 @@ class UsageFactory:
"""
return CaUsageParameters(self._city, self._base_path).enrich_buildings()
- def _ashrae(self):
+ def _comnet(self):
"""
- Enrich the city by using ASHRAE information
+ Enrich the city with COMNET usage library
"""
- AshraeUsageParameters(self._city, self._base_path).enrich_buildings()
+ return ComnetUsageParameters(self._city, self._base_path).enrich_buildings()
def enrich(self):
"""
diff --git a/requirements.txt b/requirements.txt
index 8a6287d3..15593f09 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,9 +9,9 @@ geomeppy~=0.11.8
pathlib~=1.0.1
PyWavefront~=1.3.3
xlrd~=2.0.1
-openpyxl~=3.0.7
networkx~=2.5.1
parseidf~=1.0.0
ply~=3.11
scipy==1.7.1
-PyYAML==6.0
\ No newline at end of file
+PyYAML==6.0
+rhino3dm~=7.7.0
\ No newline at end of file
diff --git a/unittests/test_customized_imports_factory.py b/unittests/test_customized_imports_factory.py
new file mode 100644
index 00000000..80373480
--- /dev/null
+++ b/unittests/test_customized_imports_factory.py
@@ -0,0 +1,49 @@
+"""
+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.usage_factory import UsageFactory
+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()
+ UsageFactory('hft', _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')
diff --git a/unittests/test_exports.py b/unittests/test_exports.py
index 5b25b4e1..b4c38be1 100644
--- a/unittests/test_exports.py
+++ b/unittests/test_exports.py
@@ -45,7 +45,7 @@ class TestExports(TestCase):
else:
file_path = (self._example_path / 'one_building_in_kelowna.gml').resolve()
self._complete_city = self._get_citygml(file_path)
- ConstructionFactory('ca', self._complete_city).enrich()
+ ConstructionFactory('nrel', self._complete_city).enrich()
UsageFactory('ca', self._complete_city).enrich()
SchedulesFactory('comnet', self._complete_city).enrich()
cli = 'C:\\Users\\Pilar\\PycharmProjects\\monthlyenergybalance\\tests_data\\weather\\inseldb_Summerland.cli'
diff --git a/unittests/test_life_cycle_assessment_factory.py b/unittests/test_life_cycle_assessment_factory.py
new file mode 100644
index 00000000..3245d56b
--- /dev/null
+++ b/unittests/test_life_cycle_assessment_factory.py
@@ -0,0 +1,58 @@
+"""
+Building test
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Guille Gutierrez Morote Guillermo.GutierrezMorote@concordia.ca
+"""
+from pathlib import Path
+from unittest import TestCase
+from imports.geometry_factory import GeometryFactory
+from imports.life_cycle_assessment_factory import LifeCycleAssessment
+
+
+class TestLifeCycleAssessment(TestCase):
+ """
+ TestBuilding TestCase 1
+ """
+ def setUp(self) -> None:
+ """
+ Test setup
+ :return: None
+ """
+ self._city_gml = None
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
+
+ def test_fuel(self):
+ city_file = "../unittests/tests_data/C40_Final.gml"
+ city = GeometryFactory('citygml', city_file).city
+ LifeCycleAssessment('fuel', city).enrich()
+ for fuel in city.fuels:
+ # print(fuel.name)
+ self.assertTrue(len(city.fuels) > 0)
+
+ def test_vehicle(self):
+ city_file = "../unittests/tests_data/C40_Final.gml"
+ city = GeometryFactory('citygml', city_file).city
+ LifeCycleAssessment('vehicle', city).enrich()
+ for vehicle in city.vehicles:
+ # print(vehicle.name)
+ self.assertTrue(len(city.vehicles) > 0)
+
+ def test_machine(self):
+ city_file = "../unittests/tests_data/C40_Final.gml"
+ city = GeometryFactory('citygml', city_file).city
+ LifeCycleAssessment('machine', city).enrich()
+ for machine in city.machines:
+ # print(machine.name)
+ self.assertTrue(len(city.machines) > 0)
+
+ def test_material(self):
+ city_file = "../unittests/tests_data/C40_Final.gml"
+ city = GeometryFactory('citygml', city_file).city
+ LifeCycleAssessment('material', city).enrich()
+ for material in city.materials:
+ print(material.material_name)
+ self.assertTrue(len(city.materials) > 0)
+
+
+
+
diff --git a/unittests/test_usage_factory.py b/unittests/test_usage_factory.py
index 82c692a1..7281f86d 100644
--- a/unittests/test_usage_factory.py
+++ b/unittests/test_usage_factory.py
@@ -9,6 +9,7 @@ from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.usage_factory import UsageFactory
from imports.geometry.helpers.geometry_helper import GeometryHelper
+from imports.construction_factory import ConstructionFactory
class TestUsageFactory(TestCase):
@@ -38,7 +39,7 @@ class TestUsageFactory(TestCase):
city = self._get_citygml(file)
for building in city.buildings:
building.function = GeometryHelper.pluto_to_function[building.function]
-
+ ConstructionFactory('nrel', city).enrich()
UsageFactory('hft', city).enrich()
for building in city.buildings:
self.assertIsNot(len(building.usage_zones), 0, 'no building usage_zones defined')
@@ -61,7 +62,7 @@ class TestUsageFactory(TestCase):
# case 2: CA
file = 'one_building_in_kelowna.gml'
city = self._get_citygml(file)
-
+ ConstructionFactory('nrel', city).enrich()
UsageFactory('ca', city).enrich()
for building in city.buildings:
self.assertIsNot(len(building.usage_zones), 0, 'no building usage_zones defined')
diff --git a/unittests/tests_data/lca_data.xml b/unittests/tests_data/lca_data.xml
new file mode 100644
index 00000000..bc3ab8ee
--- /dev/null
+++ b/unittests/tests_data/lca_data.xml
@@ -0,0 +1,573 @@
+
+
+
+
+ 0.32
+
+
+ 0.4
+
+
+ 0.4
+
+
+ 0.5
+
+
+ 0.18
+
+
+ 0.39
+
+
+ 0.27
+
+
+ 4.16
+
+
+ 2.24
+
+
+ 0.2
+
+
+ 3.19
+
+
+ 3.53
+
+
+ 0.27
+
+
+ 0.21
+
+
+ 1.69
+
+
+ 0.21
+
+
+ 0.35
+
+
+ 0.18
+
+
+ 0.81
+
+
+ 1.21
+
+
+ 1.61
+
+
+ 0.11
+
+
+ 0.3
+
+
+ 1.16
+
+
+ 0.61
+
+
+
+
+ 0.347
+ 16.5
+ 0.918
+
+
+ 0.033
+ 25.2
+ 4.16
+
+
+ 0.027
+ 16.8
+ 2.239
+
+
+ 0.023
+ 16.8
+ 2.239
+
+
+ 0.109
+ 25.2
+ 2.239
+
+
+ 0.003
+ 16.4
+ 4.16
+
+
+ 0.002
+ 11
+ 0.918
+
+
+ 0.002
+ 90
+ 0.918
+
+
+ 0.002
+ 10
+ 0.918
+
+
+ 0.002
+ 11
+ 0.918
+
+
+ 0.002
+ 132
+ 0.918
+
+
+ 0.002
+ 15
+ 0.918
+
+
+ 0.002
+ 5.5
+ 0.918
+
+
+ 0.002
+ 22.5
+ 0.918
+
+
+
+
+ 0.0123
+ 2.239
+
+
+ 0.042
+ 0.918
+
+
+ 0.01
+ 1.00000
+
+
+ 1.3
+ 1.00000
+
+
+
+
+
+ 1.8
+ 560
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+ 1.2
+ 310
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+ 2
+ 3080
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+ 1.4
+ 300
+ 0.8
+ 0.3
+ 0.7
+ 0.2
+ ....
+
+
+
+
+ 1.6
+ 900
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.6
+ 2340
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.6
+ 1570
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.4
+ 1840
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.3
+ 410
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 160
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 170
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 230
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.4
+ 240
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.4
+ 280
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.3
+ 170
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.2
+ 440
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+
+
+ 2.58
+ 2660
+ 0.95
+ 0
+ 1
+ 0.05
+ ....
+
+
+ 2.58
+ 5260
+ 0.95
+ 0
+ 1
+ 0.05
+ ....
+
+
+
+
+ 0.06
+ 1760
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.122
+ 3080
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.028
+ 3180
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.024
+ 5140
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.1
+ 6040
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.3
+ 5380
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+ 0.032
+ 2150
+ 0.9
+ 0
+ 1
+ 0.1
+ ....
+
+
+
+
+ 0.9
+ 3420
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+ 0.7
+ 1430
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+ 0.65
+ 2780
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+ 0.72
+ 2190
+ 0.6
+ 0
+ 1
+ 0.4
+ ....
+
+
+
+
+ 1.43
+ 1070
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.43
+ 240
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.43
+ 430
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.43
+ 340
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.2
+ 440
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 2.1
+ 1410
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.43
+ 250
+ 0
+ 0
+ 0
+ 1
+ ....
+
+
+ 1.44
+ 1480
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.44
+ 2220
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.27
+ 3960
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+ 1.15
+ 760
+ 0.8
+ 0
+ 1
+ 0.2
+ ....
+
+
+
+
+ 8
+ 3160
+ 0.98
+ 0
+ 1
+ 0.02
+ ....
+
+
+ 2.7
+ 5370
+ 0.98
+ 0
+ 1
+ 0.02
+ ....
+
+
+ 7.85
+ 3910
+ 0.98
+ 0
+ 1
+ 0.02
+ ....
+
+
+
+
\ No newline at end of file