forked from s_ranjbar/city_retrofit
reorganized the exports factories
This commit is contained in:
parent
f387a4be4e
commit
07e2ee9773
|
@ -1,9 +1,7 @@
|
|||
import numpy as np
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
import csv
|
||||
|
||||
from exports.insel.insel import Insel
|
||||
from exports.formats.insel import Insel
|
||||
from imports.weather.helpers.weather import Weather
|
||||
import helpers.constants as cte
|
||||
|
||||
|
@ -18,10 +16,10 @@ _CONSTRUCTION_CODE = {
|
|||
}
|
||||
|
||||
|
||||
class MonthlyEnergyBalance(Insel):
|
||||
class InselMonthlyEnergyBalance(Insel):
|
||||
|
||||
def __init__(self, city, path, radiation_calculation_method='sra', weather_format='epw'):
|
||||
super().__init__(city, path, False)
|
||||
super().__init__(city, path)
|
||||
self._radiation_calculation_method = radiation_calculation_method
|
||||
self._weather_format = weather_format
|
||||
self._contents = []
|
||||
|
@ -41,26 +39,6 @@ class MonthlyEnergyBalance(Insel):
|
|||
insel_file.write(content)
|
||||
return
|
||||
|
||||
def results(self, insel_outputs_paths):
|
||||
monthly_heatings = []
|
||||
monthly_coolings = []
|
||||
for insel_outputs_path in insel_outputs_paths:
|
||||
heating = []
|
||||
cooling = []
|
||||
with open(Path(insel_outputs_path).resolve()) as csv_file:
|
||||
csv_reader = csv.reader(csv_file)
|
||||
for line in csv_reader:
|
||||
demand = str(line).replace("['", '').replace("']", '').split()
|
||||
for i in range(0, 2):
|
||||
if demand[i] != 'NaN':
|
||||
aux = float(demand[i]) * 1000 # kWh to Wh
|
||||
demand[i] = str(aux)
|
||||
heating.append(demand[0])
|
||||
cooling.append(demand[1])
|
||||
monthly_heatings.append(pd.DataFrame(heating, columns=['INSEL']))
|
||||
monthly_coolings.append(pd.DataFrame(cooling, columns=['INSEL']))
|
||||
return monthly_heatings, monthly_coolings
|
||||
|
||||
@staticmethod
|
||||
def generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format):
|
||||
file = ""
|
||||
|
@ -174,7 +152,8 @@ class MonthlyEnergyBalance(Insel):
|
|||
for i, surface in enumerate(surfaces):
|
||||
i_block = 101 + i
|
||||
inputs = ['1 % Monthly surface radiation (W/sqm)']
|
||||
parameters = [f'12 % Azimuth {np.rad2deg(surface.azimuth)}, inclination {np.rad2deg(surface.inclination)} degrees']
|
||||
parameters = [f'12 % Azimuth {np.rad2deg(surface.azimuth)}, '
|
||||
f'inclination {np.rad2deg(surface.inclination)} degrees']
|
||||
|
||||
if surface.type != 'Ground':
|
||||
global_irradiance = surface.global_irradiance[cte.MONTH]
|
74
exports/energy_building_exports_factory.py
Normal file
74
exports/energy_building_exports_factory.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
"""
|
||||
EnergyBuildingsExportsFactory exports a city into several formats related to energy in buildings
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from exports.building_energy.energy_ade import EnergyAde
|
||||
from exports.building_energy.idf import Idf
|
||||
from exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
|
||||
|
||||
|
||||
class EnergyBuildingsExportsFactory:
|
||||
"""
|
||||
Energy Buildings exports factory class
|
||||
"""
|
||||
def __init__(self, export_type, city, path, target_buildings=None, adjacent_buildings=None):
|
||||
self._city = city
|
||||
self._export_type = '_' + export_type.lower()
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
self._path = path
|
||||
self._target_buildings = target_buildings
|
||||
self._adjacent_buildings = adjacent_buildings
|
||||
|
||||
@property
|
||||
def _energy_ade(self):
|
||||
"""
|
||||
Export to citygml with application domain extensions
|
||||
:return: None
|
||||
"""
|
||||
return EnergyAde(self._city, self._path)
|
||||
|
||||
@property
|
||||
def _idf(self):
|
||||
"""
|
||||
Export the city to Energy+ idf format
|
||||
|
||||
When target_buildings is set, only those will be calculated and their energy consumption output, non adjacent
|
||||
buildings will be considered shading objects and adjacent buildings will be considered adiabatic.
|
||||
|
||||
Adjacent buildings are provided they will be considered heated so energy plus calculations are more precise but
|
||||
no results will be calculated to speed up the calculation process.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
idf_data_path = (Path(__file__).parent / './building_energy/idf_files/').resolve()
|
||||
# todo: create a get epw file function based on the city
|
||||
weather_path = (Path(__file__).parent / '../data/weather/epw/CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve()
|
||||
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'), weather_path,
|
||||
target_buildings=self._target_buildings, adjacent_buildings=self._adjacent_buildings)
|
||||
|
||||
@property
|
||||
def _insel_monthly_energy_balance(self):
|
||||
"""
|
||||
Export to Insel MonthlyEnergyBalance
|
||||
:return: None
|
||||
"""
|
||||
return InselMonthlyEnergyBalance(self._city, self._path)
|
||||
|
||||
def export(self):
|
||||
"""
|
||||
Export the city given to the class using the given export type handler
|
||||
:return: None
|
||||
"""
|
||||
return getattr(self, self._export_type, lambda: None)
|
||||
|
||||
def export_debug(self):
|
||||
"""
|
||||
Export the city given to the class using the given export type handler
|
||||
:return: None
|
||||
"""
|
||||
return getattr(self, self._export_type)
|
|
@ -6,8 +6,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from exports.formats.energy_ade import EnergyAde
|
||||
from exports.formats.idf import Idf
|
||||
from exports.formats.obj import Obj
|
||||
from exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
|
||||
from exports.formats.stl import Stl
|
||||
|
@ -38,14 +36,6 @@ class ExportsFactory:
|
|||
def _collada(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def _energy_ade(self):
|
||||
"""
|
||||
Export to citygml with application domain extensions
|
||||
:return: None
|
||||
"""
|
||||
return EnergyAde(self._city, self._path)
|
||||
|
||||
@property
|
||||
def _stl(self):
|
||||
"""
|
||||
|
@ -70,25 +60,6 @@ class ExportsFactory:
|
|||
"""
|
||||
return Obj(self._city, self._path).to_ground_points()
|
||||
|
||||
@property
|
||||
def _idf(self):
|
||||
"""
|
||||
Export the city to Energy+ idf format
|
||||
|
||||
When target_buildings is set, only those will be calculated and their energy consumption output, non adjacent
|
||||
buildings will be considered shading objects and adjacent buildings will be considered adiabatic.
|
||||
|
||||
Adjacent buildings are provided they will be considered heated so energy plus calculations are more precise but
|
||||
no results will be calculated to speed up the calculation process.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
idf_data_path = (Path(__file__).parent / './formats/idf_files/').resolve()
|
||||
# todo: create a get epw file function based on the city
|
||||
weather_path = (Path(__file__).parent / '../data/weather/epw/CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve()
|
||||
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'), weather_path,
|
||||
target_buildings=self._target_buildings, adjacent_buildings=self._adjacent_buildings)
|
||||
|
||||
@property
|
||||
def _sra(self):
|
||||
"""
|
||||
|
|
|
@ -6,16 +6,13 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|||
"""
|
||||
|
||||
from abc import ABC
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Insel(ABC):
|
||||
def __init__(self, city, path, keep_files=False):
|
||||
def __init__(self, city, path):
|
||||
self._city = city
|
||||
self._path = path
|
||||
self._results = None
|
||||
self._keep_files = keep_files
|
||||
|
||||
@staticmethod
|
||||
def _add_block(file, block_number, block_type, inputs='', parameters=''):
|
||||
|
@ -28,16 +25,6 @@ class Insel(ABC):
|
|||
file += str(block_parameter) + "\n"
|
||||
return file
|
||||
|
||||
def run(self, insel_models):
|
||||
for insel_model in insel_models:
|
||||
finish = os.system('insel ' + str(Path(insel_model).resolve()))
|
||||
os.close(finish)
|
||||
if not self._keep_files:
|
||||
os.remove((Path(self._path) / insel_model).resolve())
|
||||
|
||||
def results(self, insel_models):
|
||||
raise NotImplementedError
|
||||
|
||||
def _export(self):
|
||||
raise NotImplementedError
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
"""
|
||||
InselExportsFactory export a city into several formats
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from exports.insel.templates.monthly_energy_balance import MonthlyEnergyBalance
|
||||
|
||||
|
||||
class InselExportsFactory:
|
||||
"""
|
||||
Insel exports factory class
|
||||
"""
|
||||
def __init__(self, export_type, city, path):
|
||||
self._city = city
|
||||
self._export_type = '_' + export_type.lower()
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
self._path = path
|
||||
|
||||
@property
|
||||
def _monthly_energy_balance(self):
|
||||
"""
|
||||
Export to Insel MonthlyEnergyBalance
|
||||
:return: None
|
||||
"""
|
||||
return MonthlyEnergyBalance(self._city, self._path)
|
||||
|
||||
def export(self):
|
||||
"""
|
||||
Export the city given to the class using the given export type handler
|
||||
:return: None
|
||||
"""
|
||||
return getattr(self, self._export_type, lambda: None)
|
||||
|
||||
def export_debug(self):
|
||||
"""
|
||||
Export the city given to the class using the given export type handler
|
||||
:return: None
|
||||
"""
|
||||
return getattr(self, self._export_type)
|
|
@ -9,7 +9,7 @@ from unittest import TestCase
|
|||
from imports.geometry_factory import GeometryFactory
|
||||
from imports.usage_factory import UsageFactory
|
||||
from imports.construction_factory import ConstructionFactory
|
||||
from exports.exports_factory import ExportsFactory
|
||||
from exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||
|
||||
|
||||
class TestBuildings(TestCase):
|
||||
|
@ -32,7 +32,7 @@ class TestBuildings(TestCase):
|
|||
building.year_of_construction = 2006
|
||||
ConstructionFactory('nrel', city).enrich()
|
||||
UsageFactory('comnet', city).enrich()
|
||||
ExportsFactory('idf', city, output_path).export()
|
||||
EnergyBuildingsExportsFactory('idf', city, output_path).export()
|
||||
|
||||
self.assertEqual(1, len(city.buildings))
|
||||
for building in city.buildings:
|
||||
|
|
|
@ -8,11 +8,9 @@ from pathlib import Path
|
|||
from unittest import TestCase
|
||||
|
||||
from numpy import inf
|
||||
from pyproj import Proj, transform
|
||||
|
||||
from imports.geometry_factory import GeometryFactory
|
||||
from imports.construction_factory import ConstructionFactory
|
||||
import geopandas
|
||||
|
||||
|
||||
class TestGeometryFactory(TestCase):
|
||||
|
@ -169,16 +167,3 @@ class TestGeometryFactory(TestCase):
|
|||
self._check_surfaces(building)
|
||||
self.assertEqual(1912.0898135701814, building.volume)
|
||||
self.assertEqual(146.19493345171213, building.floor_area)
|
||||
|
||||
# osm
|
||||
def test_subway(self):
|
||||
"""
|
||||
Test subway parsing
|
||||
:return:
|
||||
"""
|
||||
file_path = (self._example_path / 'subway.osm').resolve()
|
||||
|
||||
city = GeometryFactory('osm_subway', path=file_path).city
|
||||
|
||||
self.assertIsNotNone(city, 'subway entrances is none')
|
||||
self.assertEqual(len(city.city_objects), 20, 'Wrong number of subway entrances')
|
||||
|
|
|
@ -11,7 +11,7 @@ from unittest import TestCase
|
|||
from imports.geometry_factory import GeometryFactory
|
||||
from imports.usage_factory import UsageFactory
|
||||
from imports.construction_factory import ConstructionFactory
|
||||
from exports.exports_factory import ExportsFactory
|
||||
from exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||
from city_model_structure.greenery.vegetation import Vegetation
|
||||
from city_model_structure.greenery.soil import Soil
|
||||
from city_model_structure.greenery.plant import Plant
|
||||
|
@ -66,7 +66,7 @@ class GreeneryInIdf(TestCase):
|
|||
if surface.type == cte.ROOF:
|
||||
surface.vegetation = vegetation
|
||||
|
||||
_idf_2 = ExportsFactory('idf', city, output_path).export_debug()
|
||||
_idf_2 = EnergyBuildingsExportsFactory('idf', city, output_path).export_debug()
|
||||
_idf_2.run()
|
||||
with open((output_path / f'{city.name}_out.csv').resolve()) as f:
|
||||
reader = csv.reader(f, delimiter=',')
|
||||
|
@ -85,7 +85,7 @@ class GreeneryInIdf(TestCase):
|
|||
building.year_of_construction = 2006
|
||||
ConstructionFactory('nrel', city).enrich()
|
||||
UsageFactory('comnet', city).enrich()
|
||||
_idf = ExportsFactory('idf', city, output_path).export()
|
||||
_idf = EnergyBuildingsExportsFactory('idf', city, output_path).export()
|
||||
_idf.run()
|
||||
with open((output_path / f'{city.name}_out.csv').resolve()) as f:
|
||||
reader = csv.reader(f, delimiter=',')
|
||||
|
|
|
@ -13,7 +13,7 @@ from helpers.monthly_values import MonthlyValues
|
|||
from imports.geometry_factory import GeometryFactory
|
||||
from imports.construction_factory import ConstructionFactory
|
||||
from imports.usage_factory import UsageFactory
|
||||
from exports.insel_exports_factory import InselExportsFactory
|
||||
from exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||
from imports.weather_factory import WeatherFactory
|
||||
|
||||
|
||||
|
@ -77,7 +77,7 @@ class TestExports(TestCase):
|
|||
month_new_value = MonthlyValues().get_mean_values(new_value)
|
||||
surface.global_irradiance[cte.MONTH] = month_new_value
|
||||
|
||||
def test_monthly_energy_balance_export(self):
|
||||
def test_insel_monthly_energy_balance_export(self):
|
||||
"""
|
||||
export to Insel MonthlyEnergyBalance
|
||||
"""
|
||||
|
@ -144,6 +144,6 @@ class TestExports(TestCase):
|
|||
|
||||
# export files
|
||||
try:
|
||||
InselExportsFactory('monthly_energy_balance', city, self._output_path).export_debug()
|
||||
EnergyBuildingsExportsFactory('insel_monthly_energy_balance', city, self._output_path).export_debug()
|
||||
except Exception:
|
||||
self.fail("Insel MonthlyEnergyBalance ExportsFactory raised ExceptionType unexpectedly!")
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
"""
|
||||
TestSchedulesFactory test and validate the city model structure schedules
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder 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.usage_factory import UsageFactory
|
||||
from imports.construction_factory import ConstructionFactory
|
||||
from imports.schedules_factory import SchedulesFactory
|
||||
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
||||
|
||||
|
||||
class TestSchedulesFactory(TestCase):
|
||||
"""
|
||||
TestSchedulesFactory 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', path=file_path).city
|
||||
for building in _city.buildings:
|
||||
building.year_of_construction = 2006
|
||||
ConstructionFactory('nrel', _city).enrich()
|
||||
self.assertIsNotNone(_city, 'city is none')
|
||||
for building in _city.buildings:
|
||||
building.function = GeometryHelper.libs_function_from_hft(building.function)
|
||||
building.year_of_construction = 2005
|
||||
UsageFactory('hft', _city).enrich()
|
||||
return _city
|
||||
|
||||
def test_doe_idf_archetypes(self):
|
||||
"""
|
||||
Enrich the city with doe_idf schedule archetypes and verify it
|
||||
"""
|
||||
file = (self._example_path / 'C40_Final.gml').resolve()
|
||||
city = self._get_citygml(file)
|
||||
occupancy_handler = 'doe_idf'
|
||||
SchedulesFactory(occupancy_handler, city).enrich()
|
||||
for building in city.buildings:
|
||||
for internal_zone in building.internal_zones:
|
||||
self.assertTrue(len(internal_zone.usage_zones) > 0)
|
||||
for usage_zone in internal_zone.usage_zones:
|
||||
self.assertIsNot(len(usage_zone.occupancy.occupancy_schedules), 0, 'no occupancy schedules defined')
|
||||
for schedule in usage_zone.occupancy.occupancy_schedules:
|
||||
self.assertIsNotNone(schedule.type)
|
||||
self.assertIsNotNone(schedule.values)
|
||||
self.assertIsNotNone(schedule.data_type)
|
||||
self.assertIsNotNone(schedule.time_step)
|
||||
self.assertIsNotNone(schedule.time_range)
|
||||
self.assertIsNotNone(schedule.day_types)
|
||||
self.assertIsNot(len(usage_zone.lighting.schedules), 0, 'no lighting schedules defined')
|
||||
for schedule in usage_zone.lighting.schedules:
|
||||
self.assertIsNotNone(schedule.type)
|
||||
self.assertIsNotNone(schedule.values)
|
||||
self.assertIsNotNone(schedule.data_type)
|
||||
self.assertIsNotNone(schedule.time_step)
|
||||
self.assertIsNotNone(schedule.time_range)
|
||||
self.assertIsNotNone(schedule.day_types)
|
Loading…
Reference in New Issue
Block a user