133 lines
7.2 KiB
Python
133 lines
7.2 KiB
Python
|
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:
|
||
|
def __init__(self, building):
|
||
|
self.building = building
|
||
|
self.energy_systems = building.energy_systems
|
||
|
self.heating_demand = building.heating_demand[cte.HOUR]
|
||
|
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
|
||
|
|
||
|
def archetype1(self):
|
||
|
out_path = (Path(__file__).parent / 'out_files')
|
||
|
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:
|
||
|
if generation_system.system_type == cte.HEAT_PUMP:
|
||
|
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
|
||
|
m_dis[i + 1] = self.maximum_heating_demand / (cte.WATER_HEAT_CAPACITY * factor)
|
||
|
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:
|
||
|
T_ret[i + 1] = T[i + 1] - self.heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
|
||
|
tes_output = m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * (T[i + 1] - T_ret[i + 1])
|
||
|
if tes_output < self.heating_demand[i + 1]:
|
||
|
q_aux[i + 1] = self.heating_demand[i + 1] - tes_output
|
||
|
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)
|
||
|
return heating_consumption, hp_electricity, boiler_consumption
|
||
|
|
||
|
def enrich(self):
|
||
|
if self.energy_system_archetype == 'PV+ASHP+GasBoiler+TES':
|
||
|
building_new_heating_consumption, building_heating_electricity_consumption, building_heating_gas_consumption = (
|
||
|
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:
|
||
|
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
|
||
|
|
||
|
|