Skip to content

Feature/add thermal building model #476

Feature/add thermal building model

Feature/add thermal building model #476

Triggered via pull request November 30, 2023 14:42
Status Success
Total duration 7m 13s
Artifacts

codeql.yml

on: pull_request
Matrix: Analyze
Fit to window
Zoom out
Zoom in

Annotations

19 errors
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/calculate_gain_by_Sun.py#L68
"Albedo", "liq_precip_depth_mm", "liq_precip_rate_Hour", ] self.weather_data = pd.read_csv( - epwfile_path, skiprows=8, header=None, names=epw_labels, - encoding='ISO-8859-1', engine='python').drop('datasource', axis=1) + epwfile_path, + skiprows=8, + header=None, + names=epw_labels, + encoding="ISO-8859-1", + engine="python", + ).drop("datasource", axis=1) def calc_sun_position(self, latitude_deg, longitude_deg, year, hoy): """ Calculates the Sun Position for a specific hour and location :param latitude_deg: Geographical Latitude in Degrees
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/thermal_building_model.py#L63
class_building="average", number_of_time_steps=number_of_time_steps, ) else: building_example = Building( - country = "DE", - construction_year = 1980, - floor_area = 200, + country="DE", + construction_year=1980, + floor_area=200, class_building="average", - building_type ="SFH", - refurbishment_status = "no_refurbishment", + building_type="SFH", + refurbishment_status="no_refurbishment", number_of_time_steps=number_of_time_steps, ) building_example.calculate_all_parameters() # Pre-Calculation of solar gains with weather_data and building_data
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/thermal_building_model_investment.py#L30
""" __copyright__ = "oemof developer group" __license__ = "MIT" from oemof.tools import economics + def main(): # create solver solver = "cbc" # 'glpk', 'gurobi',.... solver_verbose = False # show/hide solver output
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/thermal_building_model_investment.py#L63
class_building="average", number_of_time_steps=number_of_time_steps, ) else: building_example = Building( - country = "DE", - construction_year = 1980, - floor_area = 200, + country="DE", + construction_year=1980, + floor_area=200, class_building="average", - building_type ="SFH", - refurbishment_status = "no_refurbishment", + building_type="SFH", + refurbishment_status="no_refurbishment", number_of_time_steps=number_of_time_steps, ) building_example.calculate_all_parameters() # Pre-Calculation of solar gains with weather_data and building_data
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/thermal_building_model_investment.py#L125
# create source object representing the gas commodity (annual limit) gas_resource = solph.components.Source( label="rgas", outputs={b_gas: solph.Flow(variable_costs=price_gas)} ) elect_from_grid = solph.components.Source( - label="elect_from_grid", - outputs={b_elect: solph.flows.Flow(variable_costs=30)}, - ) - + label="elect_from_grid", + outputs={b_elect: solph.flows.Flow(variable_costs=30)}, + ) elect_into_grid = solph.components.Sink( - label="elect_into_grid", - inputs={b_elect: solph.flows.Flow(variable_costs=10)}, - ) - + label="elect_into_grid", + inputs={b_elect: solph.flows.Flow(variable_costs=10)}, + ) gas_heater = solph.components.Transformer( - label="GasHeater", - inputs={b_gas: solph.flows.Flow()}, - outputs={b_heat: solph.flows.Flow( - investment=solph.Investment(ep_costs=epc_pv))}, - conversion_factors={b_elect: 1}, - ) + label="GasHeater", + inputs={b_gas: solph.flows.Flow()}, + outputs={ + b_heat: solph.flows.Flow( + investment=solph.Investment(ep_costs=epc_pv) + ) + }, + conversion_factors={b_elect: 1}, + ) datasheet_cop = 4.9 carnot_cop_7_35 = (35 + 273.15) / (35 - 7) cpf_7_35 = datasheet_cop / carnot_cop_7_35 - cpf_cop_7_35 = [cpf_7_35 * (40 + 273.15) / (40 - (temp)) for temp in t_outside] + cpf_cop_7_35 = [ + cpf_7_35 * (40 + 273.15) / (40 - (temp)) for temp in t_outside + ] cpf_cop_7_35 = [1 / cop for cop in cpf_cop_7_35] heat_pump = solph.components.Transformer( label="HeatPump", inputs={b_elect: solph.flows.Flow()}, - outputs={b_heat: solph.flows.Flow( - investment=solph.Investment(ep_costs=epc_pv))}, - conversion_factors={b_elect: cpf_cop_7_35, - b_heat : 1}, + outputs={ + b_heat: solph.flows.Flow( + investment=solph.Investment(ep_costs=epc_pv) + ) + }, + conversion_factors={b_elect: cpf_cop_7_35, b_heat: 1}, ) building = solph.components.experimental.GenericBuilding( - label="GenericBuilding", - inputs={b_heat: solph.flows.Flow(variable_costs=0)}, - outputs={b_cool: solph.flows.Flow(variable_costs=0)}, - solar_gains=solar_gains, - t_outside=t_outside, - internal_gains=internal_gains, - t_set_heating=20, - t_set_cooling=40, - building_config=building_example.building_config, - t_inital=20, - ) - - es.add(building, heat_pump, gas_heater, elect_into_grid, elect_from_grid, gas_resource) + label="GenericBuilding", + inputs={b_heat: solph.flows.Flow(variable_costs=0)}, + outputs={b_cool: solph.flows.Flow(variable_costs=0)}, + solar_gains=solar_gains, + t_outside=t_outside, + internal_gains=internal_gains, + t_set_heating=20, + t_set_cooling=40, + building_config=building_example.building_config, + t_inital=20, + ) + + es.add( + building, + heat_pump, + gas_heater, + elect_into_grid, + elect_from_grid, + gas_resource, + ) ########################################################################## # Optimise the energy system and plot the results ########################################################################## logging.info("Optimise the energy system")
/home/runner/work/oemof-solph/oemof-solph/src/oemof/solph/components/experimental/__init__.py#L9
from ._generic_caes import GenericCAES from ._piecewise_linear_converter import PiecewiseLinearConverter from ._sink_dsm import SinkDSM from ._generic_building import GenericBuilding + __all__ = [ "GenericCAES", "PiecewiseLinearConverter", "SinkDSM", - "GenericBuilding" + "GenericBuilding", ]
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L7
from calculate_gain_by_Sun import Window from dataclasses import dataclass import os import warnings from dataclasses import dataclass, field, fields + + @DataClass class BuildingConfig5RC: r""" The BuildingConfig gets generated by the function build_building_config of the building class
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L51
c_m: float floor_area: float heat_transfer_coefficient_ventilation: float total_air_change_rate: float + @DataClass class BuildingParameters: floor_area: float heat_transfer_coefficient_ventilation: float total_air_change_rate: float room_height: float a_roof: dict = field(default_factory=dict) - u_roof : dict = field(default_factory=dict) + u_roof: dict = field(default_factory=dict) b_roof: dict = field(default_factory=dict) a_floor: dict = field(default_factory=dict) u_floor: dict = field(default_factory=dict) b_floor: dict = field(default_factory=dict) a_wall: dict = field(default_factory=dict)
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L73
a_window: dict = field(default_factory=dict) a_window_specific: dict = field(default_factory=dict) delta_u_thermal_bridging: dict = field(default_factory=dict) u_window: dict = field(default_factory=dict) g_gl_n_window: dict = field(default_factory=dict) + def __post_init__(self): for field in fields(self): - if field.name.startswith(('a_', 'u_', 'b_')) and isinstance(getattr(self, field.name), dict): + if field.name.startswith(("a_", "u_", "b_")) and isinstance( + getattr(self, field.name), dict + ): self.validate_dict_keys(getattr(self, field.name), field.name) def validate_dict_keys(self, dictionary, field_name): required_prefix = field_name + "_" - if field_name == 'a_window_specific': - required_keys = {'a_window_horizontal', 'a_window_east', 'a_window_south', 'a_window_west', - 'a_window_north'} + if field_name == "a_window_specific": + required_keys = { + "a_window_horizontal", + "a_window_east", + "a_window_south", + "a_window_west", + "a_window_north", + } actual_keys = set(dictionary.keys()) if not required_keys.issubset(actual_keys): - raise ValueError(f"All keys in {field_name} must be one of {required_keys}") + raise ValueError( + f"All keys in {field_name} must be one of {required_keys}" + ) else: for key in dictionary.keys(): if not key.startswith(required_prefix): - raise ValueError(f"All keys in {field_name} must start with {required_prefix}") + raise ValueError( + f"All keys in {field_name} must start with {required_prefix}" + ) try: - int_part = int(key[len(required_prefix):]) + int_part = int(key[len(required_prefix) :]) except ValueError: - raise ValueError(f"The numeric part of the key in {field_name} must be an integer") + raise ValueError( + f"The numeric part of the key in {field_name} must be an integer" + ) + class Building: def __init__( self, number_of_time_steps: float, tabula_building_code: str = None, country: str = None, class_building: str = "average", - building_type:str = None, - refurbishment_status = "no_refurbishment", + building_type: str = None, + refurbishment_status="no_refurbishment", construction_year: int = None, floor_area: float = None, building_parameters: BuildingParameters = None, ): if building_parameters is not None: - print("You entered the Expert mode, by using a defining your own " - "building") + print( + "You entered the Expert mode, by using a defining your own " + "building" + ) self.tabula_building_code = tabula_building_code else: - mainPath = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + mainPath = os.path.abspath( + os.path.join(os.path.dirname(__file__), "..") + ) self.tabula_df = pd.DataFrame( pd.read_csv( os.path.join( - mainPath, "thermal_building_model", "tabula_data_sorted.csv" + mainPath, + "thermal_building_model", + "tabula_data_sorted.csv", ), low_memory=False, ) ) if tabula_building_code is not None: - print("You entered the Expert mode, by using a specific building" - "code name") + print( + "You entered the Expert mode, by using a specific building" + "code name" + ) self.tabula_building_code = tabula_building_code else: self.tabula_building_code = self.define_tabula_building_code( - country = country, - building_type = building_type, - construction_year = construction_year, - refurbishment_status = refurbishment_status + country=country, + building_type=building_type, + construction_year=construction_year, + refurbishment_status=refurbishment_status, ) self.building_parameters = building_parameters self.class_building = class_building self.number_of_time_steps = number_of_time_steps if floor_area is not None: - print("You initialized a floor area, which can deviate from" - "the floor area of the tabula buildings") + print( + "You initialized a floor area, which can deviate from" + "the floor area of the tabula buildings" + ) self.floor_area = floor_area else: self.floor_area = None # DIN 13790: 12.3.1.2 self.list_class_buildig = {
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L154
"heavy": {"a_m_var": 3.0, "c_m_var": 260000}, "very heavy": {"a_m_var": 3.0, "c_m_var": 370000}, } self.building_config = {} - def define_tabula_building_code(self, - country : str, - construction_year :int, - building_type : str, - refurbishment_status : str,): + def define_tabula_building_code( + self, + country: str, + construction_year: int, + building_type: str, + refurbishment_status: str, + ): self.tabula_df = self.tabula_df[ - (self.tabula_df["Code_Country"] == country) & - (self.tabula_df["Code_BuildingSizeClass"] == building_type) & - (self.tabula_df["Code_DataType_Building"] == "ReEx") & - (pd.to_numeric(self.tabula_df["Year1_Building"], errors='coerce').fillna(0) <= construction_year) & - (pd.to_numeric(self.tabula_df["Year2_Building"], errors='coerce').fillna(0) >= construction_year) + (self.tabula_df["Code_Country"] == country) + & (self.tabula_df["Code_BuildingSizeClass"] == building_type) + & (self.tabula_df["Code_DataType_Building"] == "ReEx") + & ( + pd.to_numeric( + self.tabula_df["Year1_Building"], errors="coerce" + ).fillna(0) + <= construction_year + ) + & ( + pd.to_numeric( + self.tabula_df["Year2_Building"], errors="coerce" + ).fillna(0) + >= construction_year + ) + ] + if refurbishment_status in { + "no_refurbishment", + "usual_refurbishment", + "advanced_refurbishment", + }: + variant_mapping = { + "no_refurbishment": 1, + "usual_refurbishment": 2, + "advanced_refurbishment": 3, + } + self.tabula_df = self.tabula_df[ + self.tabula_df["Number_BuildingVariant"] + == variant_mapping[refurbishment_status] ] - if refurbishment_status in {"no_refurbishment", "usual_refurbishment", "advanced_refurbishment"}: - variant_mapping = {"no_refurbishment": 1, "usual_refurbishment": 2, "advanced_refurbishment": 3} - self.tabula_df = self.tabula_df[ - self.tabula_df["Number_BuildingVariant"] == variant_mapping[refurbishment_status]] - - assert len(self.tabula_df) <= 1, "More than one building is founded for " \ - "the input parameters. Please write an " \ - "issue in Github" - return self.tabula_df["Code_BuildingVariant"] + + assert len(self.tabula_df) <= 1, ( + "More than one building is founded for " + "the input parameters. Please write an " + "issue in Github" + ) + return self.tabula_df["Code_BuildingVariant"] def calculate_all_parameters(self): if self.building_parameters is not None: self.initialize_from_building_parameters() else:
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L207
floor_area=self.floor_area, heat_transfer_coefficient_ventilation=self.heat_transfer_coefficient_ventilation, total_air_change_rate=self.total_air_change_rate, ) return building_config + def initialize_from_building_parameters(self): for field in fields(BuildingParameters): - setattr(self, field.name, getattr(self.building_parameters, field.name)) + setattr( + self, field.name, getattr(self.building_parameters, field.name) + ) def get_building_parameters_from_csv(self): - row = self.tabula_df.loc[ self.tabula_df["Code_BuildingVariant"] == self.tabula_building_code ] list_type = ["", "Measure_", "Actual_"]
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L227
self.calc_floor_area_ratio() self.a_roof = { "a_roof_1": float(row["A_Roof_1"].values[0]), "a_roof_2": float(row["A_Roof_2"].values[0]), } - self.a_roof = {key: value * self.floor_area_ratio for key, value in self.a_roof.items()} + self.a_roof = { + key: value * self.floor_area_ratio + for key, value in self.a_roof.items() + } self.u_roof = { "u_roof_1": float(row["U_" + str(t_b) + "Roof_1"].values[0]), "u_roof_2": float(row["U_" + str(t_b) + "Roof_2"].values[0]), } self.b_roof = {
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L240
} self.a_floor = { "a_floor_1": float(row["A_Floor_1"].values[0]), "a_floor_2": float(row["A_Floor_2"].values[0]), } - self.a_floor = {key: value * self.floor_area_ratio for key, value in self.a_floor.items()} + self.a_floor = { + key: value * self.floor_area_ratio + for key, value in self.a_floor.items() + } self.u_floor = { "u_floor_1": float(row["U_" + str(t_b) + "Floor_1"].values[0]), "u_floor_2": float(row["U_" + str(t_b) + "Floor_2"].values[0]), } self.b_floor = {
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L255
self.a_wall = { "a_wall_1": float(row["A_Wall_1"].values[0]), "a_wall_2": float(row["A_Wall_2"].values[0]), "a_wall_3": float(row["A_Wall_3"].values[0]), } - self.a_wall = {key: value * self.floor_area_ratio for key, value in self.a_wall.items()} + self.a_wall = { + key: value * self.floor_area_ratio + for key, value in self.a_wall.items() + } self.u_wall = { "u_wall_1": float(row["U_" + str(t_b) + "Wall_1"].values[0]), "u_wall_2": float(row["U_" + str(t_b) + "Wall_2"].values[0]), "u_wall_3": float(row["U_" + str(t_b) + "Wall_3"].values[0]), }
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L268
"b_wall_2": float(row["b_Transmission_Wall_2"].values[0]), "b_wall_3": float(row["b_Transmission_Wall_3"].values[0]), } self.a_door = {"a_door_1": float(row["A_Door_1"].values[0])} - self.a_door = {key: value * self.floor_area_ratio for key, value in self.a_door.items()} + self.a_door = { + key: value * self.floor_area_ratio + for key, value in self.a_door.items() + } self.u_door = { "u_door_1": float(row["U_" + str(t_b) + "Door_1"].values[0]) } self.a_window = { "a_window_1": float(row["A_Window_1"].values[0]), "a_window_2": float(row["A_Window_2"].values[0]), } - self.a_window = {key: value * self.floor_area_ratio for key, value in self.a_window.items()} + self.a_window = { + key: value * self.floor_area_ratio + for key, value in self.a_window.items() + } self.a_window_specific = { "a_window_horizontal": float(row["A_Window_Horizontal"].values[0]), "a_window_east": float(row["A_Window_East"].values[0]), "a_window_south": float(row["A_Window_South"].values[0]), "a_window_west": float(row["A_Window_West"].values[0]), "a_window_north": float(row["A_Window_North"].values[0]), } - self.a_window_specific = {key: value * self.floor_area_ratio for key, value in - self.a_window_specific.items()} + self.a_window_specific = { + key: value * self.floor_area_ratio + for key, value in self.a_window_specific.items() + } self.delta_u_thermal_bridiging = { "delta_u_thermal_bridiging": float( row["delta_U_ThermalBridging"].values[0] ) } self.u_window = { "u_window_1": float(row["U_" + str(t_b) + "Window_1"].values[0]), "u_window_2": float(row["U_" + str(t_b) + "Window_2"].values[0]), } self.g_gl_n_window = { - "g_gl_n_window_1": float( - row["g_gl_n_Window_1"].values[0] - ), - "g_gl_n_window_2": float( - row["g_gl_n_Window_2"].values[0] - ), + "g_gl_n_window_1": float(row["g_gl_n_Window_1"].values[0]), + "g_gl_n_window_2": float(row["g_gl_n_Window_2"].values[0]), } self.heat_transfer_coefficient_ventilation = float( row["h_Ventilation"].values[0] )
/home/runner/work/oemof-solph/oemof-solph/examples/thermal_building_model/tabula_reader.py#L349
def calc_floor_area_ratio(self): if self.floor_area is None: self.floor_area = self.floor_area_reference self.floor_area_ratio = 1 else: - warnings.warn("Experimental mode: The floor area is unequeal" - "to the tabula reference floor area", UserWarning) + warnings.warn( + "Experimental mode: The floor area is unequeal" + "to the tabula reference floor area", + UserWarning, + ) self.floor_area_ratio = self.floor_area / self.floor_area_reference if self.floor_area_ratio > 1: - print("The chosen floor is "+str(round((1-self.floor_area_ratio)*100,3))+" % " - "bigger than the tabula reference floor area") + print( + "The chosen floor is " + + str(round((1 - self.floor_area_ratio) * 100, 3)) + + " % " + "bigger than the tabula reference floor area" + ) elif self.floor_area_ratio < 1: - print("The chosen floor is "+str(round((1-self.floor_area_ratio)*100,3))+" % " - "smaller than the tabula reference floor area") + print( + "The chosen floor is " + + str(round((1 - self.floor_area_ratio) * 100, 3)) + + " % " + "smaller than the tabula reference floor area" + ) if 0.9 > self.floor_area_ratio or 1.1 < self.floor_area_ratio: - warnings.warn("The chosen floor area is more than 10 % different to the " - "associated tabula building. It might influence " - "the results strong and unpredictable", UserWarning) + warnings.warn( + "The chosen floor area is more than 10 % different to the " + "associated tabula building. It might influence " + "the results strong and unpredictable", + UserWarning, + ) def calc_internal_area(self): # DIN 7.2.2.2 var_at = 4.5 # the dimensionless ratio between the surface area of all surfaces facing into the room and the useful area. total_internal_area = self.floor_area * var_at
/home/runner/work/oemof-solph/oemof-solph/tests/test_scripts/test_solph/test_generic_building/test_generic_building.py#L56
energysystem = solph.EnergySystem( timeindex=tindex, infer_last_interval=False, ) -solar_gains = [3000, 4000, 1000 ,300, 300, 200, 100, 50] +solar_gains = [3000, 4000, 1000, 300, 300, 200, 100, 50] internal_gains = [100, 100, 100, 100, 100, 100, 100, 100] t_outside = [22, 19, 16, 15, 14, 10, 7, 4] building_config = SimpleNamespace( - total_internal_area=499.95, - h_ve=55.55, - h_tr_w=51.52, - h_tr_em=412.05866346891787, - h_tr_is=1724.8275, - mass_area=277.75, - h_tr_ms=2527.525, - c_m=18331500.0, - floor_area=111.1, - heat_transfer_coefficient_ventilation=0.51, - total_air_change_rate=0.6 - ) + total_internal_area=499.95, + h_ve=55.55, + h_tr_w=51.52, + h_tr_em=412.05866346891787, + h_tr_is=1724.8275, + mass_area=277.75, + h_tr_ms=2527.525, + c_m=18331500.0, + floor_area=111.1, + heat_transfer_coefficient_ventilation=0.51, + total_air_change_rate=0.6, +) ########################################################################## # Create oemof objects ##########################################################################
/home/runner/work/oemof-solph/oemof-solph/tests/test_scripts/test_solph/test_generic_building/test_generic_building.py#L96
solph.components.Source( label="elect_from_grid", outputs={b_elect: solph.flows.Flow(variable_costs=30)}, ) ) -''' +""" energysystem.add( solph.components.Sink( label="elect_into_grid", inputs={b_elect: solph.flows.Flow(variable_costs=10)}, ) ) -''' +""" # create electrical heating and cooling device energysystem.add( solph.components.Transformer( label="ElectricalHeater", inputs={b_elect: solph.flows.Flow()},
/home/runner/work/oemof-solph/oemof-solph/tests/test_scripts/test_solph/test_generic_building/test_generic_building.py#L168
results = energysystem.results["main"] custom_building = views.node(results, "GenericBuilding") print(2) + def test_storage_input(): assert flows["electricity-storage"][0] == pytest.approx( (first_input - 0.99 * init_soc) / 0.9 ) assert flows["electricity-storage"][1] == 0