Source code for eureca_building.config

"""
This module includes classes and functions to manage the CONFIG varible (the variable with simulation settings)
"""

__author__ = "Enrico Prataviera"
__credits__ = ["Enrico Prataviera"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Enrico Prataviera"

import json
import os
import configparser
import logging
from datetime import datetime, timedelta
import eureca_building.logs

global DEFAULTCONFIG_FILE
DEFAULTCONFIG_FILE = os.path.join(".", "eureca_building", "default_config.ini")

[docs]def load_config(file: str = None): """Function to load the config file, json file suggested Examples --------- "DEFAULT": {}, "model": { "name": "example_model" }, "simulation settings": { "time steps per hour": "2", "simulation reference year" : "2023", "start date": "01-01 00:00", "final date": "12-31 23:00", "heating season start": "11-15 23:00", "heating season end": "04-15 23:00", "cooling season start": "06-01 23:00", "cooling season end": "09-30 23:00" }, "solar radiation settings": { "do solar radiation calculation": "False", "height subdivisions": "4", "azimuth subdivisions": "8", "urban shading tolerances": "80.,100.,80." } Parameters ---------- file : str string path to the file to load Returns ------- eureca_building.config.Config Config object from Config class """ global CONFIG try: if file.endswith('ini'): CONFIG = Config() CONFIG.read(file) elif file.endswith('json'): CONFIG = Config.from_json(file) else: raise ValueError(f'Config file must be .json or .ini') except (FileNotFoundError, AttributeError): message = "Config file not found: Trying to load default config" print(message) logging.warning(message) CONFIG = Config() CONFIG.read(DEFAULTCONFIG_FILE) message = "Default config loaded" print(message) globals().update(CONFIG) return CONFIG
# %% ---------------------------------------------------------------------------------------------------
[docs]class Config(configparser.ConfigParser): """Inherited from configparser.ConfigParser. This class is a container for config settings. """
[docs] def __init__(self): super().__init__() # Default Values self.ts_per_hour = 1 self.start_date = datetime.strptime( "2023 01-01 00:00", "%Y %m-%d %H:%M") self.final_date = datetime.strptime( "2023 12-31 23:00", "%Y %m-%d %H:%M") self.heating_start_date = datetime.strptime( "2023 11-15 00:00", "%Y %m-%d %H:%M") self.heating_final_date = datetime.strptime( "2023 04-15 00:00", "%Y %m-%d %H:%M") self.cooling_start_date = datetime.strptime( "2023 06-30 00:00", "%Y %m-%d %H:%M") self.cooling_final_date = datetime.strptime( "2023 09-01 00:00", "%Y %m-%d %H:%M") self.time_step = int(3600 / self.ts_per_hour) # s self.number_of_time_steps = int((self.final_date - self.start_date) / timedelta( minutes=self.time_step / 60)) + 1 start_time_step = int( (self.start_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.start_time_step = start_time_step self.final_time_step = start_time_step + self.number_of_time_steps # Heating/cooling season time steps self.heating_season_start_time_step = int( (self.heating_start_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.heating_season_end_time_step = int( (self.heating_final_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.cooling_season_start_time_step = int( (self.cooling_start_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.cooling_season_end_time_step = int( (self.cooling_final_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.number_of_time_steps_year = int(8760 * 60 / (self.time_step / 60)) if self.ts_per_hour > 1: self.number_of_time_steps_year -= (self.ts_per_hour - 1) self.simulation_reference_year = 2023 # Radiation self.azimuth_subdivisions = 8 self.height_subdivisions = 4 self.do_solar_radiation_calculation = True self.urban_shading_tolerances = [80.,100.,80]
@property def ts_per_hour(self) -> int: return self._ts_per_hour @ts_per_hour.setter def ts_per_hour(self, value: int): try: value = int(value) except ValueError: raise TypeError(f"Config, time_step_per_hour is not an int: {value}") if 60 % value != 0: raise ValueError(f"Config, time_step_per_hour must be a divider of 60") self._ts_per_hour = value
[docs] def read(self, file): """Method to create the object from the config.ini file Parameters ---------- file_path : str file to load the config from """ super().read(file) # Generic config settings self.ts_per_hour = int(self['simulation settings']['time steps per hour']) self.start_date = datetime.strptime(self['simulation settings']['simulation reference year'] + ' ' + self['simulation settings']['start date'], "%Y %m-%d %H:%M") self.final_date = datetime.strptime(self['simulation settings']['simulation reference year'] + ' ' +self['simulation settings']['final date'], "%Y %m-%d %H:%M") self.heating_start_date = datetime.strptime(self['simulation settings']['simulation reference year'] + ' ' +self['simulation settings']['heating season start'], "%Y %m-%d %H:%M") self.heating_final_date = datetime.strptime(self['simulation settings']['simulation reference year'] + ' ' +self['simulation settings']['heating season end'], "%Y %m-%d %H:%M") self.cooling_start_date = datetime.strptime(self['simulation settings']['simulation reference year'] + ' ' +self['simulation settings']['cooling season start'], "%Y %m-%d %H:%M") self.cooling_final_date = datetime.strptime(self['simulation settings']['simulation reference year'] + ' ' +self['simulation settings']['cooling season end'], "%Y %m-%d %H:%M") self.time_step = int(3600 / self.ts_per_hour) # s self.number_of_time_steps = int((self.final_date - self.start_date) / timedelta( minutes=self.time_step / 60)) + 1 start_time_step = int( (self.start_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.start_time_step = start_time_step self.final_time_step = start_time_step + self.number_of_time_steps # Heating/cooling season time steps self.heating_season_start_time_step = int( (self.heating_start_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.heating_season_end_time_step = int( (self.heating_final_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.cooling_season_start_time_step = int( (self.cooling_start_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.cooling_season_end_time_step = int( (self.cooling_final_date - datetime(self.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=self.time_step / 60)) self.number_of_time_steps_year = int(8760 * 60 / (self.time_step / 60)) if self.ts_per_hour > 1: self.number_of_time_steps_year -= (self.ts_per_hour - 1) self.simulation_reference_year = int(self['simulation settings']['simulation reference year']) # Radiation self.azimuth_subdivisions = int(self['solar radiation settings']["azimuth subdivisions"]) self.height_subdivisions = int(self['solar radiation settings']["height subdivisions"]) self.do_solar_radiation_calculation = False if str.lower(self['solar radiation settings']["do solar radiation calculation"]) == "false" else True self.urban_shading_tolerances = [float(i) for i in self['solar radiation settings']["urban shading tolerances"].split(",")]
[docs] @classmethod def from_json(cls, file_path): """Class method to create the object from the config.json file Parameters ---------- file_path : str file to load the config from Returns ------- eureca_building.config.Config config object """ config_dict = cls() try: with open(file_path, "r") as json_data_file: config_dict.read_dict(json.load(json_data_file)) except FileNotFoundError: raise FileNotFoundError(f"Config file {file_path} not found") # Generic config settings config_dict.ts_per_hour = int(config_dict['simulation settings']['time steps per hour']) config_dict.start_date = datetime.strptime(config_dict['simulation settings']['simulation reference year'] + ' ' +config_dict['simulation settings']['start date'], "%Y %m-%d %H:%M") config_dict.final_date = datetime.strptime(config_dict['simulation settings']['simulation reference year'] + ' ' +config_dict['simulation settings']['final date'], "%Y %m-%d %H:%M") config_dict.heating_start_date = datetime.strptime(config_dict['simulation settings']['simulation reference year'] + ' ' +config_dict['simulation settings']['heating season start'], "%Y %m-%d %H:%M") config_dict.heating_final_date = datetime.strptime(config_dict['simulation settings']['simulation reference year'] + ' ' +config_dict['simulation settings']['heating season end'], "%Y %m-%d %H:%M") config_dict.cooling_start_date = datetime.strptime(config_dict['simulation settings']['simulation reference year'] + ' ' +config_dict['simulation settings']['cooling season start'], "%Y %m-%d %H:%M") config_dict.cooling_final_date = datetime.strptime(config_dict['simulation settings']['simulation reference year'] + ' ' +config_dict['simulation settings']['cooling season end'], "%Y %m-%d %H:%M") config_dict.time_step = int(3600 / config_dict.ts_per_hour) # s config_dict.number_of_time_steps = int((config_dict.final_date - config_dict.start_date) / timedelta( minutes=config_dict.time_step / 60)) + 1 start_time_step = int( (config_dict.start_date - datetime(config_dict.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=config_dict.time_step / 60)) config_dict.start_time_step = start_time_step config_dict.final_time_step = start_time_step + config_dict.number_of_time_steps # Heating/cooling season time steps config_dict.heating_season_start_time_step = int( (config_dict.heating_start_date - datetime(config_dict.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=config_dict.time_step / 60)) config_dict.heating_season_end_time_step = int( (config_dict.heating_final_date - datetime(config_dict.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=config_dict.time_step / 60)) config_dict.cooling_season_start_time_step = int( (config_dict.cooling_start_date - datetime(config_dict.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=config_dict.time_step / 60)) config_dict.cooling_season_end_time_step = int( (config_dict.cooling_final_date - datetime(config_dict.start_date.year, 1, 1, 00, 00, 00)) / timedelta( minutes=config_dict.time_step / 60)) config_dict.number_of_time_steps_year = int(8760 * 60 / (config_dict.time_step / 60)) if config_dict.ts_per_hour > 1: config_dict.number_of_time_steps_year -= (config_dict.ts_per_hour - 1) config_dict.simulation_reference_year = int(config_dict['simulation settings']['simulation reference year']) # Radiation config_dict.azimuth_subdivisions = int(config_dict['solar radiation settings']["azimuth subdivisions"]) config_dict.height_subdivisions = int(config_dict['solar radiation settings']["height subdivisions"]) config_dict.do_solar_radiation_calculation = False if str.lower( config_dict['solar radiation settings']["do solar radiation calculation"]) == "false" else True config_dict.urban_shading_tolerances = [float(i) for i in config_dict['solar radiation settings']["urban shading tolerances"].split(",")] return config_dict
[docs] def to_json(self, file_path): """Method to print parameetrs to json Parameters ---------- file_path : str file to print on """ with open(file_path, "w") as outfile: json.dump(self, outfile, indent=4, )
global CONFIG CONFIG = Config() # try: # CONFIG # except NameError: # load_config()