2024-03-29 13:56:49 -04:00
|
|
|
import csv
|
|
|
|
import math
|
|
|
|
from typing import List
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
import hub.helpers.constants as cte
|
|
|
|
from hub.helpers.monthly_values import MonthlyValues
|
|
|
|
|
|
|
|
|
|
|
|
class SystemSimulation:
|
2024-04-10 10:27:10 -04:00
|
|
|
def __init__(self, building, out_path):
|
2024-03-29 13:56:49 -04:00
|
|
|
self.building = building
|
|
|
|
self.energy_systems = building.energy_systems
|
2024-04-10 10:27:10 -04:00
|
|
|
self.heating_demand = [0] + building.heating_demand[cte.HOUR]
|
2024-03-29 13:56:49 -04:00
|
|
|
self.cooling_demand = building.cooling_demand
|
|
|
|
self.dhw_demand = building.domestic_hot_water_heat_demand
|
|
|
|
self.T_out = building.external_temperature[cte.HOUR]
|
|
|
|
self.maximum_heating_demand = building.heating_peak_load[cte.YEAR][0]
|
|
|
|
self.maximum_cooling_demand = building.cooling_peak_load[cte.YEAR][0]
|
|
|
|
self.name = building.name
|
|
|
|
self.energy_system_archetype = building.energy_systems_archetype_name
|
2024-04-10 10:27:10 -04:00
|
|
|
self.out_path = out_path
|
2024-03-29 13:56:49 -04:00
|
|
|
|
|
|
|
def archetype1(self):
|
2024-04-10 10:27:10 -04:00
|
|
|
out_path = self.out_path
|
2024-03-29 13:56:49 -04:00
|
|
|
T, T_sup, T_ret, m_ch, m_dis, q_hp, q_aux = [0] * len(self.heating_demand), [0] * len(
|
|
|
|
self.heating_demand), [0] * len(self.heating_demand), [0] * len(self.heating_demand), [0] * len(
|
|
|
|
self.heating_demand), [0] * len(self.heating_demand), [0] * len(self.heating_demand)
|
|
|
|
hp_electricity: List[float] = [0.0] * len(self.heating_demand)
|
|
|
|
aux_fuel: List[float] = [0.0] * len(self.heating_demand)
|
|
|
|
heating_consumption: List[float] = [0.0] * len(self.heating_demand)
|
|
|
|
boiler_consumption: List[float] = [0.0] * len(self.heating_demand)
|
|
|
|
T[0], dt = 25, 3600 # Assuming dt is defined somewhere
|
|
|
|
ua, v, hp_cap, hp_efficiency, boiler_efficiency = 0, 0, 0, 0, 0
|
|
|
|
for energy_system in self.energy_systems:
|
|
|
|
if cte.ELECTRICITY not in energy_system.demand_types:
|
|
|
|
generation_systems = energy_system.generation_systems
|
|
|
|
for generation_system in generation_systems:
|
2024-04-10 10:27:10 -04:00
|
|
|
if generation_system.system_type == cte.HEAT_PUMP and cte.HEATING in energy_system.demand_types:
|
2024-03-29 13:56:49 -04:00
|
|
|
hp_cap = generation_system.nominal_heat_output
|
|
|
|
hp_efficiency = float(generation_system.heat_efficiency)
|
|
|
|
for storage in generation_system.energy_storage_systems:
|
|
|
|
if storage.type_energy_stored == 'thermal':
|
|
|
|
v, h = float(storage.volume), float(storage.height)
|
|
|
|
r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
|
|
|
|
storage.layers)
|
|
|
|
u_tot = 1 / r_tot
|
|
|
|
d = math.sqrt((4 * v) / (math.pi * h))
|
|
|
|
a_side = math.pi * d * h
|
|
|
|
a_top = math.pi * d ** 2 / 4
|
|
|
|
ua = u_tot * (2 * a_top + a_side)
|
|
|
|
elif generation_system.system_type == cte.BOILER:
|
|
|
|
boiler_cap = generation_system.nominal_heat_output
|
|
|
|
boiler_efficiency = float(generation_system.heat_efficiency)
|
|
|
|
|
|
|
|
for i in range(len(self.heating_demand) - 1):
|
|
|
|
T[i + 1] = T[i] + ((m_ch[i] * (T_sup[i] - T[i])) + (
|
|
|
|
ua * (self.T_out[i] - T[i])) / cte.WATER_HEAT_CAPACITY - m_dis[i] * (T[i] - T_ret[i])) * (dt / (cte.WATER_DENSITY * v))
|
|
|
|
if T[i + 1] < 35:
|
|
|
|
q_hp[i + 1] = hp_cap * 1000
|
|
|
|
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * 7)
|
|
|
|
T_sup[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + T[i + 1]
|
|
|
|
elif 35 <= T[i + 1] < 45 and q_hp[i] == 0:
|
|
|
|
q_hp[i + 1] = 0
|
|
|
|
m_ch[i + 1] = 0
|
|
|
|
T_sup[i + 1] = T[i + 1]
|
|
|
|
elif 35 <= T[i + 1] < 45 and q_hp[i] > 0:
|
|
|
|
q_hp[i + 1] = hp_cap * 1000
|
|
|
|
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * 3)
|
|
|
|
T_sup[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + T[i + 1]
|
|
|
|
else:
|
|
|
|
q_hp[i + 1], m_ch[i + 1], T_sup[i + 1] = 0, 0, T[i + 1]
|
|
|
|
|
|
|
|
hp_electricity[i + 1] = q_hp[i + 1] / hp_efficiency
|
|
|
|
if self.heating_demand[i + 1] == 0:
|
|
|
|
m_dis[i + 1], t_return, T_ret[i + 1] = 0, T[i + 1], T[i + 1]
|
|
|
|
else:
|
|
|
|
if self.heating_demand[i + 1] > 0.5 * self.maximum_heating_demand:
|
|
|
|
factor = 8
|
|
|
|
else:
|
|
|
|
factor = 4
|
2024-04-10 10:27:10 -04:00
|
|
|
m_dis[i + 1] = self.maximum_heating_demand / (cte.WATER_HEAT_CAPACITY * factor * 3600)
|
2024-03-29 13:56:49 -04:00
|
|
|
t_return = T[i + 1] - self.heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
|
|
|
|
if m_dis[i + 1] == 0 or (m_dis[i + 1] > 0 and t_return < 25):
|
|
|
|
T_ret[i + 1] = max(25, T[i + 1])
|
|
|
|
else:
|
2024-04-10 10:27:10 -04:00
|
|
|
T_ret[i + 1] = T[i + 1] - self.heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * 3600)
|
2024-03-29 13:56:49 -04:00
|
|
|
tes_output = m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * (T[i + 1] - T_ret[i + 1])
|
2024-04-10 10:27:10 -04:00
|
|
|
if tes_output < (self.heating_demand[i + 1] / 3600):
|
|
|
|
q_aux[i + 1] = (self.heating_demand[i + 1] / 3600) - tes_output
|
2024-03-29 13:56:49 -04:00
|
|
|
aux_fuel[i + 1] = (q_aux[i + 1] * dt) / 50e6
|
|
|
|
boiler_consumption[i + 1] = q_aux[i + 1] / boiler_efficiency
|
|
|
|
heating_consumption[i + 1] = boiler_consumption[i + 1] + hp_electricity[i + 1]
|
|
|
|
data = list(zip(T, T_sup, T_ret, m_ch, m_dis, q_hp, hp_electricity, aux_fuel, q_aux, self.heating_demand))
|
|
|
|
file_name = f'simulation_results_{self.name}.csv'
|
|
|
|
with open(out_path / file_name, 'w', newline='') as csvfile:
|
|
|
|
output_file = csv.writer(csvfile)
|
|
|
|
# Write header
|
|
|
|
output_file.writerow(['T', 'T_sup', 'T_ret', 'm_ch', 'm_dis', 'q_hp', 'hp_electricity', 'aux_fuel', 'q_aux', 'heating_demand'])
|
|
|
|
# Write data
|
|
|
|
output_file.writerows(data)
|
2024-04-10 10:27:10 -04:00
|
|
|
return heating_consumption, hp_electricity, boiler_consumption, T_sup
|
2024-03-29 13:56:49 -04:00
|
|
|
|
|
|
|
def enrich(self):
|
2024-04-10 10:27:10 -04:00
|
|
|
if self.energy_system_archetype == 'PV+ASHP+GasBoiler+TES' or 'PV+4Pipe+DHW':
|
|
|
|
building_new_heating_consumption, building_heating_electricity_consumption, building_heating_gas_consumption, supply_temperature = (
|
2024-03-29 13:56:49 -04:00
|
|
|
self.archetype1())
|
|
|
|
self.building.heating_consumption[cte.HOUR] = building_new_heating_consumption
|
|
|
|
self.building.heating_consumption[cte.MONTH] = MonthlyValues.get_total_month(self.building.heating_consumption[cte.HOUR])
|
|
|
|
self.building.heating_consumption[cte.YEAR] = [sum(self.building.heating_consumption[cte.MONTH])]
|
|
|
|
disaggregated_consumption = {}
|
|
|
|
for energy_system in self.building.energy_systems:
|
|
|
|
if cte.HEATING in energy_system.demand_types:
|
|
|
|
for generation_system in energy_system.generation_systems:
|
2024-04-10 10:27:10 -04:00
|
|
|
if generation_system.system_type == cte.HEAT_PUMP:
|
|
|
|
generation_system.heat_supply_temperature = supply_temperature
|
2024-03-29 13:56:49 -04:00
|
|
|
disaggregated_consumption[generation_system.fuel_type] = {}
|
|
|
|
if generation_system.fuel_type == cte.ELECTRICITY:
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][
|
|
|
|
cte.HOUR] = building_heating_electricity_consumption
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][cte.MONTH] = MonthlyValues.get_total_month(
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][cte.HOUR])
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][cte.YEAR] = [
|
|
|
|
sum(disaggregated_consumption[generation_system.fuel_type][cte.MONTH])]
|
|
|
|
else:
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][cte.HOUR] = building_heating_gas_consumption
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][cte.MONTH] = MonthlyValues.get_total_month(
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][cte.HOUR])
|
|
|
|
disaggregated_consumption[generation_system.fuel_type][cte.YEAR] = [
|
|
|
|
sum(disaggregated_consumption[generation_system.fuel_type][cte.MONTH])]
|
|
|
|
self.building.heating_consumption_disaggregated = disaggregated_consumption
|
|
|
|
return self.building
|
|
|
|
|
|
|
|
|