Merge remote-tracking branch 'origin/main'

# Conflicts:
#	scripts/random_assignation.py
This commit is contained in:
ogavalda 2024-07-26 15:19:01 -04:00
commit 0ae92e77a1
67 changed files with 4717 additions and 1044 deletions

View File

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkUUID" value="97386509-ec9b-4dd7-929b-7585219c0447" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="hub" project-jdk-type="Python SDK" />
</project>

98
energy_system_retrofit.py Normal file
View File

@ -0,0 +1,98 @@
from pathlib import Path
import subprocess
from scripts.ep_run_enrich import energy_plus_workflow
from hub.imports.geometry_factory import GeometryFactory
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
from hub.imports.results_factory import ResultFactory
from scripts.energy_system_retrofit_report import EnergySystemRetrofitReport
from scripts.geojson_creator import process_geojson
from scripts import random_assignation
from hub.imports.energy_systems_factory import EnergySystemsFactory
from scripts.energy_system_sizing import SystemSizing
from scripts.solar_angles import CitySolarAngles
from scripts.pv_sizing_and_simulation import PVSizingSimulation
from scripts.energy_system_retrofit_results import consumption_data, cost_data
from scripts.energy_system_sizing_and_simulation_factory import EnergySystemsSimulationFactory
from scripts.costs.cost import Cost
from scripts.costs.constants import SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS
import hub.helpers.constants as cte
from hub.exports.exports_factory import ExportsFactory
from scripts.pv_feasibility import pv_feasibility
# Specify the GeoJSON file path
input_files_path = (Path(__file__).parent / 'input_files')
input_files_path.mkdir(parents=True, exist_ok=True)
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0001)
geojson_file_path = input_files_path / 'output_buildings.geojson'
output_path = (Path(__file__).parent / 'out_files').resolve()
output_path.mkdir(parents=True, exist_ok=True)
energy_plus_output_path = output_path / 'energy_plus_outputs'
energy_plus_output_path.mkdir(parents=True, exist_ok=True)
simulation_results_path = (Path(__file__).parent / 'out_files' / 'simulation_results').resolve()
simulation_results_path.mkdir(parents=True, exist_ok=True)
sra_output_path = output_path / 'sra_outputs'
sra_output_path.mkdir(parents=True, exist_ok=True)
cost_analysis_output_path = output_path / 'cost_analysis'
cost_analysis_output_path.mkdir(parents=True, exist_ok=True)
city = GeometryFactory(file_type='geojson',
path=geojson_file_path,
height_field='height',
year_of_construction_field='year_of_construction',
function_field='function',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
ExportsFactory('sra', city, sra_output_path).export()
sra_path = (sra_output_path / f'{city.name}_sra.xml').resolve()
subprocess.run(['sra', str(sra_path)])
ResultFactory('sra', city, sra_output_path).enrich()
pv_feasibility(-73.5681295982132, 45.49218262677643, 0.0001, selected_buildings=city.buildings)
energy_plus_workflow(city, energy_plus_output_path)
solar_angles = CitySolarAngles(city.name,
city.latitude,
city.longitude,
tilt_angle=45,
surface_azimuth_angle=180).calculate
random_assignation.call_random(city.buildings, random_assignation.residential_systems_percentage)
EnergySystemsFactory('montreal_custom', city).enrich()
SystemSizing(city.buildings).montreal_custom()
current_status_energy_consumption = consumption_data(city)
current_status_life_cycle_cost = {}
for building in city.buildings:
cost_retrofit_scenario = CURRENT_STATUS
lcc_dataframe = Cost(building=building,
retrofit_scenario=cost_retrofit_scenario,
fuel_tariffs=['Electricity-D', 'Gas-Energir']).life_cycle
lcc_dataframe.to_csv(cost_analysis_output_path / f'{building.name}_current_status_lcc.csv')
current_status_life_cycle_cost[f'{building.name}'] = cost_data(building, lcc_dataframe, cost_retrofit_scenario)
random_assignation.call_random(city.buildings, random_assignation.residential_new_systems_percentage)
EnergySystemsFactory('montreal_future', city).enrich()
for building in city.buildings:
if 'PV' in building.energy_systems_archetype_name:
ghi = [x / cte.WATTS_HOUR_TO_JULES for x in building.roofs[0].global_irradiance[cte.HOUR]]
pv_sizing_simulation = PVSizingSimulation(building,
solar_angles,
tilt_angle=45,
module_height=1,
module_width=2,
ghi=ghi)
pv_sizing_simulation.pv_output()
if building.energy_systems_archetype_name == 'PV+4Pipe+DHW':
EnergySystemsSimulationFactory('archetype13', building=building, output_path=simulation_results_path).enrich()
retrofitted_energy_consumption = consumption_data(city)
retrofitted_life_cycle_cost = {}
for building in city.buildings:
cost_retrofit_scenario = SYSTEM_RETROFIT_AND_PV
lcc_dataframe = Cost(building=building,
retrofit_scenario=cost_retrofit_scenario,
fuel_tariffs=['Electricity-D', 'Gas-Energir']).life_cycle
lcc_dataframe.to_csv(cost_analysis_output_path / f'{building.name}_retrofitted_lcc.csv')
retrofitted_life_cycle_cost[f'{building.name}'] = cost_data(building, lcc_dataframe, cost_retrofit_scenario)
(EnergySystemRetrofitReport(city, output_path, 'PV Implementation and System Retrofit',
current_status_energy_consumption, retrofitted_energy_consumption,
current_status_life_cycle_cost, retrofitted_life_cycle_cost).create_report())

View File

@ -6,6 +6,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import xmltodict
import json
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.cost.archetype import Archetype
from hub.catalog_factories.data_models.cost.content import Content
@ -15,6 +16,7 @@ from hub.catalog_factories.data_models.cost.item_description import ItemDescript
from hub.catalog_factories.data_models.cost.operational_cost import OperationalCost
from hub.catalog_factories.data_models.cost.fuel import Fuel
from hub.catalog_factories.data_models.cost.income import Income
from hub.catalog_factories.data_models.cost.pricing_rate import PricingRate
class MontrealNewCatalog(Catalog):
@ -24,6 +26,7 @@ class MontrealNewCatalog(Catalog):
def __init__(self, path):
path = (path / 'montreal_costs_completed.xml').resolve()
self._fuel_rates_path = (path.parent / 'fuel_rates.json').resolve()
with open(path, 'r', encoding='utf-8') as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list='archetype')
@ -45,7 +48,7 @@ class MontrealNewCatalog(Catalog):
construction = float(archetype['incomes']['subsidies']['construction']['#text'])
hvac = float(archetype['incomes']['subsidies']['hvac']['#text'])
photovoltaic_system = float(archetype['incomes']['subsidies']['photovoltaic']['#text'])
electricity_exports = float(archetype['incomes']['electricity_export']['#text']) / 1000 / 3600
electricity_exports = float(archetype['incomes']['electricity_export']['#text'])
reduction_tax = float(archetype['incomes']['tax_reduction']['#text']) / 100
income = Income(construction_subsidy=construction,
hvac_subsidy=hvac,
@ -75,7 +78,22 @@ class MontrealNewCatalog(Catalog):
refurbishment_unit=_refurbishment_unit,
reposition=None,
reposition_unit=None,
lifetime=None)
lifetime=None,
maintenance=None,
maintenance_unit=None)
elif 'maintenance_cost' in item.keys():
maintenance_cost = float(item['maintenance_cost']['#text'])
maintenance_unit = item['maintenance_cost']['@cost_unit']
_item_description = ItemDescription(item_type,
initial_investment=None,
initial_investment_unit=None,
refurbishment=None,
refurbishment_unit=None,
reposition=None,
reposition_unit=None,
lifetime=None,
maintenance=maintenance_cost,
maintenance_unit=maintenance_unit)
else:
_reposition = float(item['reposition']['#text'])
_reposition_unit = item['reposition']['@cost_unit']
@ -89,7 +107,9 @@ class MontrealNewCatalog(Catalog):
refurbishment_unit=None,
reposition=_reposition,
reposition_unit=_reposition_unit,
lifetime=_lifetime)
lifetime=_lifetime,
maintenance=None,
maintenance_unit=None)
return _item_description
@ -137,13 +157,35 @@ class MontrealNewCatalog(Catalog):
return capital_costs
@staticmethod
def _get_operational_costs(entry):
def load_fuel_rates(self):
rates = []
with open(self._fuel_rates_path, 'r') as f:
fuel_rates = json.load(f)
for rate in fuel_rates['rates']['fuels']['rate']:
name = rate['name']
rate_type = rate['rate_type']
units = rate['units']
values = rate['values']
rates.append(PricingRate(name=name, rate_type=rate_type, units=units, values=values))
return rates
def search_fuel_rates(self, rates, name):
variable = None
for rate in rates:
if rate.name == name:
variable = rate
return variable
def _get_operational_costs(self, entry):
fuels = []
rates = self.load_fuel_rates()
for item in entry['fuels']['fuel']:
fuel_type = item['@fuel_type']
fuel_variable = float(item['variable']['#text'])
fuel_variable_units = item['variable']['@cost_unit']
fuel_variable = item['variable']
variable = self.search_fuel_rates(rates, fuel_variable)
fuel_fixed_monthly = None
fuel_fixed_peak = None
density = None
@ -165,20 +207,22 @@ class MontrealNewCatalog(Catalog):
fuel = Fuel(fuel_type,
fixed_monthly=fuel_fixed_monthly,
fixed_power=fuel_fixed_peak,
variable=fuel_variable,
variable_units=fuel_variable_units,
variable=variable,
density=density,
density_unit=density_unit,
lower_heating_value=lower_heating_value,
lower_heating_value_unit=lower_heating_value_unit)
fuels.append(fuel)
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text'])
cooling_equipment_maintenance = float(entry['maintenance']['cooling_equipment']['#text'])
hvac_equipment = entry['maintenance']['hvac_equipment']
items = []
for item in hvac_equipment:
items.append(self.item_description(item, hvac_equipment[item]))
photovoltaic_system_maintenance = float(entry['maintenance']['photovoltaic_system']['#text'])
co2_emissions = float(entry['co2_cost']['#text'])
_operational_cost = OperationalCost(fuels,
heating_equipment_maintenance,
cooling_equipment_maintenance,
items,
photovoltaic_system_maintenance,
co2_emissions)
return _operational_cost

View File

@ -6,7 +6,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union
from hub.catalog_factories.data_models.cost.pricing_rate import PricingRate
class Fuel:
"""
@ -16,7 +16,6 @@ class Fuel:
fixed_monthly=None,
fixed_power=None,
variable=None,
variable_units=None,
density=None,
density_unit=None,
lower_heating_value=None,
@ -26,7 +25,6 @@ class Fuel:
self._fixed_monthly = fixed_monthly
self._fixed_power = fixed_power
self._variable = variable
self._variable_units = variable_units
self._density = density
self._density_unit = density_unit
self._lower_heating_value = lower_heating_value
@ -59,12 +57,12 @@ class Fuel:
return None
@property
def variable(self) -> Union[tuple[None, None], tuple[float, str]]:
def variable(self) -> Union[None, PricingRate]:
"""
Get variable costs in given units
:return: None, None or float, str
"""
return self._variable, self._variable_units
return self._variable
@property
def density(self) -> Union[tuple[None, None], tuple[float, str]]:
@ -84,11 +82,13 @@ class Fuel:
def to_dictionary(self):
"""Class content to dictionary"""
variable_price = None
if self.variable is not None:
variable_price = self.variable.to_dictionary()
content = {'Fuel': {'fuel type': self.type,
'fixed operational costs [currency/month]': self.fixed_monthly,
'fixed operational costs depending on the peak power consumed [currency/month W]': self.fixed_power,
'variable operational costs': self.variable[0],
'units': self.variable[1],
'variable operational costs': variable_price,
'density': self.density[0],
'density unit': self.density[1],
'lower heating value': self.lower_heating_value[0],

View File

@ -19,7 +19,9 @@ class ItemDescription:
refurbishment_unit=None,
reposition=None,
reposition_unit=None,
lifetime=None):
lifetime=None,
maintenance=None,
maintenance_unit=None):
self._item_type = item_type
self._initial_investment = initial_investment
@ -29,6 +31,8 @@ class ItemDescription:
self._reposition = reposition
self._reposition_unit = reposition_unit
self._lifetime = lifetime
self._maintenance = maintenance
self._maintenance_unit = maintenance_unit
@property
def type(self):
@ -70,6 +74,14 @@ class ItemDescription:
"""
return self._lifetime
@property
def maintenance(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get reposition costs of the specific item in given units
:return: None, None or float, str
"""
return self._maintenance, self._maintenance_unit
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Item': {'type': self.type,
@ -79,7 +91,9 @@ class ItemDescription:
'refurbishment units': self.refurbishment[1],
'reposition': self.reposition[0],
'reposition units': self.reposition[1],
'life time [years]': self.lifetime
'life time [years]': self.lifetime,
'maintenance': self.maintenance[0],
'maintenance units': self.maintenance[1]
}
}

View File

@ -7,16 +7,15 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
from typing import List
from hub.catalog_factories.data_models.cost.fuel import Fuel
from hub.catalog_factories.data_models.cost.item_description import ItemDescription
class OperationalCost:
"""
Operational cost class
"""
def __init__(self, fuels, maintenance_heating, maintenance_cooling, maintenance_pv, co2):
def __init__(self, fuels, maintenance_hvac, maintenance_pv, co2):
self._fuels = fuels
self._maintenance_heating = maintenance_heating
self._maintenance_cooling = maintenance_cooling
self._maintenance_hvac = maintenance_hvac
self._maintenance_pv = maintenance_pv
self._co2 = co2
@ -30,20 +29,12 @@ class OperationalCost:
return self._fuels
@property
def maintenance_heating(self):
def maintenance_hvac(self) -> List[ItemDescription]:
"""
Get cost of maintaining the heating system in currency/W
Get cost of maintaining the hvac system in currency/W
:return: float
"""
return self._maintenance_heating
@property
def maintenance_cooling(self):
"""
Get cost of maintaining the cooling system in currency/W
:return: float
"""
return self._maintenance_cooling
return self._maintenance_hvac
@property
def maintenance_pv(self):
@ -64,11 +55,13 @@ class OperationalCost:
def to_dictionary(self):
"""Class content to dictionary"""
_fuels = []
_hvac_maintenance = []
for _fuel in self.fuels:
_fuels.append(_fuel.to_dictionary())
for _hvac in self.maintenance_hvac:
_hvac_maintenance.append(_hvac.to_dictionary())
content = {'Maintenance': {'fuels': _fuels,
'cost of maintaining the heating system [currency/W]': self.maintenance_heating,
'cost of maintaining the cooling system [currency/W]': self.maintenance_cooling,
'cost of maintaining the hvac system [currency/W]': _hvac_maintenance,
'cost of maintaining the PV system [currency/W]': self.maintenance_pv,
'cost of CO2 emissions [currency/kgCO2]': self.co2
}

View File

@ -0,0 +1,62 @@
from typing import Union
class PricingRate:
def __init__(self, name=None, rate_type=None, time_range=None, units=None, values=None):
self._name = name
self._rate_type = rate_type
self._time_range = time_range
self._units = units
self._values = values
@property
def name(self):
"""
name of the rate
:return: str
"""
return self._name
@property
def rate_type(self):
"""
type of rate between fixed and variable
:return: str
"""
return self._rate_type
@property
def time_range(self) -> Union[None, str]:
"""
Get schedule time range from:
['minute', 'hour', 'day', 'week', 'month', 'year']
:return: None or str
"""
return self._time_range
@property
def units(self):
"""
get the consumption unit
:return: str
"""
return self._units
@property
def values(self):
"""
Get schedule values
:return: [Any]
"""
return self._values
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Pricing': {'name': self.name,
'time range': self.time_range,
'type': self.rate_type,
'units': self.units,
'values': self.values}
}
return content

View File

@ -10,7 +10,7 @@ class EmissionSystem:
"""
Emission system class
"""
def __init__(self, system_id, model_name=None, system_type=None, parasitic_energy_consumption=None):
def __init__(self, system_id, model_name=None, system_type=None, parasitic_energy_consumption=0):
self._system_id = system_id
self._model_name = model_name

View File

@ -135,7 +135,7 @@ class MontrealCustomCatalog(Catalog):
equipment_id = float(equipment['@id'])
equipment_type = equipment['@type']
model_name = equipment['name']
parasitic_consumption = None
parasitic_consumption = 0
if 'parasitic_consumption' in equipment:
parasitic_consumption = float(equipment['parasitic_consumption']['#text']) / 100

View File

@ -262,7 +262,7 @@ class MontrealFutureSystemCatalogue(Catalog):
system_id = None
model_name = None
system_type = None
parasitic_energy_consumption = None
parasitic_energy_consumption = 0
emission_system = EmissionSystem(system_id=system_id,
model_name=model_name,
system_type=system_type,
@ -298,7 +298,7 @@ class MontrealFutureSystemCatalogue(Catalog):
layers = [insulation_layer, tank_layer]
nominal_capacity = tes['nominal_capacity']
losses_ratio = tes['losses_ratio']
heating_coil_capacity = None
heating_coil_capacity = tes['heating_coil_capacity']
storage_component = ThermalStorageSystem(storage_id=storage_id,
model_name=model_name,
type_energy_stored=type_energy_stored,
@ -338,7 +338,7 @@ class MontrealFutureSystemCatalogue(Catalog):
nominal_capacity = template['nominal_capacity']
losses_ratio = template['losses_ratio']
volume = template['physical_characteristics']['volume']
heating_coil_capacity = None
heating_coil_capacity = template['heating_coil_capacity']
storage_component = ThermalStorageSystem(storage_id=storage_id,
model_name=model_name,
type_energy_stored=type_energy_stored,

View File

@ -92,6 +92,7 @@ class Building(CityObject):
logging.error('Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type)
self._domestic_hot_water_peak_load = None
self._fuel_consumption_breakdown = {}
self._pv_generation = {}
@property
def shell(self) -> Polyhedron:
@ -450,8 +451,8 @@ class Building(CityObject):
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
if monthly_values is None:
return None
results[cte.MONTH] = [x * cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values)]
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
return results
@property
@ -467,8 +468,8 @@ class Building(CityObject):
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
if monthly_values is None:
return None
results[cte.MONTH] = [x * cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values)]
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
return results
@property
@ -483,8 +484,8 @@ class Building(CityObject):
monthly_values = PeakLoads().peak_loads_from_hourly(self.domestic_hot_water_heat_demand[cte.HOUR])
if monthly_values is None:
return None
results[cte.MONTH] = [x for x in monthly_values]
results[cte.YEAR] = [max(monthly_values)]
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
return results
@property
@ -809,39 +810,16 @@ class Building(CityObject):
Get total electricity produced onsite in J
return: dict
"""
orientation_losses_factor = {cte.MONTH: {'north': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'east': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'south': [2.137931, 1.645503, 1.320946, 1.107817, 0.993213, 0.945175,
0.967949, 1.065534, 1.24183, 1.486486, 1.918033, 2.210526],
'west': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]},
cte.YEAR: {'north': [0],
'east': [0],
'south': [1.212544],
'west': [0]}
}
# Add other systems whenever new ones appear
if self.energy_systems is None:
return self._onsite_electrical_production
for energy_system in self.energy_systems:
for generation_system in energy_system.generation_systems:
if generation_system.system_type == cte.PHOTOVOLTAIC:
if generation_system.electricity_efficiency is not None:
_efficiency = float(generation_system.electricity_efficiency)
else:
_efficiency = 0
self._onsite_electrical_production = {}
for _key in self.roofs[0].global_irradiance.keys():
_results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))]
for surface in self.roofs:
if _key in orientation_losses_factor:
_results = [x + y * _efficiency * surface.perimeter_area
* surface.solar_collectors_area_reduction_factor * z
for x, y, z in zip(_results, surface.global_irradiance[_key],
orientation_losses_factor[_key]['south'])]
self._onsite_electrical_production[_key] = _results
return self._onsite_electrical_production
@onsite_electrical_production.setter
def onsite_electrical_production(self, value):
"""
set onsite electrical production from external pv simulations
:return:
"""
self._onsite_electrical_production = value
@property
def lower_corner(self):
"""
@ -876,37 +854,39 @@ class Building(CityObject):
if demand_type in generation_system.energy_consumption:
fuel_breakdown[f'{generation_system.fuel_type}'][f'{demand_type}'] = (
generation_system.energy_consumption)[f'{demand_type}'][cte.YEAR][0]
storage_systems = generation_system.energy_storage_systems
if storage_systems:
for storage_system in storage_systems:
if storage_system.type_energy_stored == 'thermal' and storage_system.heating_coil_energy_consumption:
fuel_breakdown[cte.ELECTRICITY][f'{demand_type}'] += storage_system.heating_coil_energy_consumption[cte.YEAR][0]
#TODO: When simulation models of all energy system archetypes are created, this part can be removed
heating = 0
cooling = 0
dhw = 0
heating_fuels = []
dhw_fuels = []
for energy_system in self.energy_systems:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
heating_fuels.append(generation_system.fuel_type)
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
dhw_fuels.append(generation_system.fuel_type)
for key in fuel_breakdown:
if cte.HEATING not in fuel_breakdown[key]:
heating += 1
if key == cte.ELECTRICITY and cte.COOLING not in fuel_breakdown[key]:
cooling += 1
if cte.DOMESTIC_HOT_WATER not in fuel_breakdown[key]:
dhw += 1
if heating > 0:
for energy_system in energy_systems:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.HEATING] = self.heating_consumption[cte.YEAR][0] / 3600
if dhw > 0:
for energy_system in energy_systems:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.DOMESTIC_HOT_WATER] = \
self.domestic_hot_water_consumption[cte.YEAR][0] / 3600
if cooling > 0:
for energy_system in energy_systems:
if cte.COOLING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.COOLING] = self.cooling_consumption[cte.YEAR][0] / 3600
for energy_system in energy_systems:
if cte.COOLING in energy_system.demand_types and cte.COOLING not in fuel_breakdown[key]:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.COOLING] = self.cooling_consumption[cte.YEAR][0]
for fuel in heating_fuels:
if cte.HEATING not in fuel_breakdown[fuel]:
for energy_system in energy_systems:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.HEATING] = self.heating_consumption[cte.YEAR][0]
for fuel in dhw_fuels:
if cte.DOMESTIC_HOT_WATER not in fuel_breakdown[fuel]:
for energy_system in energy_systems:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0]
self._fuel_consumption_breakdown = fuel_breakdown
return self._fuel_consumption_breakdown

View File

@ -46,6 +46,8 @@ class Surface:
self._vegetation = None
self._percentage_shared = None
self._solar_collectors_area_reduction_factor = None
self._global_irradiance_tilted = {}
self._installed_solar_collector_area = None
@property
def name(self):
@ -384,3 +386,35 @@ class Surface:
:param value: float
"""
self._solar_collectors_area_reduction_factor = value
@property
def global_irradiance_tilted(self) -> dict:
"""
Get global irradiance on a tilted surface in J/m2
:return: dict
"""
return self._global_irradiance_tilted
@global_irradiance_tilted.setter
def global_irradiance_tilted(self, value):
"""
Set global irradiance on a tilted surface in J/m2
:param value: dict
"""
self._global_irradiance_tilted = value
@property
def installed_solar_collector_area(self):
"""
Get installed solar collector area in m2
:return: dict
"""
return self._installed_solar_collector_area
@installed_solar_collector_area.setter
def installed_solar_collector_area(self, value):
"""
Set installed solar collector area in m2
:return: dict
"""
self._installed_solar_collector_area = value

View File

@ -41,9 +41,10 @@ class CityObject:
self._ground_temperature = {}
self._global_horizontal = {}
self._diffuse = {}
self._beam = {}
self._direct_normal = {}
self._sensors = []
self._neighbours = None
self._beam = {}
@property
def level_of_detail(self) -> LevelOfDetail:
@ -238,20 +239,20 @@ class CityObject:
self._diffuse = value
@property
def beam(self) -> dict:
def direct_normal(self) -> dict:
"""
Get beam radiation surrounding the city object in J/m2
:return: dict{dict{[float]}}
"""
return self._beam
return self._direct_normal
@beam.setter
def beam(self, value):
@direct_normal.setter
def direct_normal(self, value):
"""
Set beam radiation surrounding the city object in J/m2
:param value: dict{dict{[float]}}
"""
self._beam = value
self._direct_normal = value
@property
def lower_corner(self):
@ -302,3 +303,19 @@ class CityObject:
Set the list of neighbour_objects and their properties associated to the current city_object
"""
self._neighbours = value
@property
def beam(self) -> dict:
"""
Get beam radiation surrounding the city object in J/m2
:return: dict{dict{[float]}}
"""
return self._beam
@beam.setter
def beam(self, value):
"""
Set beam radiation surrounding the city object in J/m2
:param value: dict{dict{[float]}}
"""
self._beam = value

View File

@ -13,7 +13,7 @@ class EmissionSystem:
def __init__(self):
self._model_name = None
self._type = None
self._parasitic_energy_consumption = None
self._parasitic_energy_consumption = 0
@property
def model_name(self):

View File

@ -26,6 +26,10 @@ class PvGenerationSystem(GenerationSystem):
self._width = None
self._height = None
self._electricity_power = None
self._tilt_angle = None
self._surface_azimuth = None
self._solar_altitude_angle = None
self._solar_azimuth_angle = None
@property
def nominal_electricity_output(self):
@ -202,3 +206,35 @@ class PvGenerationSystem(GenerationSystem):
:param value: float
"""
self._electricity_power = value
@property
def tilt_angle(self):
"""
Get tilt angle of PV system in degrees
:return: float
"""
return self._tilt_angle
@tilt_angle.setter
def tilt_angle(self, value):
"""
Set PV system tilt angle in degrees
:param value: float
"""
self._tilt_angle = value
@property
def surface_azimuth(self):
"""
Get surface azimuth angle of PV system in degrees. 0 is North
:return: float
"""
return self._surface_azimuth
@surface_azimuth.setter
def surface_azimuth(self, value):
"""
Set PV system tilt angle in degrees
:param value: float
"""
self._surface_azimuth = value

View File

@ -24,6 +24,7 @@ class ThermalStorageSystem(EnergyStorageSystem):
self._maximum_operating_temperature = None
self._heating_coil_capacity = None
self._temperature = None
self._heating_coil_energy_consumption = None
@property
def volume(self):
@ -95,7 +96,7 @@ class ThermalStorageSystem(EnergyStorageSystem):
Get heating coil capacity in Watts
:return: float
"""
return self._maximum_operating_temperature
return self._heating_coil_capacity
@heating_coil_capacity.setter
def heating_coil_capacity(self, value):
@ -120,3 +121,19 @@ class ThermalStorageSystem(EnergyStorageSystem):
:param value: dict{[float]}
"""
self._temperature = value
@property
def heating_coil_energy_consumption(self) -> dict:
"""
Get fuel consumption in W, m3, or kg
:return: dict{[float]}
"""
return self._heating_coil_energy_consumption
@heating_coil_energy_consumption.setter
def heating_coil_energy_consumption(self, value):
"""
Set fuel consumption in W, m3, or kg
:param value: dict{[float]}
"""
self._heating_coil_energy_consumption = value

View File

@ -0,0 +1,106 @@
{
"rates": {
"fuels": {
"rate": [
{
"name": "Electricity-D",
"fuel_type": "Electricity",
"rate_name": "D",
"units": "CAD/kWh",
"usage_type": "residential",
"maximum_power_demand_kW": 65,
"rate_type": "fixed",
"notes": null,
"start_date": null,
"end_date": null,
"values": [
0.075
]
},
{
"name": "Electricity-Flex-D",
"fuel_type": "Electricity",
"rate_name": "Flex-D",
"units": "CAD/kWh",
"usage_type": "residential",
"maximum_power_demand_kW": 65,
"rate_type": "variable",
"notes": null,
"start_date": null,
"end_date": null,
"values": [
0.075,
0.075,
0.075,
0.075,
0.075,
0.075,
0.551,
0.551,
0.551,
0.075,
0.075,
0.075,
0.075,
0.075,
0.075,
0.075,
0.551,
0.551,
0.551,
0.551,
0.075,
0.075,
0.075,
0.075
]
},
{
"name": "Gas-Energir",
"fuel_type": "Gas",
"rate_name": null,
"units": "CAD/m3",
"usage_type": "residential",
"maximum_power_demand_kW": null,
"rate_type": "fixed",
"notes": null,
"start_date": null,
"end_date": null,
"values": [
0.4
]
},
{
"name": "Diesel-Fixed",
"fuel_type": "Diesel",
"rate_name": null,
"units": "CAD/l",
"usage_type": "residential",
"maximum_power_demand_kW": null,
"rate_type": "fixed",
"notes": null,
"start_date": null,
"end_date": null,
"values": [
1.2
]
},
{
"name": "Biomass-Fixed",
"fuel_type": "Biomass",
"rate_name": null,
"units": "CAD/kg",
"usage_type": "residential",
"maximum_power_demand_kW": null,
"rate_type": "fixed",
"notes": null,
"start_date": null,
"end_date": null,
"values": [
0.04
]
}
]
}
}
}

View File

@ -25,8 +25,8 @@
<D_services>
<D20_onsite_generation>
<D2010_photovoltaic_system>
<investment_cost cost_unit="currency/m2"> 0 </investment_cost>
<reposition cost_unit="currency/m2"> 0 </reposition>
<investment_cost cost_unit="currency/m2"> 300 </investment_cost>
<reposition cost_unit="currency/m2"> 300 </reposition>
<lifetime_equipment lifetime="years"> 25 </lifetime_equipment>
</D2010_photovoltaic_system>
</D20_onsite_generation>
@ -124,34 +124,58 @@
<operational_cost>
<fuels>
<fuel fuel_type="Electricity">
<fixed_monthly cost_unit="currency/month">12.27</fixed_monthly>
<fixed_power cost_unit="currency/month*kW">0</fixed_power>
<variable cost_unit="currency/kWh">0.075</variable>
<density/>
<lower_heating_value/>
<fixed_monthly cost_unit="currency/month"> 12.27 </fixed_monthly>
<fixed_power cost_unit="currency/(month*kW)"> 0 </fixed_power>
<variable>Electricity-D</variable>
</fuel>
<fuel fuel_type="Electricity">
<fixed_monthly cost_unit="currency/month"> 12.27 </fixed_monthly>
<fixed_power cost_unit="currency/(month*kW)"> 0 </fixed_power>
<variable>Electricity-Flex-D</variable>
</fuel>
<fuel fuel_type="Gas">
<fixed_monthly cost_unit="currency/month"> 17.71 </fixed_monthly>
<variable cost_unit="currency/m3"> 0.4 </variable>
<variable>Gas-Energir</variable>
<density density_unit="kg/m3"> 0.777 </density>
<lower_heating_value lhv_unit="MJ/kg"> 47.1 </lower_heating_value>
</fuel>
<fuel fuel_type="Diesel">
<fixed_monthly/>
<variable cost_unit="currency/l"> 1.2 </variable>
<variable>Diesel-Fixed</variable>
<density density_unit="kg/l"> 0.846 </density>
<lower_heating_value lhv_unit="MJ/kg"> 42.6 </lower_heating_value>
</fuel>
<fuel fuel_type="Biomass">
<fixed_monthly/>
<variable cost_unit="currency/kg"> 0.04 </variable>
<variable>Biomass-Fixed</variable>
<density/>
<lower_heating_value lhv_unit="MJ/kg"> 18 </lower_heating_value>
</fuel>
</fuels>
<maintenance>
<heating_equipment cost_unit="currency/kW">40</heating_equipment>
<cooling_equipment cost_unit="currency/kW">40</cooling_equipment>
<hvac_equipment>
<air_source_heat_pump>
<maintenance_cost cost_unit="cureency/kW">100</maintenance_cost>
</air_source_heat_pump>
<ground_source_heat_pump>
<maintenance_cost cost_unit="cureency/kW">60</maintenance_cost>
</ground_source_heat_pump>
<water_source_heat_pump>
<maintenance_cost cost_unit="cureency/kW">50</maintenance_cost>
</water_source_heat_pump>
<gas_boiler>
<maintenance_cost cost_unit="cureency/kW">50</maintenance_cost>
</gas_boiler>
<electric_boiler>
<maintenance_cost cost_unit="cureency/kW">100</maintenance_cost>
</electric_boiler>
<general_heating_equipment>
<maintenance_cost cost_unit="cureency/kW">60</maintenance_cost>
</general_heating_equipment>
<general_cooling_equipment>
<maintenance_cost cost_unit="cureency/kW">50</maintenance_cost>
</general_cooling_equipment>
</hvac_equipment>
<photovoltaic_system cost_unit="currency/m2">1</photovoltaic_system>
</maintenance>
<co2_cost cost_unit="currency/kgCO2"> 30 </co2_cost>
@ -163,7 +187,7 @@
<hvac cost_unit="%">1.5</hvac>
<photovoltaic cost_unit="%">3.6</photovoltaic>
</subsidies>
<electricity_export cost_unit="currency/kWh">0.07</electricity_export>
<electricity_export cost_unit="currency/kWh">0.075</electricity_export>
<tax_reduction cost_unit="%">5</tax_reduction>
</incomes>
</archetype>
@ -294,31 +318,57 @@
<fuel fuel_type="Electricity">
<fixed_monthly cost_unit="currency/month"> 12.27 </fixed_monthly>
<fixed_power cost_unit="currency/(month*kW)"> 0 </fixed_power>
<variable cost_unit="currency/kWh"> 0.075 </variable>
<variable>Electricity-D</variable>
</fuel>
<fuel fuel_type="Electricity">
<fixed_monthly cost_unit="currency/month"> 12.27 </fixed_monthly>
<fixed_power cost_unit="currency/(month*kW)"> 0 </fixed_power>
<variable>Electricity-Flex-D</variable>
</fuel>
<fuel fuel_type="Gas">
<fixed_monthly cost_unit="currency/month"> 17.71 </fixed_monthly>
<variable cost_unit="currency/m3"> 0.0640 </variable>
<variable>Gas-Energir</variable>
<density density_unit="kg/m3"> 0.777 </density>
<lower_heating_value lhv_unit="MJ/kg"> 47.1 </lower_heating_value>
</fuel>
<fuel fuel_type="Diesel">
<fixed_monthly/>
<variable cost_unit="currency/l"> 1.2 </variable>
<variable>Diesel-Fixed</variable>
<density density_unit="kg/l"> 0.846 </density>
<lower_heating_value lhv_unit="MJ/kg"> 42.6 </lower_heating_value>
</fuel>
<fuel fuel_type="Biomass">
<fixed_monthly/>
<variable cost_unit="currency/kg"> 0.04 </variable>
<variable>Biomass-Fixed</variable>
<density/>
<lower_heating_value lhv_unit="MJ/kg"> 18 </lower_heating_value>
</fuel>
</fuels>
<maintenance>
<heating_equipment cost_unit="currency/kW">40</heating_equipment>
<cooling_equipment cost_unit="currency/kW">40</cooling_equipment>
<photovoltaic_system cost_unit="currency/m2">0</photovoltaic_system>
<hvac_equipment>
<air_source_heat_pump>
<maintenance_cost cost_unit="cureency/kW">100</maintenance_cost>
</air_source_heat_pump>
<ground_source_heat_pump>
<maintenance_cost cost_unit="cureency/kW">60</maintenance_cost>
</ground_source_heat_pump>
<water_source_heat_pump>
<maintenance_cost cost_unit="cureency/kW">50</maintenance_cost>
</water_source_heat_pump>
<gas_boiler>
<maintenance_cost cost_unit="cureency/kW">50</maintenance_cost>
</gas_boiler>
<electric_boiler>
<maintenance_cost cost_unit="cureency/kW">100</maintenance_cost>
</electric_boiler>
<general_heating_equipment>
<maintenance_cost cost_unit="cureency/kW">60</maintenance_cost>
</general_heating_equipment>
<general_cooling_equipment>
<maintenance_cost cost_unit="cureency/kW">50</maintenance_cost>
</general_cooling_equipment>
</hvac_equipment>
<photovoltaic_system cost_unit="currency/m2">1</photovoltaic_system>
</maintenance>
<co2_cost cost_unit="currency/kgCO2"> 30 </co2_cost>
</operational_cost>

View File

@ -911,7 +911,7 @@
<nominal_cooling_output/>
<minimum_cooling_output/>
<maximum_cooling_output/>
<cooling_efficiency/>
<cooling_efficiency>4.5</cooling_efficiency>
<electricity_efficiency/>
<source_temperature/>
<source_mass_flow/>
@ -931,7 +931,13 @@
</heat_efficiency_curve>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
<cooling_efficiency_curve>
<curve_type>bi-quadratic</curve_type>
<dependant_variable>COP</dependant_variable>
<parameters>source_temperature</parameters>
<parameters>supply_temperature</parameters>
<coefficients a="0.951894" b="-0.010518" c="0.000126" d="-0.003399" e="0.000183" f="-0.000206"/>
</cooling_efficiency_curve>
<distribution_systems/>
<energy_storage_systems/>
<domestic_hot_water>True</domestic_hot_water>
@ -1049,7 +1055,7 @@
<heat_efficiency>3.5</heat_efficiency>
<reversible/>
<fuel_type>electricity</fuel_type>
<source_medium>Water</source_medium>
<source_medium>Air</source_medium>
<supply_medium>Water</supply_medium>
<nominal_cooling_output/>
<minimum_cooling_output/>
@ -1065,7 +1071,13 @@
<minimum_cooling_supply_temperature/>
<heat_output_curve/>
<heat_fuel_consumption_curve/>
<heat_efficiency_curve/>
<heat_efficiency_curve>
<curve_type>bi-quadratic</curve_type>
<dependant_variable>COP</dependant_variable>
<parameters>source_temperature</parameters>
<parameters>supply_temperature</parameters>
<coefficients a="1.990668" b="0" c="0" d="-0.027252" e="0.000131" f="0"/>
</heat_efficiency_curve>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
@ -1259,7 +1271,7 @@
<storage_type>sensible</storage_type>
<nominal_capacity/>
<losses_ratio/>
<heating_coil_capacity/>
<heating_coil_capacity>5000</heating_coil_capacity>
</templateStorages>
</energy_storage_components>
<materials>
@ -1426,6 +1438,29 @@
<generation_id>27</generation_id>
</components>
</system>
<system>
<id>11</id>
<name>Central Heating System َASHP Gas-Boiler TES</name>
<schema>schemas/ASHP+TES+GasBoiler.jpg</schema>
<demands>
<demand>heating</demand>
</demands>
<components>
<generation_id>23</generation_id>
<generation_id>16</generation_id>
</components>
</system>
<system>
<id>12</id>
<name>Unitary ASHP Cooling System</name>
<schema>schemas/ASHP+TES+GasBoiler.jpg</schema>
<demands>
<demand>cooling</demand>
</demands>
<components>
<generation_id>23</generation_id>
</components>
</system>
</systems>
<system_archetypes>
@ -1516,6 +1551,23 @@
<system_id>10</system_id>
</systems>
</system_archetype>
<system_archetype id="14">
<name>Central Heating+Unitary Cooling+Unitary DHW</name>
<systems>
<system_id>10</system_id>
<system_id>11</system_id>
<system_id>12</system_id>
</systems>
</system_archetype>
<system_archetype id="15">
<name>Central Heating+Unitary Cooling+Unitary DHW+PV</name>
<systems>
<system_id>7</system_id>
<system_id>10</system_id>
<system_id>11</system_id>
<system_id>12</system_id>
</systems>
</system_archetype>
</system_archetypes>
</EnergySystemCatalog>

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -67,7 +67,7 @@ class SimplifiedRadiosityAlgorithm:
i = (total_days + day - 1) * 24 + hour - 1
representative_building = self._city.buildings[0]
_global = representative_building.diffuse[cte.HOUR][i] / cte.WATTS_HOUR_TO_JULES
_beam = representative_building.beam[cte.HOUR][i] / cte.WATTS_HOUR_TO_JULES
_beam = representative_building.direct_normal[cte.HOUR][i] / cte.WATTS_HOUR_TO_JULES
content += f'{day} {month} {hour} {_global} {_beam}\n'
with open(file, 'w', encoding='utf-8') as file:
file.write(content)

View File

@ -10,6 +10,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
KELVIN = 273.15
WATER_DENSITY = 1000 # kg/m3
WATER_HEAT_CAPACITY = 4182 # J/kgK
WATER_THERMAL_CONDUCTIVITY = 0.65 # W/mK
NATURAL_GAS_LHV = 36.6e6 # J/m3
AIR_DENSITY = 1.293 # kg/m3
AIR_HEAT_CAPACITY = 1005.2 # J/kgK

View File

@ -32,10 +32,21 @@ class NrcanPhysicsParameters:
city = self._city
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_nrcan_construction_function:
logging.error('Building %s has an unknown building function %s', building.name, building.function)
main_function = None
functions = building.function.split('_')
if len(functions) > 1:
maximum_percentage = 0
for function in functions:
percentage_and_function = function.split('-')
if float(percentage_and_function[0]) > maximum_percentage:
maximum_percentage = float(percentage_and_function[0])
main_function = percentage_and_function[-1]
else:
main_function = functions[-1]
if main_function not in Dictionaries().hub_function_to_nrcan_construction_function:
logging.error('Building %s has an unknown building function %s', building.name, main_function)
continue
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
function = Dictionaries().hub_function_to_nrcan_construction_function[main_function]
try:
archetype = self._search_archetype(nrcan_catalog, function, building.year_of_construction, self._climate_zone)

View File

@ -136,10 +136,14 @@ class MontrealCustomEnergySystemParameters:
_distribution_system.distribution_consumption_variable_flow = \
archetype_distribution_system.distribution_consumption_variable_flow
_distribution_system.heat_losses = archetype_distribution_system.heat_losses
_emission_system = None
_generic_emission_system = None
if archetype_distribution_system.emission_systems is not None:
_emission_system = EmissionSystem()
_distribution_system.emission_systems = [_emission_system]
_emission_systems = []
for emission_system in archetype_distribution_system.emission_systems:
_generic_emission_system = EmissionSystem()
_generic_emission_system.parasitic_energy_consumption = emission_system.parasitic_energy_consumption
_emission_systems.append(_generic_emission_system)
_distribution_system.emission_systems = _emission_systems
_distribution_systems.append(_distribution_system)
return _distribution_systems

View File

@ -82,8 +82,7 @@ class MontrealFutureEnergySystemParameters:
return _generic_energy_systems
@staticmethod
def _create_generation_systems(archetype_system):
def _create_generation_systems(self, archetype_system):
_generation_systems = []
archetype_generation_systems = archetype_system.generation_systems
if archetype_generation_systems is not None:
@ -107,6 +106,7 @@ class MontrealFutureEnergySystemParameters:
_generation_system.cell_temperature_coefficient = archetype_generation_system.cell_temperature_coefficient
_generation_system.width = archetype_generation_system.width
_generation_system.height = archetype_generation_system.height
_generation_system.tilt_angle = self._city.latitude
_generic_storage_system = None
if archetype_generation_system.energy_storage_systems is not None:
_generic_storage_system = ElectricalStorageSystem()
@ -160,6 +160,7 @@ class MontrealFutureEnergySystemParameters:
_generic_storage_system.height = storage_system.height
_generic_storage_system.layers = storage_system.layers
_generic_storage_system.storage_medium = storage_system.storage_medium
_generic_storage_system.heating_coil_capacity = storage_system.heating_coil_capacity
_storage_systems.append(_generic_storage_system)
_generation_system.energy_storage_systems = _storage_systems
if archetype_generation_system.domestic_hot_water:
@ -184,10 +185,14 @@ class MontrealFutureEnergySystemParameters:
_distribution_system.distribution_consumption_variable_flow = \
archetype_distribution_system.distribution_consumption_variable_flow
_distribution_system.heat_losses = archetype_distribution_system.heat_losses
_emission_system = None
_generic_emission_system = None
if archetype_distribution_system.emission_systems is not None:
_emission_system = EmissionSystem()
_distribution_system.emission_systems = [_emission_system]
_emission_systems = []
for emission_system in archetype_distribution_system.emission_systems:
_generic_emission_system = EmissionSystem()
_generic_emission_system.parasitic_energy_consumption = emission_system.parasitic_energy_consumption
_emission_systems.append(_generic_emission_system)
_distribution_system.emission_systems = _emission_systems
_distribution_systems.append(_distribution_system)
return _distribution_systems

View File

@ -127,6 +127,19 @@ class Geojson:
function = None
if self._function_field is not None:
function = str(feature['properties'][self._function_field])
if function == 'Mixed use' or function == 'mixed use':
function_parts = []
for key, value in feature['properties'].items():
if key.startswith("mixed_type_") and not key.endswith("_percentage"):
type_key = key
percentage_key = f"{key}_percentage"
if percentage_key in feature['properties']:
if self._function_to_hub is not None and feature['properties'][type_key] in self._function_to_hub:
usage_function = self._function_to_hub[feature['properties'][type_key]]
function_parts.append(f"{feature['properties'][percentage_key]}-{usage_function}")
else:
function_parts.append(f"{feature['properties'][percentage_key]}-{feature['properties'][type_key]}")
function = "_".join(function_parts)
if self._function_to_hub is not None:
# use the transformation dictionary to retrieve the proper function
if function in self._function_to_hub:

View File

@ -60,9 +60,12 @@ class EnergyPlusMultipleBuildings:
for building in self._city.buildings:
building.heating_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Heating Demand (J)']
building.cooling_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Cooling Demand (J)']
building.domestic_hot_water_heat_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} DHW Demand (W)']
building.appliances_electrical_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Appliances (W)']
building.lighting_electrical_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Lighting (W)']
building.domestic_hot_water_heat_demand[cte.HOUR] = \
[x * cte.WATTS_HOUR_TO_JULES for x in building_energy_demands[f'Building {building.name} DHW Demand (W)']]
building.appliances_electrical_demand[cte.HOUR] = \
[x * cte.WATTS_HOUR_TO_JULES for x in building_energy_demands[f'Building {building.name} Appliances (W)']]
building.lighting_electrical_demand[cte.HOUR] = \
[x * cte.WATTS_HOUR_TO_JULES for x in building_energy_demands[f'Building {building.name} Lighting (W)']]
building.heating_demand[cte.MONTH] = MonthlyValues.get_total_month(building.heating_demand[cte.HOUR])
building.cooling_demand[cte.MONTH] = MonthlyValues.get_total_month(building.cooling_demand[cte.HOUR])
building.domestic_hot_water_heat_demand[cte.MONTH] = (

View File

@ -34,7 +34,7 @@ class SimplifiedRadiosityAlgorithm:
for key in self._results:
_irradiance = {}
header_name = key.split(':')
result = [x for x in self._results[key]]
result = [x * cte.WATTS_HOUR_TO_JULES for x in self._results[key]]
city_object_name = header_name[1]
building = self._city.city_object(city_object_name)
surface_id = header_name[2]

View File

@ -35,29 +35,60 @@ class ComnetUsageParameters:
city = self._city
comnet_catalog = UsageCatalogFactory('comnet').catalog
for building in city.buildings:
usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
try:
archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
continue
for internal_zone in building.internal_zones:
if internal_zone.area is None:
raise TypeError('Internal zone area not defined, ACH cannot be calculated')
if internal_zone.volume is None:
raise TypeError('Internal zone volume not defined, ACH cannot be calculated')
if internal_zone.area <= 0:
raise TypeError('Internal zone area is zero, ACH cannot be calculated')
volume_per_area = internal_zone.volume / internal_zone.area
usage = Usage()
usage.name = usage_name
self._assign_values(usage, archetype_usage, volume_per_area, building.cold_water_temperature)
usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, archetype_usage)
internal_zone.usages = [usage]
usages = []
comnet_archetype_usages = []
building_functions = building.function.split('_')
for function in building_functions:
usages.append(function.split('-'))
for usage in usages:
comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[usage[-1]]
try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name)
comnet_archetype_usages.append(comnet_archetype_usage)
except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, comnet_usage_name)
continue
for (i, internal_zone) in enumerate(building.internal_zones):
internal_zone_usages = []
if len(building.internal_zones) > 1:
volume_per_area = 0
if internal_zone.area is None:
logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s',
building.name, usages[i][-1])
continue
if internal_zone.volume is None:
logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s',
building.name, usages[i][-1])
continue
if internal_zone.area <= 0:
logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s',
building.name, usages[i][-1])
continue
volume_per_area += internal_zone.volume / internal_zone.area
usage = Usage()
usage.name = usages[i][-1]
self._assign_values(usage, comnet_archetype_usages[i], volume_per_area, building.cold_water_temperature)
usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, comnet_archetype_usages[i])
internal_zone_usages.append(usage)
else:
if building.storeys_above_ground is None:
logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s',
building.name, usages)
continue
volume_per_area = building.volume / building.floor_area / building.storeys_above_ground
for (j, mixed_usage) in enumerate(usages):
usage = Usage()
usage.name = mixed_usage[-1]
if len(usages) > 1:
usage.percentage = float(mixed_usage[0]) / 100
else:
usage.percentage = 1
self._assign_values(usage, comnet_archetype_usages[j], volume_per_area, building.cold_water_temperature)
self._calculate_reduced_values_from_extended_library(usage, comnet_archetype_usages[j])
internal_zone_usages.append(usage)
internal_zone.usages = internal_zone_usages
@staticmethod
def _search_archetypes(comnet_catalog, usage_name):
comnet_archetypes = comnet_catalog.entries('archetypes').usages

View File

@ -33,53 +33,72 @@ class NrcanUsageParameters:
city = self._city
nrcan_catalog = UsageCatalogFactory('nrcan').catalog
comnet_catalog = UsageCatalogFactory('comnet').catalog
for building in city.buildings:
usage_name = Dictionaries().hub_usage_to_nrcan_usage[building.function]
try:
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
continue
usages = []
nrcan_archetype_usages = []
comnet_archetype_usages = []
building_functions = building.function.split('_')
for function in building_functions:
usages.append(function.split('-'))
for usage in usages:
usage_name = Dictionaries().hub_usage_to_nrcan_usage[usage[-1]]
try:
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
nrcan_archetype_usages.append(archetype_usage)
except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
continue
comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[usage[-1]]
try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name)
comnet_archetype_usages.append(comnet_archetype_usage)
except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, comnet_usage_name)
continue
comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name)
except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, comnet_usage_name)
continue
for internal_zone in building.internal_zones:
for (i, internal_zone) in enumerate(building.internal_zones):
internal_zone_usages = []
if len(building.internal_zones) > 1:
volume_per_area = 0
if internal_zone.area is None:
logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s',
building.name, usage_name)
building.name, usages[i][-1])
continue
if internal_zone.volume is None:
logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s',
building.name, usage_name)
building.name, usages[i][-1])
continue
if internal_zone.area <= 0:
logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s',
building.name, usage_name)
building.name, usages[i][-1])
continue
volume_per_area += internal_zone.volume / internal_zone.area
usage = Usage()
usage.name = usages[i][-1]
self._assign_values(usage, nrcan_archetype_usages[i], volume_per_area, building.cold_water_temperature)
self._assign_comnet_extra_values(usage, comnet_archetype_usages[i], nrcan_archetype_usages[i].occupancy.occupancy_density)
usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, nrcan_archetype_usages[i])
internal_zone_usages.append(usage)
else:
if building.storeys_above_ground is None:
logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s',
building.name, usage_name)
building.name, usages)
continue
volume_per_area = building.volume / building.floor_area / building.storeys_above_ground
for (j, mixed_usage) in enumerate(usages):
usage = Usage()
usage.name = mixed_usage[-1]
if len(usages) > 1:
usage.percentage = float(mixed_usage[0]) / 100
else:
usage.percentage = 1
self._assign_values(usage, nrcan_archetype_usages[j], volume_per_area, building.cold_water_temperature)
self._assign_comnet_extra_values(usage, comnet_archetype_usages[j], nrcan_archetype_usages[j].occupancy.occupancy_density)
self._calculate_reduced_values_from_extended_library(usage, nrcan_archetype_usages[j])
internal_zone_usages.append(usage)
usage = Usage()
usage.name = usage_name
self._assign_values(usage, archetype_usage, volume_per_area, building.cold_water_temperature)
self._assign_comnet_extra_values(usage, comnet_archetype_usage, archetype_usage.occupancy.occupancy_density)
usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, archetype_usage)
internal_zone.usages = [usage]
internal_zone.usages = internal_zone_usages
@staticmethod
def _search_archetypes(catalog, usage_name):

View File

@ -114,18 +114,22 @@ class EpwWeatherParameters:
for x in self._weather_values['global_horizontal_radiation_wh_m2']]
building.diffuse[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES
for x in self._weather_values['diffuse_horizontal_radiation_wh_m2']]
building.beam[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES
for x in self._weather_values['direct_normal_radiation_wh_m2']]
building.direct_normal[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES
for x in self._weather_values['direct_normal_radiation_wh_m2']]
building.beam[cte.HOUR] = [building.global_horizontal[cte.HOUR][i] -
building.diffuse[cte.HOUR][i]
for i in range(len(building.global_horizontal[cte.HOUR]))]
building.cold_water_temperature[cte.HOUR] = wh().cold_water_temperature(building.external_temperature[cte.HOUR])
# create the monthly and yearly values out of the hourly
for building in self._city.buildings:
building.external_temperature[cte.MONTH] = \
MonthlyValues().get_mean_values(building.external_temperature[cte.HOUR])
building.external_temperature[cte.YEAR] = [sum(building.external_temperature[cte.HOUR]) / 9870]
building.external_temperature[cte.YEAR] = [sum(building.external_temperature[cte.HOUR]) / 8760]
building.cold_water_temperature[cte.MONTH] = \
MonthlyValues().get_mean_values(building.cold_water_temperature[cte.HOUR])
building.cold_water_temperature[cte.YEAR] = [sum(building.cold_water_temperature[cte.HOUR]) / 9870]
building.cold_water_temperature[cte.YEAR] = [sum(building.cold_water_temperature[cte.HOUR]) / 8760]
# If the usage has already being imported, the domestic hot water missing values must be calculated here that
# the cold water temperature is finally known

View File

@ -8,7 +8,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import logging
import math
import hub.helpers.constants as cte
from datetime import datetime, timedelta
class Weather:
"""
@ -55,25 +55,19 @@ class Weather:
# and Craig Christensen, National Renewable Energy Laboratory
# ambient temperatures( in °C)
# cold water temperatures( in °C)
ambient_temperature_fahrenheit = []
average_temperature = 0
maximum_temperature = -1000
minimum_temperature = 1000
for temperature in ambient_temperature:
value = temperature * 9 / 5 + 32
ambient_temperature_fahrenheit.append(value)
average_temperature += value / 8760
if value > maximum_temperature:
maximum_temperature = value
if value < minimum_temperature:
minimum_temperature = value
delta_temperature = maximum_temperature - minimum_temperature
ratio = 0.4 + 0.01 * (average_temperature - 44)
lag = 35 - 1 * (average_temperature - 44)
t_out_fahrenheit = [1.8 * t_out + 32 for t_out in ambient_temperature]
t_out_average = sum(t_out_fahrenheit) / len(t_out_fahrenheit)
max_difference = max(t_out_fahrenheit) - min(t_out_fahrenheit)
ratio = 0.4 + 0.01 * (t_out_average - 44)
lag = 35 - (t_out_average - 35)
number_of_day = [a for a in range(1, 366)]
day_of_year = [day for day in number_of_day for _ in range(24)]
cold_temperature_fahrenheit = []
cold_temperature = []
for temperature in ambient_temperature_fahrenheit:
radians = (0.986 * (temperature-15-lag) - 90) * math.pi / 180
cold_temperature.append((average_temperature + 6 + ratio * (delta_temperature/2) * math.sin(radians) - 32) * 5/9)
for i in range(len(ambient_temperature)):
cold_temperature_fahrenheit.append(t_out_average + 6 + ratio * (max_difference / 2) *
math.sin(math.radians(0.986 * (day_of_year[i] - 15 - lag) - 90)))
cold_temperature.append((cold_temperature_fahrenheit[i] - 32) / 1.8)
return cold_temperature
def epw_file(self, region_code):

View File

@ -0,0 +1,863 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56769087843276,
45.49251875903776
],
[
-73.56765050367694,
45.492560280202284
],
[
-73.5677794213865,
45.49262188364245
],
[
-73.56781916241786,
45.49258006136105
],
[
-73.56769087843276,
45.49251875903776
]
]
]
},
"id": 173347,
"properties": {
"name": "01044617",
"address": "rue Victor-Hugo (MTL) 1666",
"function": "1000",
"height": 9,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56765050367694,
45.492560280202284
],
[
-73.56761436875776,
45.49259744179384
],
[
-73.5676075694645,
45.49260454199484
],
[
-73.56773226889548,
45.49266394156485
],
[
-73.56773726906921,
45.49266624130272
],
[
-73.5677794213865,
45.49262188364245
],
[
-73.56765050367694,
45.492560280202284
]
]
]
},
"id": 173348,
"properties": {
"name": "01044619",
"address": "rue Victor-Hugo (MTL) 1670",
"function": "1000",
"height": 9,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56829026835214,
45.492524742569145
],
[
-73.56849646900322,
45.49262354174874
],
[
-73.56861067001111,
45.492505541343576
],
[
-73.56864076915663,
45.492519941474434
],
[
-73.56866246900178,
45.49249754209202
],
[
-73.56867696946317,
45.49250454136644
],
[
-73.56867726964143,
45.49250414255471
],
[
-73.56881486931461,
45.492362042624144
],
[
-73.56881686903772,
45.492359941181455
],
[
-73.5688004699483,
45.49235084193039
],
[
-73.56882097012145,
45.4923320417195
],
[
-73.56879846891101,
45.49232034109352
],
[
-73.56883736970825,
45.492284841271946
],
[
-73.56886806888434,
45.492256240993704
],
[
-73.56885337003277,
45.49224914198001
],
[
-73.56890226932418,
45.49219894164121
],
[
-73.56851866897392,
45.49201434154299
],
[
-73.56837326884313,
45.492163841620254
],
[
-73.56864696910176,
45.49229554163243
],
[
-73.5685268682051,
45.49241904187041
],
[
-73.56825396962694,
45.49228824183907
],
[
-73.56810906858335,
45.49243794104013
],
[
-73.56829026835214,
45.492524742569145
]
]
]
},
"id": 173403,
"properties": {
"name": "01044334",
"address": "rue Saint-Jacques (MTL) 1460",
"function": "1000",
"height": 15,
"year_of_construction": 1985
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.5683896684674,
45.491800342137736
],
[
-73.56838616878639,
45.49180414157881
],
[
-73.56850686988925,
45.49185994152571
],
[
-73.56851286844197,
45.4918626410622
],
[
-73.56855549071014,
45.49181750806087
],
[
-73.56842962331187,
45.49175738300567
],
[
-73.5683896684674,
45.491800342137736
]
]
]
},
"id": 174898,
"properties": {
"name": "01044590",
"address": "rue Victor-Hugo (MTL) 1600",
"function": "1000",
"height": 9,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.5680637695714,
45.49212884162544
],
[
-73.56802228176146,
45.49217205619571
],
[
-73.56815668696326,
45.49223626189717
],
[
-73.56815766959974,
45.49223524178655
],
[
-73.56818746886172,
45.49224944155107
],
[
-73.56822816806918,
45.49220694186927
],
[
-73.5680637695714,
45.49212884162544
]
]
]
},
"id": 175785,
"properties": {
"name": "01044602",
"address": "rue Victor-Hugo (MTL) 1630",
"function": "1000",
"height": 12,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56850793693103,
45.49167318076048
],
[
-73.56846877951091,
45.4917152818903
],
[
-73.56859506290321,
45.491775605518725
],
[
-73.56863463503653,
45.491733702062774
],
[
-73.56850793693103,
45.49167318076048
]
]
]
},
"id": 175910,
"properties": {
"name": "01044586",
"address": "rue Victor-Hugo (MTL) 1590",
"function": "1000",
"height": 9,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56817543449134,
45.49201384773851
],
[
-73.56813497596143,
45.49205532773507
],
[
-73.56826745951075,
45.492118613912375
],
[
-73.56830763251781,
45.49207699906335
],
[
-73.56817543449134,
45.49201384773851
]
]
]
},
"id": 176056,
"properties": {
"name": "01044599",
"address": "rue Victor-Hugo (MTL) 1620",
"function": "1000",
"height": 8,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56772876855176,
45.49247194194522
],
[
-73.56773406949068,
45.492474341387755
],
[
-73.56773125185198,
45.492477239659124
],
[
-73.56785890467093,
45.492538239964624
],
[
-73.56789966910456,
45.49249534173201
],
[
-73.56776616865103,
45.49243264153464
],
[
-73.56772876855176,
45.49247194194522
]
]
]
},
"id": 176261,
"properties": {
"name": "01044613",
"address": "rue Victor-Hugo (MTL) 1656",
"function": "1000",
"height": 10,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56802228176146,
45.49217205619571
],
[
-73.56798225825526,
45.492213743742184
],
[
-73.56811660206223,
45.49227791893211
],
[
-73.56815668696326,
45.49223626189717
],
[
-73.56802228176146,
45.49217205619571
]
]
]
},
"id": 176293,
"properties": {
"name": "01044604",
"address": "rue Victor-Hugo (MTL) 1636",
"function": "1000",
"height": 12,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56790222258577,
45.49229712328457
],
[
-73.56785996900595,
45.49234104192853
],
[
-73.56799446861396,
45.49240484193282
],
[
-73.56803643080562,
45.49236123475947
],
[
-73.56790222258577,
45.49229712328457
]
]
]
},
"id": 176296,
"properties": {
"name": "01044611",
"address": "rue Victor-Hugo (MTL) 1650",
"function": "1000",
"height": 10,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56798225825526,
45.492213743742184
],
[
-73.56794223597048,
45.4922554321734
],
[
-73.56807651582375,
45.49231957685336
],
[
-73.56811660206223,
45.49227791893211
],
[
-73.56798225825526,
45.492213743742184
]
]
]
},
"id": 176298,
"properties": {
"name": "01044607",
"address": "rue Victor-Hugo (MTL) 1640",
"function": "1000",
"height": 12,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56742736898599,
45.49184704208998
],
[
-73.56761256873325,
45.491896142437554
],
[
-73.56766926915839,
45.4917902412014
],
[
-73.56766956853903,
45.49179024192391
],
[
-73.56792966911675,
45.49183254222432
],
[
-73.56793006788594,
45.491831141828406
],
[
-73.56794526884076,
45.49174634219527
],
[
-73.56794516904765,
45.49174634225465
],
[
-73.56753896905731,
45.491638642248425
],
[
-73.56742736898599,
45.49184704208998
]
]
]
},
"id": 176918,
"properties": {
"name": "01097185",
"address": "rue Victor-Hugo (MTL) 1591",
"function": "1000",
"height": 10,
"year_of_construction": 1987
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56773125185198,
45.492477239659124
],
[
-73.56769087843276,
45.49251875903776
],
[
-73.56781916241786,
45.49258006136105
],
[
-73.56785890467093,
45.492538239964624
],
[
-73.56773125185198,
45.492477239659124
]
]
]
},
"id": 178164,
"properties": {
"name": "01044615",
"address": "rue Victor-Hugo (MTL) 1660",
"function": "1000",
"height": 9,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56846877951091,
45.4917152818903
],
[
-73.56842962331187,
45.49175738300567
],
[
-73.56855549071014,
45.49181750806087
],
[
-73.56859506290321,
45.491775605518725
],
[
-73.56846877951091,
45.4917152818903
]
]
]
},
"id": 179679,
"properties": {
"name": "01044588",
"address": "rue Victor-Hugo (MTL) 1596",
"function": "1000",
"height": 9,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56825635009473,
45.49193088860213
],
[
-73.56821589168355,
45.491972368627906
],
[
-73.5683477837006,
45.4920353716151
],
[
-73.56838787594006,
45.49199371809223
],
[
-73.56825635009473,
45.49193088860213
]
]
]
},
"id": 179789,
"properties": {
"name": "01044595",
"address": "rue Victor-Hugo (MTL) 1610",
"function": "1000",
"height": 8,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56821589168355,
45.491972368627906
],
[
-73.56817543449134,
45.49201384773851
],
[
-73.56830763251781,
45.49207699906335
],
[
-73.5683477837006,
45.4920353716151
],
[
-73.56821589168355,
45.491972368627906
]
]
]
},
"id": 181310,
"properties": {
"name": "01044597",
"address": "rue Victor-Hugo (MTL) 1616",
"function": "1000",
"height": 8,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56809506939487,
45.49209624228538
],
[
-73.56809246893268,
45.4920988416879
],
[
-73.56821287000538,
45.49216124158406
],
[
-73.56822186852654,
45.49216584161625
],
[
-73.56826745951075,
45.492118613912375
],
[
-73.56813497596143,
45.49205532773507
],
[
-73.56809506939487,
45.49209624228538
]
]
]
},
"id": 182393,
"properties": {
"name": "01044601",
"address": "rue Victor-Hugo (MTL) 1626",
"function": "1000",
"height": 8,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56790756893894,
45.492291541967774
],
[
-73.56790222258577,
45.49229712328457
],
[
-73.56803643080562,
45.49236123475947
],
[
-73.56807651582375,
45.49231957685336
],
[
-73.56794223597048,
45.4922554321734
],
[
-73.56790756893894,
45.492291541967774
]
]
]
},
"id": 182442,
"properties": {
"name": "01044609",
"address": "rue Victor-Hugo (MTL) 1646",
"function": "1000",
"height": 11,
"year_of_construction": 1986
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.56829706912258,
45.49188914205178
],
[
-73.56825635009473,
45.49193088860213
],
[
-73.56838787594006,
45.49199371809223
],
[
-73.56842846901456,
45.49195154234486
],
[
-73.56829706912258,
45.49188914205178
]
]
]
},
"id": 182546,
"properties": {
"name": "01044592",
"address": "rue Victor-Hugo (MTL) 1606",
"function": "1000",
"height": 8,
"year_of_construction": 1986
}
}
]
}

View File

@ -0,0 +1,55 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-73.58000127109773,
45.49613461675315
],
[
-73.57962787855432,
45.496524875557746
],
[
-73.57996357265695,
45.49668114195629
],
[
-73.57996427397713,
45.496680342403664
],
[
-73.58034707390021,
45.49625804233725
],
[
-73.58034697395713,
45.496257942524835
],
[
-73.58000127109773,
45.49613461675315
]
]
]
},
"id": 179764,
"properties": {
"name": "01119274",
"address": "rue Guy (MTL) 2157",
"function": "Mixed use",
"mixed_type_1": "commercial",
"mixed_type_1_percentage": 50,
"mixed_type_2": "6000",
"mixed_type_2_percentage": 50,
"height": 62,
"year_of_construction": 1954
}
}
]
}

101
main.py
View File

@ -1,4 +1,3 @@
from scripts.geojson_creator import process_geojson
from pathlib import Path
import subprocess
from scripts.ep_run_enrich import energy_plus_workflow
@ -8,58 +7,80 @@ from hub.imports.construction_factory import ConstructionFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
from hub.imports.results_factory import ResultFactory
from scripts.energy_system_analysis_report import EnergySystemAnalysisReport
from scripts.energy_system_retrofit_report import EnergySystemRetrofitReport
from scripts.geojson_creator import process_geojson
from scripts import random_assignation
from hub.imports.energy_systems_factory import EnergySystemsFactory
from scripts.energy_system_sizing import SystemSizing
from scripts.energy_system_retrofit_results import system_results, new_system_results
from scripts.solar_angles import CitySolarAngles
from scripts.pv_sizing_and_simulation import PVSizingSimulation
from scripts.energy_system_retrofit_results import consumption_data, cost_data
from scripts.energy_system_sizing_and_simulation_factory import EnergySystemsSimulationFactory
from scripts.costs.cost import Cost
from scripts.costs.constants import SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV
from scripts.costs.constants import SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS
import hub.helpers.constants as cte
from hub.exports.exports_factory import ExportsFactory
from scripts.pv_feasibility import pv_feasibility
import matplotlib.pyplot as plt
import numpy as np
# Specify the GeoJSON file path
# geojson_file = process_geojson(x=-73.5953602192335, y=45.492414530022515, diff=0.001)
file_path = (Path(__file__).parent / 'input_files' / 'output_buildings.geojson')
# Specify the output path for the PDF file
data = {}
input_files_path = (Path(__file__).parent / 'input_files')
input_files_path.mkdir(parents=True, exist_ok=True)
# geojson_file = process_geojson(x=-73.58001358793511, y=45.496445294438715, diff=0.0001)
geojson_file_path = input_files_path / 'test_geojson.geojson'
output_path = (Path(__file__).parent / 'out_files').resolve()
# Create city object from GeoJSON file
city = GeometryFactory('geojson',
path=file_path,
output_path.mkdir(parents=True, exist_ok=True)
energy_plus_output_path = output_path / 'energy_plus_outputs'
energy_plus_output_path.mkdir(parents=True, exist_ok=True)
simulation_results_path = (Path(__file__).parent / 'out_files' / 'simulation_results').resolve()
simulation_results_path.mkdir(parents=True, exist_ok=True)
sra_output_path = output_path / 'sra_outputs'
sra_output_path.mkdir(parents=True, exist_ok=True)
cost_analysis_output_path = output_path / 'cost_analysis'
cost_analysis_output_path.mkdir(parents=True, exist_ok=True)
city = GeometryFactory(file_type='geojson',
path=geojson_file_path,
height_field='height',
year_of_construction_field='year_of_construction',
function_field='function',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
# Enrich city data
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
energy_plus_workflow(city)
random_assignation.call_random(city.buildings, random_assignation.residential_systems_percentage)
EnergySystemsFactory('montreal_custom', city).enrich()
SystemSizing(city.buildings).montreal_custom()
current_system = new_system_results(city.buildings)
random_assignation.call_random(city.buildings, random_assignation.residential_new_systems_percentage)
EnergySystemsFactory('montreal_future', city).enrich()
for building in city.buildings:
EnergySystemsSimulationFactory('archetype1', building=building, output_path=output_path).enrich()
print(building.energy_consumption_breakdown[cte.ELECTRICITY][cte.COOLING] +
building.energy_consumption_breakdown[cte.ELECTRICITY][cte.HEATING] +
building.energy_consumption_breakdown[cte.ELECTRICITY][cte.DOMESTIC_HOT_WATER])
new_system = new_system_results(city.buildings)
# EnergySystemAnalysisReport(city, output_path).create_report(current_system, new_system)
for building in city.buildings:
costs = Cost(building=building, retrofit_scenario=SYSTEM_RETROFIT_AND_PV).life_cycle
costs.to_csv(output_path / f'{building.name}_lcc.csv')
(costs.loc['global_operational_costs', f'Scenario {SYSTEM_RETROFIT_AND_PV}'].
to_csv(output_path / f'{building.name}_op.csv'))
costs.loc['global_capital_costs', f'Scenario {SYSTEM_RETROFIT_AND_PV}'].to_csv(
output_path / f'{building.name}_cc.csv')
costs.loc['global_maintenance_costs', f'Scenario {SYSTEM_RETROFIT_AND_PV}'].to_csv(
output_path / f'{building.name}_m.csv')
energy_plus_workflow(city, energy_plus_output_path)
data[f'{city.buildings[0].function}'] = city.buildings[0].heating_demand[cte.YEAR][0] / 3.6e9
city.buildings[0].function = cte.COMMERCIAL
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
energy_plus_workflow(city, energy_plus_output_path)
data[f'{city.buildings[0].function}'] = city.buildings[0].heating_demand[cte.YEAR][0] / 3.6e9
city.buildings[0].function = cte.MEDIUM_OFFICE
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
energy_plus_workflow(city, energy_plus_output_path)
data[f'{city.buildings[0].function}'] = city.buildings[0].heating_demand[cte.YEAR][0] / 3.6e9
categories = list(data.keys())
values = list(data.values())
# Plotting
fig, ax = plt.subplots(figsize=(10, 6), dpi=96)
fig.suptitle('Impact of different usages on yearly heating demand', fontsize=16, weight='bold', alpha=.8)
ax.bar(categories, values, color=['#2196f3', '#ff5a5f', '#4caf50'], width=0.6, zorder=2)
ax.grid(which="major", axis='x', color='#DAD8D7', alpha=0.5, zorder=1)
ax.grid(which="major", axis='y', color='#DAD8D7', alpha=0.5, zorder=1)
ax.set_xlabel('Building Type', fontsize=12, labelpad=10)
ax.set_ylabel('Energy Consumption (MWh)', fontsize=14, labelpad=10)
ax.yaxis.set_major_locator(plt.MaxNLocator(integer=True))
ax.set_xticks(np.arange(len(categories)))
ax.set_xticklabels(categories, rotation=45, ha='right')
ax.bar_label(ax.containers[0], padding=3, color='black', fontsize=12, rotation=0)
ax.spines[['top', 'left', 'bottom']].set_visible(False)
ax.spines['right'].set_linewidth(1.1)
# Set a white background
fig.patch.set_facecolor('white')
# Adjust the margins around the plot area
plt.subplots_adjust(left=0.1, right=0.9, top=0.85, bottom=0.25)
# Save the plot
plt.savefig('plot_nrcan.png', bbox_inches='tight')
plt.close()
print('test')

BIN
plot_nrcan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

73
pv_assessment.py Normal file
View File

@ -0,0 +1,73 @@
import pandas as pd
from scripts.geojson_creator import process_geojson
from pathlib import Path
import subprocess
from hub.imports.geometry_factory import GeometryFactory
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
from hub.imports.results_factory import ResultFactory
from scripts.solar_angles import CitySolarAngles
from scripts.ep_run_enrich import energy_plus_workflow
import hub.helpers.constants as cte
from hub.exports.exports_factory import ExportsFactory
from scripts.pv_sizing_and_simulation import PVSizingSimulation
# Specify the GeoJSON file path
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0005)
file_path = (Path(__file__).parent / 'input_files' / 'output_buildings.geojson')
# Specify the output path for the PDF file
output_path = (Path(__file__).parent / 'out_files').resolve()
# Create city object from GeoJSON file
city = GeometryFactory('geojson',
path=file_path,
height_field='height',
year_of_construction_field='year_of_construction',
function_field='function',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
# Enrich city data
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
ExportsFactory('sra', city, output_path).export()
sra_path = (output_path / f'{city.name}_sra.xml').resolve()
subprocess.run(['sra', str(sra_path)])
ResultFactory('sra', city, output_path).enrich()
energy_plus_workflow(city)
solar_angles = CitySolarAngles(city.name,
city.latitude,
city.longitude,
tilt_angle=45,
surface_azimuth_angle=180).calculate
df = pd.DataFrame()
df.index = ['yearly lighting (kWh)', 'yearly appliance (kWh)', 'yearly heating (kWh)', 'yearly cooling (kWh)',
'yearly dhw (kWh)', 'roof area (m2)', 'used area for pv (m2)', 'number of panels', 'pv production (kWh)']
for building in city.buildings:
ghi = [x / cte.WATTS_HOUR_TO_JULES for x in building.roofs[0].global_irradiance[cte.HOUR]]
pv_sizing_simulation = PVSizingSimulation(building,
solar_angles,
tilt_angle=45,
module_height=1,
module_width=2,
ghi=ghi)
pv_sizing_simulation.pv_output()
yearly_lighting = building.lighting_electrical_demand[cte.YEAR][0] / 1000
yearly_appliance = building.appliances_electrical_demand[cte.YEAR][0] / 1000
yearly_heating = building.heating_demand[cte.YEAR][0] / (3.6e6 * 3)
yearly_cooling = building.cooling_demand[cte.YEAR][0] / (3.6e6 * 4.5)
yearly_dhw = building.domestic_hot_water_heat_demand[cte.YEAR][0] / 1000
roof_area = building.roofs[0].perimeter_area
used_roof = pv_sizing_simulation.available_space()
number_of_pv_panels = pv_sizing_simulation.total_number_of_panels
yearly_pv = building.onsite_electrical_production[cte.YEAR][0] / 1000
df[f'{building.name}'] = [yearly_lighting, yearly_appliance, yearly_heating, yearly_cooling, yearly_dhw, roof_area,
used_roof, number_of_pv_panels, yearly_pv]
df.to_csv(output_path / 'pv.csv')

View File

@ -12,7 +12,8 @@ import numpy_financial as npf
from hub.city_model_structure.building import Building
import hub.helpers.constants as cte
from scripts.costs.configuration import Configuration
from scripts.costs.constants import SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV
from scripts.costs.constants import (SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV,
SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS, PV, SYSTEM_RETROFIT)
from scripts.costs.cost_base import CostBase
@ -31,12 +32,13 @@ class CapitalCosts(CostBase):
'B3010_opaque_roof',
'B1010_superstructure',
'D2010_photovoltaic_system',
'D3020_heat_and_cooling_generating_systems',
'D3040_distribution_systems',
'D3050_other_hvac_ahu',
'D3060_storage_systems',
'D3020_simultaneous_heat_and_cooling_generating_systems',
'D3030_heating_systems',
'D3040_cooling_systems',
'D3050_distribution_systems',
'D3060_other_hvac_ahu',
'D3070_storage_systems',
'D40_dhw',
'D5020_lighting_and_branch_wiring'
],
dtype='float'
)
@ -45,12 +47,13 @@ class CapitalCosts(CostBase):
self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = 0
self._yearly_capital_costs.loc[0, 'B1010_superstructure'] = 0
self._yearly_capital_costs.loc[0, 'D2010_photovoltaic_system'] = 0
self._yearly_capital_costs.loc[0, 'D3020_heat_and_cooling_generating_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3080_other_hvac_ahu'] = 0
self._yearly_capital_costs.loc[0, 'D3060_storage_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3020_simultaneous_heat_and_cooling_generating_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3030_heating_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3040_cooling_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3050_distribution_systems'] = 0
self._yearly_capital_costs.loc[0, 'D3060_other_hvac_ahu'] = 0
self._yearly_capital_costs.loc[0, 'D3070_storage_systems'] = 0
self._yearly_capital_costs.loc[0, 'D40_dhw'] = 0
# self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = 0
self._yearly_capital_incomes = pd.DataFrame(
index=self._rng,
@ -70,12 +73,14 @@ class CapitalCosts(CostBase):
for roof in self._building.roofs:
self._surface_pv += roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor
for roof in self._building.roofs:
if roof.installed_solar_collector_area is not None:
self._surface_pv += roof.installed_solar_collector_area
else:
self._surface_pv += roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor
def calculate(self) -> tuple[pd.DataFrame, pd.DataFrame]:
if self._configuration.retrofit_scenario in (SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
self.skin_capital_cost()
if self._configuration.retrofit_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
self.energy_system_capital_cost()
self.skin_capital_cost()
self.energy_system_capital_cost()
self.skin_yearly_capital_costs()
self.yearly_energy_system_costs()
self.yearly_incomes()
@ -106,10 +111,11 @@ class CapitalCosts(CostBase):
capital_cost_transparent = surface_transparent * chapter.item('B2020_transparent').refurbishment[0]
capital_cost_roof = surface_roof * chapter.item('B3010_opaque_roof').refurbishment[0]
capital_cost_ground = surface_ground * chapter.item('B1010_superstructure').refurbishment[0]
self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = capital_cost_opaque * self._own_capital
self._yearly_capital_costs.loc[0, 'B2020_transparent'] = capital_cost_transparent * self._own_capital
self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = capital_cost_roof * self._own_capital
self._yearly_capital_costs.loc[0, 'B1010_superstructure'] = capital_cost_ground * self._own_capital
if self._configuration.retrofit_scenario not in (SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS, PV, SYSTEM_RETROFIT):
self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = capital_cost_opaque * self._own_capital
self._yearly_capital_costs.loc[0, 'B2020_transparent'] = capital_cost_transparent * self._own_capital
self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = capital_cost_roof * self._own_capital
self._yearly_capital_costs.loc[0, 'B1010_superstructure'] = capital_cost_ground * self._own_capital
capital_cost_skin = capital_cost_opaque + capital_cost_ground + capital_cost_transparent + capital_cost_roof
return capital_cost_opaque, capital_cost_transparent, capital_cost_roof, capital_cost_ground, capital_cost_skin
@ -147,21 +153,22 @@ class CapitalCosts(CostBase):
def energy_system_capital_cost(self):
chapter = self._capital_costs_chapter.chapter('D_services')
energy_system_components = self.system_components()
system_components = energy_system_components[0]
component_categories = energy_system_components[1]
component_sizes = energy_system_components[-1]
system_components, component_categories, component_sizes = self.system_components()
capital_cost_heating_and_cooling_equipment = 0
capital_cost_heating_equipment = 0
capital_cost_cooling_equipment = 0
capital_cost_domestic_hot_water_equipment = 0
capital_cost_energy_storage_equipment = 0
capital_cost_distribution_equipment = 0
capital_cost_lighting = 0
capital_cost_pv = self._surface_pv * chapter.item('D2010_photovoltaic_system').initial_investment[0]
# capital_cost_lighting = self._total_floor_area * \
# chapter.item('D5020_lighting_and_branch_wiring').initial_investment[0]
for (i, component) in enumerate(system_components):
if component_categories[i] == 'generation':
if component_categories[i] == 'multi_generation':
capital_cost_heating_and_cooling_equipment += chapter.item(component).initial_investment[0] * component_sizes[i]
elif component_categories[i] == 'heating':
capital_cost_heating_equipment += chapter.item(component).initial_investment[0] * component_sizes[i]
elif component_categories[i] == 'cooling':
capital_cost_cooling_equipment += chapter.item(component).initial_investment[0] * component_sizes[i]
elif component_categories[i] == 'dhw':
capital_cost_domestic_hot_water_equipment += chapter.item(component).initial_investment[0] * \
component_sizes[i]
@ -171,26 +178,37 @@ class CapitalCosts(CostBase):
else:
capital_cost_energy_storage_equipment += chapter.item(component).initial_investment[0] * component_sizes[i]
self._yearly_capital_costs.loc[0, 'D2010_photovoltaic_system'] = capital_cost_pv
self._yearly_capital_costs.loc[0, 'D3020_heat_and_cooling_generating_systems'] = (
capital_cost_heating_and_cooling_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = (
capital_cost_distribution_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D3060_storage_systems'] = (
capital_cost_energy_storage_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D40_dhw'] = (
capital_cost_domestic_hot_water_equipment * self._own_capital)
# self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = capital_cost_lighting * self._own_capital
capital_cost_hvac = capital_cost_heating_and_cooling_equipment + capital_cost_distribution_equipment + capital_cost_energy_storage_equipment + capital_cost_domestic_hot_water_equipment
return (capital_cost_pv, capital_cost_heating_and_cooling_equipment, capital_cost_distribution_equipment,
capital_cost_energy_storage_equipment, capital_cost_domestic_hot_water_equipment, capital_cost_lighting, capital_cost_hvac)
if self._configuration.retrofit_scenario in (SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV, PV):
self._yearly_capital_costs.loc[0, 'D2010_photovoltaic_system'] = capital_cost_pv
if (self._configuration.retrofit_scenario in
(SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT)):
self._yearly_capital_costs.loc[0, 'D3020_simultaneous_heat_and_cooling_generating_systems'] = (
capital_cost_heating_and_cooling_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D3030_heating_systems'] = (
capital_cost_heating_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D3040_cooling_systems'] = (
capital_cost_cooling_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D3050_distribution_systems'] = (
capital_cost_distribution_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D3070_storage_systems'] = (
capital_cost_energy_storage_equipment * self._own_capital)
self._yearly_capital_costs.loc[0, 'D40_dhw'] = (
capital_cost_domestic_hot_water_equipment * self._own_capital)
capital_cost_hvac = (capital_cost_heating_and_cooling_equipment + capital_cost_distribution_equipment +
capital_cost_energy_storage_equipment + capital_cost_domestic_hot_water_equipment)
return (capital_cost_pv, capital_cost_heating_and_cooling_equipment, capital_cost_heating_equipment,
capital_cost_distribution_equipment, capital_cost_cooling_equipment, capital_cost_energy_storage_equipment,
capital_cost_domestic_hot_water_equipment, capital_cost_lighting, capital_cost_hvac)
def yearly_energy_system_costs(self):
chapter = self._capital_costs_chapter.chapter('D_services')
system_investment_costs = self.energy_system_capital_cost()
system_components = self.system_components()[0]
component_categories = self.system_components()[1]
component_sizes = self.system_components()[2]
system_components, component_categories, component_sizes = self.system_components()
pv = False
for energy_system in self._building.energy_systems:
for generation_system in energy_system.generation_systems:
if generation_system.system_type == cte.PHOTOVOLTAIC:
pv = True
for year in range(1, self._configuration.number_of_years):
costs_increase = math.pow(1 + self._configuration.consumer_price_index, year)
self._yearly_capital_costs.loc[year, 'D2010_photovoltaic_system'] = (
@ -200,65 +218,90 @@ class CapitalCosts(CostBase):
system_investment_costs[0] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'D3020_heat_and_cooling_generating_systems'] = (
self._yearly_capital_costs.loc[year, 'D3020_simultaneous_heat_and_cooling_generating_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
system_investment_costs[1] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'D3040_distribution_systems'] = (
self._yearly_capital_costs.loc[year, 'D3030_heating_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
system_investment_costs[2] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'D3060_storage_systems'] = (
self._yearly_capital_costs.loc[year, 'D3040_cooling_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
system_investment_costs[3] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'D40_dhw'] = (
self._yearly_capital_costs.loc[year, 'D3050_distribution_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
system_investment_costs[4] * self._configuration.percentage_credit
)
)
# self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] = (
# -npf.pmt(
# self._configuration.interest_rate,
# self._configuration.credit_years,
# system_investment_costs[5] * self._configuration.percentage_credit
# )
# )
# if (year % chapter.item('D5020_lighting_and_branch_wiring').lifetime) == 0:
# reposition_cost_lighting = (
# self._total_floor_area * chapter.item('D5020_lighting_and_branch_wiring').reposition[0] * costs_increase
# )
# self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] += reposition_cost_lighting
if self._configuration.retrofit_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
self._yearly_capital_costs.loc[year, 'D3070_storage_systems'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
system_investment_costs[5] * self._configuration.percentage_credit
)
)
self._yearly_capital_costs.loc[year, 'D40_dhw'] = (
-npf.pmt(
self._configuration.interest_rate,
self._configuration.credit_years,
system_investment_costs[6] * self._configuration.percentage_credit
)
)
if self._configuration.retrofit_scenario not in (SKIN_RETROFIT, PV):
for (i, component) in enumerate(system_components):
if (year % chapter.item(component).lifetime) == 0 and year != (self._configuration.number_of_years - 1):
if component_categories[i] == 'multi_generation':
reposition_cost_heating_and_cooling_equipment = (chapter.item(component).reposition[0] *
component_sizes[i] * costs_increase)
self._yearly_capital_costs.loc[year, 'D3020_simultaneous_heat_and_cooling_generating_systems'] += (
reposition_cost_heating_and_cooling_equipment)
elif component_categories[i] == 'heating':
reposition_cost_heating_equipment = (chapter.item(component).reposition[0] *
component_sizes[i] * costs_increase)
self._yearly_capital_costs.loc[year, 'D3030_heating_systems'] += (
reposition_cost_heating_equipment)
elif component_categories[i] == 'cooling':
reposition_cost_cooling_equipment = (chapter.item(component).reposition[0] *
component_sizes[i] * costs_increase)
self._yearly_capital_costs.loc[year, 'D3040_cooling_systems'] += (
reposition_cost_cooling_equipment)
elif component_categories[i] == 'dhw':
reposition_cost_domestic_hot_water_equipment = (
chapter.item(component).reposition[0] * component_sizes[i] * costs_increase)
self._yearly_capital_costs.loc[year, 'D40_dhw'] += reposition_cost_domestic_hot_water_equipment
elif component_categories[i] == 'distribution':
reposition_cost_distribution_equipment = (
chapter.item(component).reposition[0] * component_sizes[i] * costs_increase)
self._yearly_capital_costs.loc[year, 'D3050_distribution_systems'] += (
reposition_cost_distribution_equipment)
else:
reposition_cost_energy_storage_equipment = (
chapter.item(component).initial_investment[0] * component_sizes[i] * costs_increase)
self._yearly_capital_costs.loc[year, 'D3070_storage_systems'] += reposition_cost_energy_storage_equipment
if self._configuration.retrofit_scenario == CURRENT_STATUS and pv:
if (year % chapter.item('D2010_photovoltaic_system').lifetime) == 0:
self._yearly_capital_costs.loc[year, 'D2010_photovoltaic_system'] += (
self._surface_pv * chapter.item('D2010_photovoltaic_system').reposition[0] * costs_increase
)
elif self._configuration.retrofit_scenario in (PV, SYSTEM_RETROFIT_AND_PV,
SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV):
if (year % chapter.item('D2010_photovoltaic_system').lifetime) == 0:
self._yearly_capital_costs.loc[year, 'D2010_photovoltaic_system'] += (
self._surface_pv * chapter.item('D2010_photovoltaic_system').reposition[0] * costs_increase
)
for (i, component) in enumerate(system_components):
if (year % chapter.item(component).lifetime) == 0 and year != (self._configuration.number_of_years - 1):
if component_categories[i] == 'generation':
reposition_cost_heating_and_cooling_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase
self._yearly_capital_costs.loc[year, 'D3020_heat_and_cooling_generating_systems'] += reposition_cost_heating_and_cooling_equipment
elif component_categories[i] == 'dhw':
reposition_cost_domestic_hot_water_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase
self._yearly_capital_costs.loc[year, 'D40_dhw'] += reposition_cost_domestic_hot_water_equipment
elif component_categories[i] == 'distribution':
reposition_cost_distribution_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase
self._yearly_capital_costs.loc[year, 'D3040_distribution_systems'] += reposition_cost_distribution_equipment
else:
reposition_cost_energy_storage_equipment = chapter.item(component).initial_investment[0] * component_sizes[i] * costs_increase
self._yearly_capital_costs.loc[year, 'D3060_storage_systems'] += reposition_cost_energy_storage_equipment
def system_components(self):
system_components = []
@ -283,8 +326,11 @@ class CapitalCosts(CostBase):
system_components.append(self.boiler_type(generation_system))
else:
system_components.append('D302010_template_heat')
elif cte.HEATING or cte.COOLING in demand_types:
component_categories.append('generation')
elif cte.HEATING in demand_types:
if cte.COOLING in demand_types and generation_system.fuel_type == cte.ELECTRICITY:
component_categories.append('multi_generation')
else:
component_categories.append('heating')
sizes.append(installed_capacity)
if generation_system.system_type == cte.HEAT_PUMP:
item_type = self.heat_pump_type(generation_system)
@ -293,11 +339,18 @@ class CapitalCosts(CostBase):
item_type = self.boiler_type(generation_system)
system_components.append(item_type)
else:
if cte.COOLING in demand_types and cte.HEATING not in demand_types:
if cooling_capacity > heating_capacity:
system_components.append('D302090_template_cooling')
else:
system_components.append('D302010_template_heat')
elif cte.COOLING in demand_types:
component_categories.append('cooling')
sizes.append(installed_capacity)
if generation_system.system_type == cte.HEAT_PUMP:
item_type = self.heat_pump_type(generation_system)
system_components.append(item_type)
else:
system_components.append('D302090_template_cooling')
if generation_system.energy_storage_systems is not None:
energy_storage_systems = generation_system.energy_storage_systems
for storage_system in energy_storage_systems:
@ -308,7 +361,7 @@ class CapitalCosts(CostBase):
if distribution_systems is not None:
for distribution_system in distribution_systems:
component_categories.append('distribution')
sizes.append(self._building.cooling_peak_load[cte.YEAR][0] / 3.6e6)
sizes.append(self._building.cooling_peak_load[cte.YEAR][0] / 1000)
system_components.append('D3040_distribution_systems')
return system_components, component_categories, sizes

View File

@ -28,7 +28,8 @@ class Configuration:
factories_handler,
retrofit_scenario,
fuel_type,
dictionary
dictionary,
fuel_tariffs
):
self._number_of_years = number_of_years
self._percentage_credit = percentage_credit
@ -45,6 +46,7 @@ class Configuration:
self._retrofit_scenario = retrofit_scenario
self._fuel_type = fuel_type
self._dictionary = dictionary
self._fuel_tariffs = fuel_tariffs
@property
def number_of_years(self):
@ -227,3 +229,10 @@ class Configuration:
Get hub function to cost function dictionary
"""
return self._dictionary
@property
def fuel_tariffs(self):
"""
Get fuel tariffs
"""
return self._fuel_tariffs

View File

@ -11,9 +11,13 @@ CURRENT_STATUS = 0
SKIN_RETROFIT = 1
SYSTEM_RETROFIT_AND_PV = 2
SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV = 3
PV = 4
SYSTEM_RETROFIT = 5
RETROFITTING_SCENARIOS = [
CURRENT_STATUS,
SKIN_RETROFIT,
SYSTEM_RETROFIT_AND_PV,
SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV
SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV,
PV,
SYSTEM_RETROFIT
]

View File

@ -40,7 +40,10 @@ class Cost:
retrofitting_year_construction=2020,
factories_handler='montreal_new',
retrofit_scenario=CURRENT_STATUS,
dictionary=None):
dictionary=None,
fuel_tariffs=None):
if fuel_tariffs is None:
fuel_tariffs = ['Electricity-D', 'Gas-Energir']
if dictionary is None:
dictionary = Dictionaries().hub_function_to_montreal_custom_costs_function
self._building = building
@ -57,7 +60,8 @@ class Cost:
factories_handler,
retrofit_scenario,
fuel_type,
dictionary)
dictionary,
fuel_tariffs)
@property
def building(self) -> Building:
@ -89,12 +93,13 @@ class Cost:
global_capital_costs['B1010_superstructure']
)
df_capital_costs_systems = (
global_capital_costs['D3020_heat_and_cooling_generating_systems'] +
global_capital_costs['D3040_distribution_systems'] +
global_capital_costs['D3050_other_hvac_ahu'] +
global_capital_costs['D3060_storage_systems'] +
global_capital_costs['D3020_simultaneous_heat_and_cooling_generating_systems'] +
global_capital_costs['D3030_heating_systems'] +
global_capital_costs['D3040_cooling_systems'] +
global_capital_costs['D3050_distribution_systems'] +
global_capital_costs['D3060_other_hvac_ahu'] +
global_capital_costs['D3070_storage_systems'] +
global_capital_costs['D40_dhw'] +
global_capital_costs['D5020_lighting_and_branch_wiring'] +
global_capital_costs['D2010_photovoltaic_system']
)

View File

@ -45,7 +45,7 @@ class PeakLoad:
conditioning_peak[i] = self._building.heating_peak_load[cte.MONTH][i] * heating
else:
conditioning_peak[i] = self._building.cooling_peak_load[cte.MONTH][i] * cooling
monthly_electricity_peak[i] += 0.8 * conditioning_peak[i] / 3600
monthly_electricity_peak[i] += 0.8 * conditioning_peak[i]
electricity_peak_load_results = pd.DataFrame(
monthly_electricity_peak,

View File

@ -25,6 +25,7 @@ class TotalMaintenanceCosts(CostBase):
columns=[
'Heating_maintenance',
'Cooling_maintenance',
'DHW_maintenance',
'PV_maintenance'
],
dtype='float'
@ -39,15 +40,77 @@ class TotalMaintenanceCosts(CostBase):
archetype = self._archetype
# todo: change area pv when the variable exists
roof_area = 0
for roof in building.roofs:
roof_area += roof.solid_polygon.area
surface_pv = roof_area * 0.5
surface_pv = 0
for roof in self._building.roofs:
if roof.installed_solar_collector_area is not None:
surface_pv += roof.installed_solar_collector_area
else:
surface_pv = roof_area * 0.5
peak_heating = building.heating_peak_load[cte.YEAR][0] / 3.6e6
peak_cooling = building.cooling_peak_load[cte.YEAR][0] / 3.6e6
energy_systems = building.energy_systems
maintenance_heating_0 = 0
maintenance_cooling_0 = 0
maintenance_dhw_0 = 0
heating_equipments = {}
cooling_equipments = {}
dhw_equipments = {}
for energy_system in energy_systems:
if cte.COOLING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
if generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.AIR:
cooling_equipments['air_source_heat_pump'] = generation_system.nominal_cooling_output / 1000
elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.GROUND:
cooling_equipments['ground_source_heat_pump'] = generation_system.nominal_cooling_output / 1000
elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.WATER:
cooling_equipments['water_source_heat_pump'] = generation_system.nominal_cooling_output / 1000
else:
cooling_equipments['general_cooling_equipment'] = generation_system.nominal_cooling_output / 1000
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.AIR:
heating_equipments['air_source_heat_pump'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.GROUND:
heating_equipments['ground_source_heat_pump'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.WATER:
heating_equipments['water_source_heat_pump'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.BOILER and generation_system.fuel_type == cte.GAS:
heating_equipments['gas_boiler'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.BOILER and generation_system.fuel_type == cte.ELECTRICITY:
heating_equipments['electric_boiler'] = generation_system.nominal_heat_output / 1000
else:
heating_equipments['general_heating_equipment'] = generation_system.nominal_heat_output / 1000
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types and cte.HEATING not in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.AIR:
dhw_equipments['air_source_heat_pump'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.GROUND:
dhw_equipments['ground_source_heat_pump'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.WATER:
dhw_equipments['water_source_heat_pump'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.BOILER and generation_system.fuel_type == cte.GAS:
dhw_equipments['gas_boiler'] = generation_system.nominal_heat_output / 1000
elif generation_system.system_type == cte.BOILER and generation_system.fuel_type == cte.ELECTRICITY:
dhw_equipments['electric_boiler'] = generation_system.nominal_heat_output / 1000
else:
dhw_equipments['general_heating_equipment'] = generation_system.nominal_heat_output / 1000
for heating_equipment in heating_equipments:
component = self.search_hvac_equipment(heating_equipment)
maintenance_cost = component.maintenance[0]
maintenance_heating_0 += (heating_equipments[heating_equipment] * maintenance_cost)
for cooling_equipment in cooling_equipments:
component = self.search_hvac_equipment(cooling_equipment)
maintenance_cost = component.maintenance[0]
maintenance_cooling_0 += (cooling_equipments[cooling_equipment] * maintenance_cost)
for dhw_equipment in dhw_equipments:
component = self.search_hvac_equipment(dhw_equipment)
maintenance_cost = component.maintenance[0]
maintenance_dhw_0 += (dhw_equipments[dhw_equipment] * maintenance_cost)
maintenance_heating_0 = peak_heating * archetype.operational_cost.maintenance_heating
maintenance_cooling_0 = peak_cooling * archetype.operational_cost.maintenance_cooling
maintenance_pv_0 = surface_pv * archetype.operational_cost.maintenance_pv
for year in range(1, self._configuration.number_of_years + 1):
@ -58,8 +121,18 @@ class TotalMaintenanceCosts(CostBase):
self._yearly_maintenance_costs.loc[year, 'Cooling_maintenance'] = (
maintenance_cooling_0 * costs_increase
)
self._yearly_maintenance_costs.loc[year, 'DHW_maintenance'] = (
maintenance_dhw_0 * costs_increase
)
self._yearly_maintenance_costs.loc[year, 'PV_maintenance'] = (
maintenance_pv_0 * costs_increase
)
self._yearly_maintenance_costs.fillna(0, inplace=True)
return self._yearly_maintenance_costs
def search_hvac_equipment(self, equipment_type):
for component in self._archetype.operational_cost.maintenance_hvac:
if component.type == equipment_type:
return component

View File

@ -42,48 +42,68 @@ class TotalOperationalCosts(CostBase):
factor = total_floor_area / 80
else:
factor = 1
total_electricity_consumption = sum(self._building.energy_consumption_breakdown[cte.ELECTRICITY].values())
total_electricity_consumption = sum(self._building.energy_consumption_breakdown[cte.ELECTRICITY].values()) / 3600
peak_electricity_load = PeakLoad(self._building).electricity_peak_load
peak_load_value = peak_electricity_load.max(axis=1)
peak_electricity_demand = peak_load_value[1] / 1000 # self._peak_electricity_demand adapted to kW
fuels = archetype.operational_cost.fuels
for fuel in fuels:
if fuel.type in fuel_consumption_breakdown.keys():
if fuel.type == cte.ELECTRICITY:
for system_fuel in self._configuration.fuel_type:
fuel = None
for fuel_tariff in self._configuration.fuel_tariffs:
if system_fuel in fuel_tariff:
fuel = self.search_fuel(system_fuel, fuel_tariff)
if fuel.type == cte.ELECTRICITY:
if fuel.variable.rate_type == 'fixed':
variable_electricity_cost_year_0 = (
total_electricity_consumption * fuel.variable[0] / 1000
total_electricity_consumption * float(fuel.variable.values[0]) / 1000
)
peak_electricity_cost_year_0 = peak_electricity_demand * fuel.fixed_power * 12
monthly_electricity_cost_year_0 = fuel.fixed_monthly * 12 * factor
for year in range(1, self._configuration.number_of_years + 1):
price_increase_electricity = math.pow(1 + self._configuration.electricity_price_index, year)
price_increase_peak_electricity = math.pow(1 + self._configuration.electricity_peak_index, year)
self._yearly_operational_costs.at[year, 'Fixed Costs Electricity Peak'] = (
peak_electricity_cost_year_0 * price_increase_peak_electricity
)
self._yearly_operational_costs.at[year, 'Fixed Costs Electricity Monthly'] = (
monthly_electricity_cost_year_0 * price_increase_peak_electricity
)
if not isinstance(variable_electricity_cost_year_0, pd.DataFrame):
variable_costs_electricity = variable_electricity_cost_year_0 * price_increase_electricity
else:
variable_costs_electricity = float(variable_electricity_cost_year_0.iloc[0] * price_increase_electricity)
self._yearly_operational_costs.at[year, 'Variable Costs Electricity'] = (
variable_costs_electricity
)
else:
fuel_fixed_cost = fuel.fixed_monthly * 12 * factor
if fuel.type == cte.BIOMASS:
conversion_factor = 1
hourly_electricity_consumption = self.hourly_fuel_consumption_profile(fuel.type)
hourly_electricity_price_profile = fuel.variable.values * len(hourly_electricity_consumption)
hourly_electricity_price = [hourly_electricity_consumption[i] / 1000 * hourly_electricity_price_profile[i]
for i in range(len(hourly_electricity_consumption))]
variable_electricity_cost_year_0 = sum(hourly_electricity_price)
peak_electricity_cost_year_0 = peak_electricity_demand * fuel.fixed_power * 12
monthly_electricity_cost_year_0 = fuel.fixed_monthly * 12 * factor
for year in range(1, self._configuration.number_of_years + 1):
price_increase_electricity = math.pow(1 + self._configuration.electricity_price_index, year)
price_increase_peak_electricity = math.pow(1 + self._configuration.electricity_peak_index, year)
self._yearly_operational_costs.at[year, 'Fixed Costs Electricity Peak'] = (
peak_electricity_cost_year_0 * price_increase_peak_electricity
)
self._yearly_operational_costs.at[year, 'Fixed Costs Electricity Monthly'] = (
monthly_electricity_cost_year_0 * price_increase_peak_electricity
)
if not isinstance(variable_electricity_cost_year_0, pd.DataFrame):
variable_costs_electricity = variable_electricity_cost_year_0 * price_increase_electricity
else:
conversion_factor = fuel.density[0]
variable_costs_electricity = float(variable_electricity_cost_year_0.iloc[0] * price_increase_electricity)
self._yearly_operational_costs.at[year, 'Variable Costs Electricity'] = (
variable_costs_electricity
)
else:
fuel_fixed_cost = fuel.fixed_monthly * 12 * factor
if fuel.type == cte.BIOMASS:
conversion_factor = 1
else:
conversion_factor = fuel.density[0]
if fuel.variable.rate_type == 'fixed':
variable_cost_fuel = (
((sum(fuel_consumption_breakdown[fuel.type].values()) * 3600)/(1e6*fuel.lower_heating_value[0] * conversion_factor)) * fuel.variable[0])
for year in range(1, self._configuration.number_of_years + 1):
price_increase_gas = math.pow(1 + self._configuration.gas_price_index, year)
self._yearly_operational_costs.at[year, f'Fixed Costs {fuel.type}'] = fuel_fixed_cost * price_increase_gas
self._yearly_operational_costs.at[year, f'Variable Costs {fuel.type}'] = (
variable_cost_fuel * price_increase_gas)
(sum(fuel_consumption_breakdown[fuel.type].values()) / (
1e6 * fuel.lower_heating_value[0] * conversion_factor)) * fuel.variable.values[0])
else:
hourly_fuel_consumption = self.hourly_fuel_consumption_profile(fuel.type)
hourly_fuel_price_profile = fuel.variable.values * len(hourly_fuel_consumption)
hourly_fuel_price = [hourly_fuel_consumption[i] / (
1e6 * fuel.lower_heating_value[0] * conversion_factor) * hourly_fuel_price_profile[i]
for i in range(len(hourly_fuel_consumption))]
variable_cost_fuel = sum(hourly_fuel_price)
for year in range(1, self._configuration.number_of_years + 1):
price_increase_gas = math.pow(1 + self._configuration.gas_price_index, year)
self._yearly_operational_costs.at[year, f'Fixed Costs {fuel.type}'] = fuel_fixed_cost * price_increase_gas
self._yearly_operational_costs.at[year, f'Variable Costs {fuel.type}'] = (
variable_cost_fuel * price_increase_gas)
self._yearly_operational_costs.fillna(0, inplace=True)
return self._yearly_operational_costs
@ -102,3 +122,116 @@ class TotalOperationalCosts(CostBase):
return columns_list
def search_fuel(self, system_fuel, tariff):
fuels = self._archetype.operational_cost.fuels
for fuel in fuels:
if system_fuel == fuel.type and tariff == fuel.variable.name:
return fuel
raise KeyError(f'fuel {system_fuel} with {tariff} tariff not found')
def hourly_fuel_consumption_profile(self, fuel_type):
hourly_fuel_consumption = []
energy_systems = self._building.energy_systems
if fuel_type == cte.ELECTRICITY:
appliance = self._building.appliances_electrical_demand[cte.HOUR]
lighting = self._building.lighting_electrical_demand[cte.HOUR]
elec_heating = 0
elec_cooling = 0
elec_dhw = 0
if cte.HEATING in self._building.energy_consumption_breakdown[cte.ELECTRICITY]:
elec_heating = 1
if cte.COOLING in self._building.energy_consumption_breakdown[cte.ELECTRICITY]:
elec_cooling = 1
if cte.DOMESTIC_HOT_WATER in self._building.energy_consumption_breakdown[cte.ELECTRICITY]:
elec_dhw = 1
heating = None
cooling = None
dhw = None
if elec_heating == 1:
for energy_system in energy_systems:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
if cte.HEATING in generation_system.energy_consumption:
heating = generation_system.energy_consumption[cte.HEATING][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
heating = [x / 2 for x in self._building.heating_consumption[cte.HOUR]]
else:
heating = self._building.heating_consumption[cte.HOUR]
if elec_dhw == 1:
for energy_system in energy_systems:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
if cte.DOMESTIC_HOT_WATER in generation_system.energy_consumption:
dhw = generation_system.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
dhw = [x / 2 for x in self._building.domestic_hot_water_consumption[cte.HOUR]]
else:
dhw = self._building.domestic_hot_water_consumption[cte.HOUR]
if elec_cooling == 1:
for energy_system in energy_systems:
if cte.COOLING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if cte.COOLING in generation_system.energy_consumption:
cooling = generation_system.energy_consumption[cte.COOLING][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
cooling = [x / 2 for x in self._building.cooling_consumption[cte.HOUR]]
else:
cooling = self._building.cooling_consumption[cte.HOUR]
for i in range(len(self._building.heating_demand[cte.HOUR])):
hourly = 0
hourly += appliance[i] / 3600
hourly += lighting[i] / 3600
if heating is not None:
hourly += heating[i] / 3600
if cooling is not None:
hourly += cooling[i] / 3600
if dhw is not None:
hourly += dhw[i] / 3600
hourly_fuel_consumption.append(hourly)
else:
heating = None
dhw = None
if cte.HEATING in self._building.energy_consumption_breakdown[fuel_type]:
for energy_system in energy_systems:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if cte.HEATING in generation_system.energy_consumption:
heating = generation_system.energy_consumption[cte.HEATING][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
heating = [x / 2 for x in self._building.heating_consumption[cte.HOUR]]
else:
heating = self._building.heating_consumption[cte.HOUR]
if cte.DOMESTIC_HOT_WATER in self._building.energy_consumption_breakdown[fuel_type]:
for energy_system in energy_systems:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if cte.DOMESTIC_HOT_WATER in generation_system.energy_consumption:
dhw = generation_system.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
dhw = [x / 2 for x in self._building.domestic_hot_water_consumption[cte.HOUR]]
else:
dhw = self._building.domestic_hot_water_consumption[cte.HOUR]
for i in range(len(self._building.heating_demand[cte.HOUR])):
hourly = 0
if heating is not None:
hourly += heating[i] / 3600
if dhw is not None:
hourly += dhw[i] / 3600
hourly_fuel_consumption.append(hourly)
return hourly_fuel_consumption

View File

@ -33,14 +33,12 @@ class TotalOperationalIncomes(CostBase):
onsite_electricity_production = 0
else:
onsite_electricity_production = building.onsite_electrical_production[cte.YEAR][0]
for year in range(1, self._configuration.number_of_years + 1):
price_increase_electricity = math.pow(1 + self._configuration.electricity_price_index, year)
# todo: check the adequate assignation of price. Pilar
price_export = archetype.income.electricity_export * cte.WATTS_HOUR_TO_JULES * 1000 # to account for unit change
price_export = archetype.income.electricity_export # to account for unit change
self._yearly_operational_incomes.loc[year, 'Incomes electricity'] = (
onsite_electricity_production * price_export * price_increase_electricity
(onsite_electricity_production / 3.6e6) * price_export * price_increase_electricity
)
self._yearly_operational_incomes.fillna(0, inplace=True)
return self._yearly_operational_incomes
return self._yearly_operational_incomes

View File

@ -1,338 +0,0 @@
import os
import hub.helpers.constants as cte
import matplotlib.pyplot as plt
import random
import matplotlib.colors as mcolors
from matplotlib import cm
from scripts.report_creation import LatexReport
class EnergySystemAnalysisReport:
def __init__(self, city, output_path):
self.city = city
self.output_path = output_path
self.content = []
self.report = LatexReport('energy_system_analysis_report.tex')
def building_energy_info(self):
table_data = [
["Building Name", "Year of Construction", "function", "Yearly Heating Demand (MWh)",
"Yearly Cooling Demand (MWh)", "Yearly DHW Demand (MWh)", "Yearly Electricity Demand (MWh)"]
]
intensity_table_data = [["Building Name", "Total Floor Area m2", "Heating Demand Intensity kWh/m2",
"Cooling Demand Intensity kWh/m2", "Electricity Intensity kWh/m2"]]
for building in self.city.buildings:
total_floor_area = 0
for zone in building.thermal_zones_from_internal_zones:
total_floor_area += zone.total_floor_area
building_data = [
building.name,
str(building.year_of_construction),
building.function,
str(format(building.heating_demand[cte.YEAR][0] / 3.6e9, '.2f')),
str(format(building.cooling_demand[cte.YEAR][0] / 3.6e9, '.2f')),
str(format(building.domestic_hot_water_heat_demand[cte.YEAR][0] / 1e6, '.2f')),
str(format(
(building.lighting_electrical_demand[cte.YEAR][0] + building.appliances_electrical_demand[cte.YEAR][0])
/ 1e6, '.2f')),
]
intensity_data = [
building.name,
str(format(total_floor_area, '.2f')),
str(format(building.heating_demand[cte.YEAR][0] / (3.6e6 * total_floor_area), '.2f')),
str(format(building.cooling_demand[cte.YEAR][0] / (3.6e6 * total_floor_area), '.2f')),
str(format(
(building.lighting_electrical_demand[cte.YEAR][0] + building.appliances_electrical_demand[cte.YEAR][0]) /
(1e3 * total_floor_area), '.2f'))
]
table_data.append(building_data)
intensity_table_data.append(intensity_data)
self.report.add_table(table_data, caption='City Buildings Energy Demands')
self.report.add_table(intensity_table_data, caption='Energy Intensity Information')
def base_case_charts(self):
save_directory = self.output_path
def autolabel(bars, ax):
for bar in bars:
height = bar.get_height()
ax.annotate('{:.1f}'.format(height),
xy=(bar.get_x() + bar.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom')
def create_hvac_demand_chart(building_names, yearly_heating_demand, yearly_cooling_demand):
fig, ax = plt.subplots()
bar_width = 0.35
index = range(len(building_names))
bars1 = ax.bar(index, yearly_heating_demand, bar_width, label='Yearly Heating Demand (MWh)')
bars2 = ax.bar([i + bar_width for i in index], yearly_cooling_demand, bar_width,
label='Yearly Cooling Demand (MWh)')
ax.set_xlabel('Building Name')
ax.set_ylabel('Energy Demand (MWh)')
ax.set_title('Yearly HVAC Demands')
ax.set_xticks([i + bar_width / 2 for i in index])
ax.set_xticklabels(building_names, rotation=45, ha='right')
ax.legend()
autolabel(bars1, ax)
autolabel(bars2, ax)
fig.tight_layout()
plt.savefig(save_directory / 'hvac_demand_chart.jpg')
plt.close()
def create_bar_chart(title, ylabel, data, filename, bar_color=None):
fig, ax = plt.subplots()
bar_width = 0.35
index = range(len(building_names))
if bar_color is None:
# Generate a random color
bar_color = random.choice(list(mcolors.CSS4_COLORS.values()))
bars = ax.bar(index, data, bar_width, label=ylabel, color=bar_color)
ax.set_xlabel('Building Name')
ax.set_ylabel('Energy Demand (MWh)')
ax.set_title(title)
ax.set_xticks([i + bar_width / 2 for i in index])
ax.set_xticklabels(building_names, rotation=45, ha='right')
ax.legend()
autolabel(bars, ax)
fig.tight_layout()
plt.savefig(save_directory / filename)
plt.close()
building_names = [building.name for building in self.city.buildings]
yearly_heating_demand = [building.heating_demand[cte.YEAR][0] / 3.6e9 for building in self.city.buildings]
yearly_cooling_demand = [building.cooling_demand[cte.YEAR][0] / 3.6e9 for building in self.city.buildings]
yearly_dhw_demand = [building.domestic_hot_water_heat_demand[cte.YEAR][0] / 1e6 for building in
self.city.buildings]
yearly_electricity_demand = [(building.lighting_electrical_demand[cte.YEAR][0] +
building.appliances_electrical_demand[cte.YEAR][0]) / 1e6 for building in
self.city.buildings]
create_hvac_demand_chart(building_names, yearly_heating_demand, yearly_cooling_demand)
create_bar_chart('Yearly DHW Demands', 'Energy Demand (MWh)', yearly_dhw_demand, 'dhw_demand_chart.jpg', )
create_bar_chart('Yearly Electricity Demands', 'Energy Demand (MWh)', yearly_electricity_demand,
'electricity_demand_chart.jpg')
def maximum_monthly_hvac_chart(self):
save_directory = self.output_path
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October',
'November', 'December']
for building in self.city.buildings:
maximum_monthly_heating_load = []
maximum_monthly_cooling_load = []
fig, axs = plt.subplots(1, 2, figsize=(12, 6)) # Create a figure with 2 subplots side by side
for demand in building.heating_peak_load[cte.MONTH]:
maximum_monthly_heating_load.append(demand / 3.6e6)
for demand in building.cooling_peak_load[cte.MONTH]:
maximum_monthly_cooling_load.append(demand / 3.6e6)
# Plot maximum monthly heating load
axs[0].bar(months, maximum_monthly_heating_load, color='red') # Plot on the first subplot
axs[0].set_title('Maximum Monthly Heating Load')
axs[0].set_xlabel('Month')
axs[0].set_ylabel('Load (kWh)')
axs[0].tick_params(axis='x', rotation=45)
# Plot maximum monthly cooling load
axs[1].bar(months, maximum_monthly_cooling_load, color='blue') # Plot on the second subplot
axs[1].set_title('Maximum Monthly Cooling Load')
axs[1].set_xlabel('Month')
axs[1].set_ylabel('Load (kWh)')
axs[1].tick_params(axis='x', rotation=45)
plt.tight_layout() # Adjust layout to prevent overlapping
plt.savefig(save_directory / f'{building.name}_monthly_maximum_hvac_loads.jpg')
plt.close()
def load_duration_curves(self):
save_directory = self.output_path
for building in self.city.buildings:
heating_demand = [demand / 3.6e6 for demand in building.heating_demand[cte.HOUR]]
cooling_demand = [demand / 3.6e6 for demand in building.cooling_demand[cte.HOUR]]
heating_demand_sorted = sorted(heating_demand, reverse=True)
cooling_demand_sorted = sorted(cooling_demand, reverse=True)
plt.style.use('ggplot')
# Create figure and axis objects with 1 row and 2 columns
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
# Plot sorted heating demand
axs[0].plot(heating_demand_sorted, color='red', linewidth=2, label='Heating Demand')
axs[0].set_xlabel('Hour', fontsize=14)
axs[0].set_ylabel('Heating Demand (kWh)', fontsize=14)
axs[0].set_title('Heating Load Duration Curve', fontsize=16)
axs[0].grid(True)
axs[0].legend(loc='upper right', fontsize=12)
# Plot sorted cooling demand
axs[1].plot(cooling_demand_sorted, color='blue', linewidth=2, label='Cooling Demand')
axs[1].set_xlabel('Hour', fontsize=14)
axs[1].set_ylabel('Cooling Demand (kWh)', fontsize=14)
axs[1].set_title('Cooling Load Duration Curve', fontsize=16)
axs[1].grid(True)
axs[1].legend(loc='upper right', fontsize=12)
# Adjust layout
plt.tight_layout()
plt.savefig(save_directory / f'{building.name}_load_duration_curve.jpg')
plt.close()
def individual_building_info(self, building):
table_data = [
["Maximum Monthly HVAC Demands",
f"\\includegraphics[width=1\\linewidth]{{{building.name}_monthly_maximum_hvac_loads.jpg}}"],
["Load Duration Curve", f"\\includegraphics[width=1\\linewidth]{{{building.name}_load_duration_curve.jpg}}"],
]
self.report.add_table(table_data, caption=f'{building.name} Information', first_column_width=1.5)
def building_system_retrofit_results(self, building_name, current_system, new_system):
current_system_archetype = current_system[f'{building_name}']['Energy System Archetype']
current_system_heating = current_system[f'{building_name}']['Heating Equipments']
current_system_cooling = current_system[f'{building_name}']['Cooling Equipments']
current_system_dhw = current_system[f'{building_name}']['DHW Equipments']
current_system_pv = current_system[f'{building_name}']['Photovoltaic System Capacity']
current_system_heating_fuel = current_system[f'{building_name}']['Heating Fuel']
current_system_hvac_consumption = current_system[f'{building_name}']['Yearly HVAC Energy Consumption (MWh)']
current_system_dhw_consumption = current_system[f'{building_name}']['DHW Energy Consumption (MWH)']
current_pv_production = current_system[f'{building_name}']['PV Yearly Production (kWh)']
current_capital_cost = current_system[f'{building_name}']['Energy System Capital Cost (CAD)']
current_operational = current_system[f'{building_name}']['Energy System Average Yearly Operational Cost (CAD)']
current_lcc = current_system[f'{building_name}']['Energy System Life Cycle Cost (CAD)']
new_system_archetype = new_system[f'{building_name}']['Energy System Archetype']
new_system_heating = new_system[f'{building_name}']['Heating Equipments']
new_system_cooling = new_system[f'{building_name}']['Cooling Equipments']
new_system_dhw = new_system[f'{building_name}']['DHW Equipments']
new_system_pv = new_system[f'{building_name}']['Photovoltaic System Capacity']
new_system_heating_fuel = new_system[f'{building_name}']['Heating Fuel']
new_system_hvac_consumption = new_system[f'{building_name}']['Yearly HVAC Energy Consumption (MWh)']
new_system_dhw_consumption = new_system[f'{building_name}']['DHW Energy Consumption (MWH)']
new_pv_production = new_system[f'{building_name}']['PV Yearly Production (kWh)']
new_capital_cost = new_system[f'{building_name}']['Energy System Capital Cost (CAD)']
new_operational = new_system[f'{building_name}']['Energy System Average Yearly Operational Cost (CAD)']
new_lcc = new_system[f'{building_name}']['Energy System Life Cycle Cost (CAD)']
energy_system_table_data = [
["Detail", "Existing System", "Proposed System"],
["Energy System Archetype", current_system_archetype, new_system_archetype],
["Heating Equipments", current_system_heating, new_system_heating],
["Cooling Equipments", current_system_cooling, new_system_cooling],
["DHW Equipments", current_system_dhw, new_system_dhw],
["Photovoltaic System Capacity", current_system_pv, new_system_pv],
["Heating Fuel", current_system_heating_fuel, new_system_heating_fuel],
["Yearly HVAC Energy Consumption (MWh)", current_system_hvac_consumption, new_system_hvac_consumption],
["DHW Energy Consumption (MWH)", current_system_dhw_consumption, new_system_dhw_consumption],
["PV Yearly Production (kWh)", current_pv_production, new_pv_production],
["Energy System Capital Cost (CAD)", current_capital_cost, new_capital_cost],
["Energy System Average Yearly Operational Cost (CAD)", current_operational, new_operational],
["Energy System Life Cycle Cost (CAD)", current_lcc, new_lcc]
]
self.report.add_table(energy_system_table_data, caption=f'Building {building_name} Energy System Characteristics')
def building_fuel_consumption_breakdown(self, building):
save_directory = self.output_path
# Initialize variables to store fuel consumption breakdown
fuel_breakdown = {
"Heating": {"Gas": 0, "Electricity": 0},
"Domestic Hot Water": {"Gas": 0, "Electricity": 0},
"Cooling": {"Electricity": 0},
"Appliance": building.appliances_electrical_demand[cte.YEAR][0] / 1e6,
"Lighting": building.lighting_electrical_demand[cte.YEAR][0] / 1e6
}
# Iterate through energy systems of the building
for energy_system in building.energy_systems:
for demand_type in energy_system.demand_types:
if demand_type == cte.HEATING:
consumption = building.heating_consumption[cte.YEAR][0] / 3.6e9
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
fuel_breakdown[demand_type]["Electricity"] += consumption
else:
fuel_breakdown[demand_type]["Gas"] += consumption
elif demand_type == cte.DOMESTIC_HOT_WATER:
consumption = building.domestic_hot_water_consumption[cte.YEAR][0] / 1e6
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
fuel_breakdown[demand_type]["Electricity"] += consumption
else:
fuel_breakdown[demand_type]["Gas"] += consumption
elif demand_type == cte.COOLING:
consumption = building.cooling_consumption[cte.YEAR][0] / 3.6e9
fuel_breakdown[demand_type]["Electricity"] += consumption
electricity_labels = ['Appliance', 'Lighting']
electricity_sizes = [fuel_breakdown['Appliance'], fuel_breakdown['Lighting']]
if fuel_breakdown['Heating']['Electricity'] > 0:
electricity_labels.append('Heating')
electricity_sizes.append(fuel_breakdown['Heating']['Electricity'])
if fuel_breakdown['Cooling']['Electricity'] > 0:
electricity_labels.append('Cooling')
electricity_sizes.append(fuel_breakdown['Cooling']['Electricity'])
if fuel_breakdown['Domestic Hot Water']['Electricity'] > 0:
electricity_labels.append('Domestic Hot Water')
electricity_sizes.append(fuel_breakdown['Domestic Hot Water']['Electricity'])
# Data for bar chart
gas_labels = ['Heating', 'Domestic Hot Water']
gas_sizes = [fuel_breakdown['Heating']['Gas'], fuel_breakdown['Domestic Hot Water']['Gas']]
# Set the style
plt.style.use('ggplot')
# Create plot grid
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
# Plot pie chart for electricity consumption breakdown
colors = cm.get_cmap('tab20c', len(electricity_labels))
axs[0].pie(electricity_sizes, labels=electricity_labels,
autopct=lambda pct: f"{pct:.1f}%\n({pct / 100 * sum(electricity_sizes):.2f})",
startangle=90, colors=[colors(i) for i in range(len(electricity_labels))])
axs[0].set_title('Electricity Consumption Breakdown')
# Plot bar chart for natural gas consumption breakdown
colors = cm.get_cmap('Paired', len(gas_labels))
axs[1].bar(gas_labels, gas_sizes, color=[colors(i) for i in range(len(gas_labels))])
axs[1].set_ylabel('Consumption (MWh)')
axs[1].set_title('Natural Gas Consumption Breakdown')
# Add grid to bar chart
axs[1].grid(axis='y', linestyle='--', alpha=0.7)
# Add a title to the entire figure
plt.suptitle('Building Energy Consumption Breakdown', fontsize=16, fontweight='bold')
# Adjust layout
plt.tight_layout()
# Save the plot as a high-quality image
plt.savefig(save_directory / f'{building.name}_energy_consumption_breakdown.png', dpi=300)
plt.close()
def create_report(self, current_system, new_system):
os.chdir(self.output_path)
self.report.add_section('Current Status')
self.building_energy_info()
self.base_case_charts()
self.report.add_image('hvac_demand_chart.jpg', caption='Yearly HVAC Demands')
self.report.add_image('dhw_demand_chart.jpg', caption='Yearly DHW Demands')
self.report.add_image('electricity_demand_chart.jpg', caption='Yearly Electricity Demands')
self.maximum_monthly_hvac_chart()
self.load_duration_curves()
for building in self.city.buildings:
self.individual_building_info(building)
self.building_system_retrofit_results(building_name=building.name, current_system=current_system, new_system=new_system)
self.building_fuel_consumption_breakdown(building)
self.report.add_image(f'{building.name}_energy_consumption_breakdown.png',
caption=f'Building {building.name} Consumption by source and sector breakdown')
self.report.save_report()
self.report.compile_to_pdf()

View File

@ -0,0 +1,596 @@
import os
import hub.helpers.constants as cte
import matplotlib.pyplot as plt
from matplotlib import cm
from scripts.report_creation import LatexReport
from matplotlib.ticker import MaxNLocator
import numpy as np
from pathlib import Path
import glob
class EnergySystemRetrofitReport:
def __init__(self, city, output_path, retrofit_scenario, current_status_energy_consumption_data,
retrofitted_energy_consumption_data, current_status_lcc_data, retrofitted_lcc_data):
self.city = city
self.current_status_data = current_status_energy_consumption_data
self.retrofitted_data = retrofitted_energy_consumption_data
self.current_status_lcc = current_status_lcc_data
self.retrofitted_lcc = retrofitted_lcc_data
self.output_path = output_path
self.content = []
self.retrofit_scenario = retrofit_scenario
self.report = LatexReport('energy_system_retrofit_report',
'Energy System Retrofit Report', self.retrofit_scenario, output_path)
self.system_schemas_path = (Path(__file__).parent.parent / 'hub' / 'data' / 'energy_systems' / 'schemas')
self.charts_path = Path(output_path) / 'charts'
self.charts_path.mkdir(parents=True, exist_ok=True)
files = glob.glob(f'{self.charts_path}/*')
for file in files:
os.remove(file)
def building_energy_info(self):
table_data = [
["Building Name", "Year of Construction", "function", "Yearly Heating Demand (MWh)",
"Yearly Cooling Demand (MWh)", "Yearly DHW Demand (MWh)", "Yearly Electricity Demand (MWh)"]
]
intensity_table_data = [["Building Name", "Total Floor Area $m^2$", "Heating Demand Intensity kWh/ $m^2$",
"Cooling Demand Intensity kWh/ $m^2$", "Electricity Intensity kWh/ $m^2$"]]
peak_load_data = [["Building Name", "Heating Peak Load (kW)", "Cooling Peak Load (kW)",
"Domestic Hot Water Peak Load (kW)"]]
for building in self.city.buildings:
total_floor_area = 0
for zone in building.thermal_zones_from_internal_zones:
total_floor_area += zone.total_floor_area
building_data = [
building.name,
str(building.year_of_construction),
building.function,
str(format(building.heating_demand[cte.YEAR][0] / 3.6e9, '.2f')),
str(format(building.cooling_demand[cte.YEAR][0] / 3.6e9, '.2f')),
str(format(building.domestic_hot_water_heat_demand[cte.YEAR][0] / 3.6e9, '.2f')),
str(format(
(building.lighting_electrical_demand[cte.YEAR][0] + building.appliances_electrical_demand[cte.YEAR][0])
/ 3.6e9, '.2f')),
]
intensity_data = [
building.name,
str(format(total_floor_area, '.2f')),
str(format(building.heating_demand[cte.YEAR][0] / (3.6e6 * total_floor_area), '.2f')),
str(format(building.cooling_demand[cte.YEAR][0] / (3.6e6 * total_floor_area), '.2f')),
str(format(
(building.lighting_electrical_demand[cte.YEAR][0] + building.appliances_electrical_demand[cte.YEAR][0]) /
(3.6e6 * total_floor_area), '.2f'))
]
peak_data = [
building.name,
str(format(building.heating_peak_load[cte.YEAR][0] / 1000, '.2f')),
str(format(building.cooling_peak_load[cte.YEAR][0] / 1000, '.2f')),
str(format(
(building.lighting_electrical_demand[cte.YEAR][0] + building.appliances_electrical_demand[cte.YEAR][0]) /
(3.6e6 * total_floor_area), '.2f'))
]
table_data.append(building_data)
intensity_table_data.append(intensity_data)
peak_load_data.append(peak_data)
self.report.add_table(table_data, caption='Buildings Energy Consumption Data')
self.report.add_table(intensity_table_data, caption='Buildings Energy Use Intensity Data')
self.report.add_table(peak_load_data, caption='Buildings Peak Load Data')
def plot_monthly_energy_demands(self, data, file_name, title):
# Data preparation
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
demands = {
'Heating': ('heating', '#2196f3'),
'Cooling': ('cooling', '#ff5a5f'),
'DHW': ('dhw', '#4caf50'),
'Electricity': ('lighting_appliance', '#ffc107')
}
# Helper function for plotting
def plot_bar_chart(ax, demand_type, color, ylabel, title):
values = data[demand_type]
ax.bar(months, values, color=color, width=0.6, zorder=2)
ax.grid(which="major", axis='x', color='#DAD8D7', alpha=0.5, zorder=1)
ax.grid(which="major", axis='y', color='#DAD8D7', alpha=0.5, zorder=1)
ax.set_ylabel(ylabel, fontsize=14, labelpad=10)
ax.set_title(title, fontsize=14, weight='bold', alpha=.8, pad=40)
ax.xaxis.set_major_locator(MaxNLocator(integer=True))
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
ax.set_xticks(np.arange(len(months)))
ax.set_xticklabels(months, rotation=45, ha='right')
ax.bar_label(ax.containers[0], padding=3, color='black', fontsize=12, rotation=90)
ax.spines[['top', 'left', 'bottom']].set_visible(False)
ax.spines['right'].set_linewidth(1.1)
average_value = np.mean(values)
ax.axhline(y=average_value, color='grey', linewidth=2, linestyle='--')
ax.text(len(months) - 1, average_value, f'Average = {average_value:.1f} kWh', ha='right', va='bottom',
color='grey')
# Plotting
fig, axs = plt.subplots(4, 1, figsize=(20, 16), dpi=96)
fig.suptitle(title, fontsize=16, weight='bold', alpha=.8)
plot_bar_chart(axs[0], 'heating', demands['Heating'][1], 'Heating Demand (kWh)', 'Monthly Heating Demand')
plot_bar_chart(axs[1], 'cooling', demands['Cooling'][1], 'Cooling Demand (kWh)', 'Monthly Cooling Demand')
plot_bar_chart(axs[2], 'dhw', demands['DHW'][1], 'DHW Demand (kWh)', 'Monthly DHW Demand')
plot_bar_chart(axs[3], 'lighting_appliance', demands['Electricity'][1], 'Electricity Demand (kWh)',
'Monthly Electricity Demand')
# Set a white background
fig.patch.set_facecolor('white')
# Adjust the margins around the plot area
plt.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.1, hspace=0.5)
# Save the plot
chart_path = self.charts_path / f'{file_name}.png'
plt.savefig(chart_path, bbox_inches='tight')
plt.close()
return chart_path
def plot_monthly_energy_consumption(self, data, file_name, title):
# Data preparation
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
consumptions = {
'Heating': ('heating', '#2196f3', 'Heating Consumption (kWh)', 'Monthly Energy Consumption for Heating'),
'Cooling': ('cooling', '#ff5a5f', 'Cooling Consumption (kWh)', 'Monthly Energy Consumption for Cooling'),
'DHW': ('dhw', '#4caf50', 'DHW Consumption (kWh)', 'Monthly DHW Consumption')
}
# Helper function for plotting
def plot_bar_chart(ax, consumption_type, color, ylabel, title):
values = data[consumption_type]
ax.bar(months, values, color=color, width=0.6, zorder=2)
ax.grid(which="major", axis='x', color='#DAD8D7', alpha=0.5, zorder=1)
ax.grid(which="major", axis='y', color='#DAD8D7', alpha=0.5, zorder=1)
ax.set_xlabel('Month', fontsize=12, labelpad=10)
ax.set_ylabel(ylabel, fontsize=14, labelpad=10)
ax.set_title(title, fontsize=14, weight='bold', alpha=.8, pad=40)
ax.xaxis.set_major_locator(MaxNLocator(integer=True))
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
ax.set_xticks(np.arange(len(months)))
ax.set_xticklabels(months, rotation=45, ha='right')
ax.bar_label(ax.containers[0], padding=3, color='black', fontsize=12, rotation=90)
ax.spines[['top', 'left', 'bottom']].set_visible(False)
ax.spines['right'].set_linewidth(1.1)
average_value = np.mean(values)
ax.axhline(y=average_value, color='grey', linewidth=2, linestyle='--')
ax.text(len(months) - 1, average_value, f'Average = {average_value:.1f} kWh', ha='right', va='bottom',
color='grey')
# Plotting
fig, axs = plt.subplots(3, 1, figsize=(20, 15), dpi=96)
fig.suptitle(title, fontsize=16, weight='bold', alpha=.8)
plot_bar_chart(axs[0], 'heating', consumptions['Heating'][1], consumptions['Heating'][2],
consumptions['Heating'][3])
plot_bar_chart(axs[1], 'cooling', consumptions['Cooling'][1], consumptions['Cooling'][2],
consumptions['Cooling'][3])
plot_bar_chart(axs[2], 'dhw', consumptions['DHW'][1], consumptions['DHW'][2], consumptions['DHW'][3])
# Set a white background
fig.patch.set_facecolor('white')
# Adjust the margins around the plot area
plt.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.1, wspace=0.3, hspace=0.5)
# Save the plot
chart_path = self.charts_path / f'{file_name}.png'
plt.savefig(chart_path, bbox_inches='tight')
plt.close()
return chart_path
def fuel_consumption_breakdown(self, file_name, data):
fuel_consumption_breakdown = {}
for building in self.city.buildings:
for key, breakdown in data[f'{building.name}']['energy_consumption_breakdown'].items():
if key not in fuel_consumption_breakdown:
fuel_consumption_breakdown[key] = {sector: 0 for sector in breakdown}
for sector, value in breakdown.items():
if sector in fuel_consumption_breakdown[key]:
fuel_consumption_breakdown[key][sector] += value / 3.6e6
else:
fuel_consumption_breakdown[key][sector] = value / 3.6e6
plt.style.use('ggplot')
num_keys = len(fuel_consumption_breakdown)
fig, axs = plt.subplots(1 if num_keys <= 2 else num_keys, min(num_keys, 2), figsize=(12, 5))
axs = axs if num_keys > 1 else [axs] # Ensure axs is always iterable
for i, (fuel, breakdown) in enumerate(fuel_consumption_breakdown.items()):
labels = breakdown.keys()
values = breakdown.values()
colors = cm.get_cmap('tab20c', len(labels))
ax = axs[i] if num_keys > 1 else axs[0]
ax.pie(values, labels=labels,
autopct=lambda pct: f"{pct:.1f}%\n({pct / 100 * sum(values):.2f})",
startangle=90, colors=[colors(j) for j in range(len(labels))])
ax.set_title(f'{fuel} Consumption Breakdown')
plt.suptitle('City Energy Consumption Breakdown', fontsize=16, fontweight='bold')
plt.tight_layout(rect=[0, 0, 1, 0.95]) # Adjust layout to fit the suptitle
chart_path = self.charts_path / f'{file_name}.png'
plt.savefig(chart_path, dpi=300)
plt.close()
return chart_path
def energy_system_archetype_schematic(self):
energy_system_archetypes = {}
for building in self.city.buildings:
if building.energy_systems_archetype_name not in energy_system_archetypes:
energy_system_archetypes[building.energy_systems_archetype_name] = [building.name]
else:
energy_system_archetypes[building.energy_systems_archetype_name].append(building.name)
text = ""
items = ""
for archetype, buildings in energy_system_archetypes.items():
buildings_str = ", ".join(buildings)
text += f"Figure 4 shows the schematic of the proposed energy system for buildings {buildings_str}.\n"
if archetype in ['PV+4Pipe+DHW', 'PV+ASHP+GasBoiler+TES']:
text += "This energy system archetype is formed of the following systems: \par"
items = ['Rooftop Photovoltaic System: The rooftop PV system is tied to the grid and in case there is surplus '
'energy, it is sold to Hydro-Quebec through their Net-Meterin program.',
'4-Pipe HVAC System: This systems includes a 4-pipe heat pump capable of generating heat and cooling '
'at the same time, a natural gas boiler as the auxiliary heating system, and a hot water storage tank.'
'The temperature inside the tank is kept between 40-55 C. The cooling demand is totally supplied by '
'the heat pump unit.',
'Domestic Hot Water Heat Pump System: This system is in charge of supplying domestic hot water demand.'
'The heat pump is connected to a thermal storage tank with electric resistance heating coil inside it.'
' The temperature inside the tank should always remain above 60 C.']
self.report.add_text(text)
self.report.add_itemize(items=items)
schema_path = self.system_schemas_path / f'{archetype}.jpg'
self.report.add_image(str(schema_path).replace('\\', '/'),
f'Proposed energy system for buildings {buildings_str}')
def plot_monthly_radiation(self):
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
monthly_roof_radiation = []
for i in range(len(months)):
tilted_radiation = 0
for building in self.city.buildings:
tilted_radiation += (building.roofs[0].global_irradiance_tilted[cte.MONTH][i] /
(cte.WATTS_HOUR_TO_JULES * 1000))
monthly_roof_radiation.append(tilted_radiation)
def plot_bar_chart(ax, months, values, color, ylabel, title):
ax.bar(months, values, color=color, width=0.6, zorder=2)
ax.grid(which="major", axis='x', color='#DAD8D7', alpha=0.5, zorder=1)
ax.grid(which="major", axis='y', color='#DAD8D7', alpha=0.5, zorder=1)
ax.set_xlabel('Month', fontsize=12, labelpad=10)
ax.set_ylabel(ylabel, fontsize=14, labelpad=10)
ax.set_title(title, fontsize=14, weight='bold', alpha=.8, pad=40)
ax.xaxis.set_major_locator(MaxNLocator(integer=True))
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
ax.set_xticks(np.arange(len(months)))
ax.set_xticklabels(months, rotation=45, ha='right')
ax.bar_label(ax.containers[0], padding=3, color='black', fontsize=12, rotation=90)
ax.spines[['top', 'left', 'bottom']].set_visible(False)
ax.spines['right'].set_linewidth(1.1)
average_value = np.mean(values)
ax.axhline(y=average_value, color='grey', linewidth=2, linestyle='--')
ax.text(len(months) - 1, average_value, f'Average = {average_value:.1f} kWh', ha='right', va='bottom',
color='grey')
# Plotting the bar chart
fig, ax = plt.subplots(figsize=(15, 8), dpi=96)
plot_bar_chart(ax, months, monthly_roof_radiation, '#ffc107', 'Tilted Roof Radiation (kWh / m2)',
'Monthly Tilted Roof Radiation')
# Set a white background
fig.patch.set_facecolor('white')
# Adjust the margins around the plot area
plt.subplots_adjust(left=0.1, right=0.95, top=0.9, bottom=0.1)
# Save the plot
chart_path = self.charts_path / 'monthly_tilted_roof_radiation.png'
plt.savefig(chart_path, bbox_inches='tight')
plt.close()
return chart_path
def energy_consumption_comparison(self, current_status_data, retrofitted_data, file_name, title):
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
consumptions = {
'Heating': ('heating', '#2196f3', 'Heating Consumption (kWh)', 'Monthly Energy Consumption for Heating'),
'Cooling': ('cooling', '#ff5a5f', 'Cooling Consumption (kWh)', 'Monthly Energy Consumption for Cooling'),
'DHW': ('dhw', '#4caf50', 'DHW Consumption (kWh)', 'Monthly DHW Consumption')
}
# Helper function for plotting
def plot_double_bar_chart(ax, consumption_type, color, ylabel, title):
current_values = current_status_data[consumption_type]
retrofitted_values = retrofitted_data[consumption_type]
bar_width = 0.35
index = np.arange(len(months))
ax.bar(index, current_values, bar_width, label='Current Status', color=color, alpha=0.7, zorder=2)
ax.bar(index + bar_width, retrofitted_values, bar_width, label='Retrofitted', color=color, hatch='/', zorder=2)
ax.grid(which="major", axis='x', color='#DAD8D7', alpha=0.5, zorder=1)
ax.grid(which="major", axis='y', color='#DAD8D7', alpha=0.5, zorder=1)
ax.set_xlabel('Month', fontsize=12, labelpad=10)
ax.set_ylabel(ylabel, fontsize=14, labelpad=10)
ax.set_title(title, fontsize=14, weight='bold', alpha=.8, pad=40)
ax.set_xticks(index + bar_width / 2)
ax.set_xticklabels(months, rotation=45, ha='right')
ax.legend()
# Adding bar labels
ax.bar_label(ax.containers[0], padding=3, color='black', fontsize=12, rotation=90)
ax.bar_label(ax.containers[1], padding=3, color='black', fontsize=12, rotation=90)
ax.spines[['top', 'left', 'bottom']].set_visible(False)
ax.spines['right'].set_linewidth(1.1)
# Plotting
fig, axs = plt.subplots(3, 1, figsize=(20, 25), dpi=96)
fig.suptitle(title, fontsize=16, weight='bold', alpha=.8)
plot_double_bar_chart(axs[0], 'heating', consumptions['Heating'][1], consumptions['Heating'][2],
consumptions['Heating'][3])
plot_double_bar_chart(axs[1], 'cooling', consumptions['Cooling'][1], consumptions['Cooling'][2],
consumptions['Cooling'][3])
plot_double_bar_chart(axs[2], 'dhw', consumptions['DHW'][1], consumptions['DHW'][2], consumptions['DHW'][3])
# Set a white background
fig.patch.set_facecolor('white')
# Adjust the margins around the plot area
plt.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.1, wspace=0.3, hspace=0.5)
# Save the plot
chart_path = self.charts_path / f'{file_name}.png'
plt.savefig(chart_path, bbox_inches='tight')
plt.close()
return chart_path
def yearly_consumption_comparison(self):
current_total_consumption = round(self.current_status_data['total_consumption'], 2)
retrofitted_total_consumption = round(self.retrofitted_data['total_consumption'], 2)
text = (
f'The total yearly energy consumption before and after the retrofit are {current_total_consumption} MWh and '
f'{retrofitted_total_consumption} MWh, respectively.')
if retrofitted_total_consumption < current_total_consumption:
change = str(round((current_total_consumption - retrofitted_total_consumption) * 100 / current_total_consumption,
2))
text += f'Therefore, the total yearly energy consumption decreased by {change} \%.'
else:
change = str(round((retrofitted_total_consumption - current_total_consumption) * 100 /
retrofitted_total_consumption, 2))
text += f'Therefore, the total yearly energy consumption increased by {change} \%. \par'
self.report.add_text(text)
def pv_system(self):
self.report.add_text('The first step in PV assessments is evaluating the potential of buildings for installing '
'rooftop PV system. The benchmark value used for this evaluation is the mean yearly solar '
'incident in Montreal. According to Hydro-Quebec, the mean annual incident in Montreal is 1350'
'kWh/m2. Therefore, any building with rooftop annual global horizontal radiation of less than '
'1080 kWh/m2 is considered to be infeasible. Table 4 shows the yearly horizontal radiation on '
'buildings roofs. \par')
radiation_data = [
["Building Name", "Roof Area $m^2$", "Function", "Rooftop Annual Global Horizontal Radiation kWh/ $m^2$"]
]
pv_feasible_buildings = []
for building in self.city.buildings:
if building.roofs[0].global_irradiance[cte.YEAR][0] > 1080:
pv_feasible_buildings.append(building.name)
data = [building.name, str(format(building.roofs[0].perimeter_area, '.2f')), building.function,
str(format(building.roofs[0].global_irradiance[cte.YEAR][0] / (cte.WATTS_HOUR_TO_JULES * 1000), '.2f'))]
radiation_data.append(data)
self.report.add_table(radiation_data,
caption='Buildings Roof Characteristics')
if len(pv_feasible_buildings) == len(self.city.buildings):
buildings_str = 'all'
else:
buildings_str = ", ".join(pv_feasible_buildings)
self.report.add_text(f"From the table it can be seen that {buildings_str} buildings are good candidates to have "
f"rooftop PV system. The next step is calculating the amount of solar radiation on a tilted "
f"surface. Figure 5 shows the total monthly solar radiation on a surface with the tilt angle "
f"of 45 degrees on the roofs of those buildings that are identified to have rooftop PV system."
f"\par")
tilted_radiation = self.plot_monthly_radiation()
self.report.add_image(str(tilted_radiation).replace('\\', '/'),
caption='Total Monthly Solar Radiation on Buildings Roofs on a 45 Degrees Tilted Surface',
placement='H')
self.report.add_text('The first step in sizing the PV system is to find the available roof area. '
'Few considerations need to be made here. The considerations include space for maintenance '
'crew, space for mechanical equipment, and orientation correction factor to make sure all '
'the panel are truly facing south. After all these considerations, the minimum distance '
'between the panels to avoid shading throughout the year is found. Table 5 shows the number of'
'panles on each buildings roof, yearly PV production, total electricity consumption, and self '
'consumption. \par')
pv_output_table = [['Building Name', 'Total Surface Area of PV Panels ($m^2$)',
'Total Solar Incident on PV Modules (MWh)', 'Yearly PV production (MWh)']]
for building in self.city.buildings:
if building.name in pv_feasible_buildings:
pv_data = []
pv_data.append(building.name)
yearly_solar_incident = (building.roofs[0].global_irradiance_tilted[cte.YEAR][0] *
building.roofs[0].installed_solar_collector_area) / (cte.WATTS_HOUR_TO_JULES * 1e6)
yearly_solar_incident_str = format(yearly_solar_incident, '.2f')
yearly_pv_output = building.onsite_electrical_production[cte.YEAR][0] / (cte.WATTS_HOUR_TO_JULES * 1e6)
yearly_pv_output_str = format(yearly_pv_output, '.2f')
pv_data.append(format(building.roofs[0].installed_solar_collector_area, '.2f'))
pv_data.append(yearly_solar_incident_str)
pv_data.append(yearly_pv_output_str)
pv_output_table.append(pv_data)
self.report.add_table(pv_output_table, caption='PV System Simulation Results', first_column_width=3)
def life_cycle_cost_stacked_bar(self, file_name, title):
# Aggregate LCC components for current and retrofitted statuses
current_status_capex = 0
current_status_opex = 0
current_status_maintenance = 0
current_status_end_of_life = 0
retrofitted_capex = 0
retrofitted_opex = 0
retrofitted_maintenance = 0
retrofitted_end_of_life = 0
current_status_operational_income = 0
retrofitted_operational_income = 0
for building in self.city.buildings:
current_status_capex += self.current_status_lcc[f'{building.name}']['capital_cost_per_sqm']
retrofitted_capex += self.retrofitted_lcc[f'{building.name}']['capital_cost_per_sqm']
current_status_opex += self.current_status_lcc[f'{building.name}']['operational_cost_per_sqm']
retrofitted_opex += self.retrofitted_lcc[f'{building.name}']['operational_cost_per_sqm']
current_status_maintenance += self.current_status_lcc[f'{building.name}']['maintenance_cost_per_sqm']
retrofitted_maintenance += self.retrofitted_lcc[f'{building.name}']['maintenance_cost_per_sqm']
current_status_end_of_life += self.current_status_lcc[f'{building.name}']['end_of_life_cost_per_sqm']
retrofitted_end_of_life += self.retrofitted_lcc[f'{building.name}']['end_of_life_cost_per_sqm']
current_status_operational_income += self.current_status_lcc[f'{building.name}']['operational_income_per_sqm']
retrofitted_operational_income += self.retrofitted_lcc[f'{building.name}']['operational_income_per_sqm']
current_status_lcc_components_sqm = {
'Capital Cost': current_status_capex / len(self.city.buildings),
'Operational Cost': (current_status_opex - current_status_operational_income) / len(self.city.buildings),
'Maintenance Cost': current_status_maintenance / len(self.city.buildings),
'End of Life Cost': current_status_end_of_life / len(self.city.buildings),
}
retrofitted_lcc_components_sqm = {
'Capital Cost': retrofitted_capex / len(self.city.buildings),
'Operational Cost': (retrofitted_opex - retrofitted_operational_income) / len(self.city.buildings),
'Maintenance Cost': retrofitted_maintenance / len(self.city.buildings),
'End of Life Cost': retrofitted_end_of_life / len(self.city.buildings),
}
labels = ['Current Status', 'Retrofitted Status']
categories = ['Capital Cost', 'Operational Cost', 'Maintenance Cost', 'End of Life Cost']
colors = ['#2196f3', '#ff5a5f', '#4caf50', '#ffc107'] # Added new color
# Data preparation
bar_width = 0.35
r = np.arange(len(labels))
fig, ax = plt.subplots(figsize=(12, 8), dpi=96)
fig.suptitle(title, fontsize=16, weight='bold', alpha=.8)
# Plotting current status data
bottom = np.zeros(len(labels))
for category, color in zip(categories, colors):
values = [current_status_lcc_components_sqm[category], retrofitted_lcc_components_sqm[category]]
ax.bar(r, values, bottom=bottom, color=color, edgecolor='white', width=bar_width, label=category)
bottom += values
# Adding summation annotations at the top of the bars
for idx, (x, total) in enumerate(zip(r, bottom)):
ax.text(x, total, f'{total:.1f}', ha='center', va='bottom', fontsize=12, fontweight='bold')
# Adding labels, title, and grid
ax.set_xlabel('LCC Components', fontsize=12, labelpad=10)
ax.set_ylabel('Average Cost (CAD/m²)', fontsize=14, labelpad=10)
ax.grid(which="major", axis='y', color='#DAD8D7', alpha=0.5, zorder=1)
ax.set_xticks(r)
ax.set_xticklabels(labels, rotation=45, ha='right')
ax.legend()
# Adding a white background
fig.patch.set_facecolor('white')
# Adjusting the margins around the plot area
plt.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.2)
# Save the plot
chart_path = self.charts_path / f'{file_name}.png'
plt.savefig(chart_path, bbox_inches='tight')
plt.close()
return chart_path
def create_report(self):
# Add sections and text to the report
self.report.add_section('Overview of the Current Status in Buildings')
self.report.add_text('In this section, an overview of the current status of buildings characteristics, '
'energy demand and consumptions are provided')
self.report.add_subsection('Buildings Characteristics')
self.building_energy_info()
# current monthly demands and consumptions
current_monthly_demands = self.current_status_data['monthly_demands']
current_monthly_consumptions = self.current_status_data['monthly_consumptions']
# Plot and save demand chart
current_demand_chart_path = self.plot_monthly_energy_demands(data=current_monthly_demands,
file_name='current_monthly_demands',
title='Current Status Monthly Energy Demands')
# Plot and save consumption chart
current_consumption_chart_path = self.plot_monthly_energy_consumption(data=current_monthly_consumptions,
file_name='monthly_consumptions',
title='Monthly Energy Consumptions')
current_consumption_breakdown_path = self.fuel_consumption_breakdown('City_Energy_Consumption_Breakdown',
self.current_status_data)
retrofitted_consumption_breakdown_path = self.fuel_consumption_breakdown(
'fuel_consumption_breakdown_after_retrofit',
self.retrofitted_data)
life_cycle_cost_sqm_stacked_bar_chart_path = self.life_cycle_cost_stacked_bar('lcc_per_sqm',
'LCC Analysis')
# Add current state of energy demands in the city
self.report.add_subsection('Current State of Energy Demands in the City')
self.report.add_text('The total monthly energy demands in the city are shown in Figure 1. It should be noted '
'that the electricity demand refers to total lighting and appliance electricity demands')
self.report.add_image(str(current_demand_chart_path).replace('\\', '/'),
'Total Monthly Energy Demands in City',
placement='h')
# Add current state of energy consumption in the city
self.report.add_subsection('Current State of Energy Consumption in the City')
self.report.add_text('The following figure shows the amount of energy consumed to supply heating, cooling, and '
'domestic hot water needs in the city. The details of the systems in each building before '
'and after retrofit are provided in Section 4. \par')
self.report.add_image(str(current_consumption_chart_path).replace('\\', '/'),
'Total Monthly Energy Consumptions in City',
placement='H')
self.report.add_text('Figure 3 shows the yearly energy supplied to the city by fuel in different sectors. '
'All the values are in kWh.')
self.report.add_image(str(current_consumption_breakdown_path).replace('\\', '/'),
'Current Energy Consumption Breakdown in the City by Fuel',
placement='H')
self.report.add_section(f'{self.retrofit_scenario}')
self.report.add_subsection('Proposed Systems')
self.energy_system_archetype_schematic()
if 'PV' in self.retrofit_scenario:
self.report.add_subsection('Rooftop Photovoltaic System Implementation')
self.pv_system()
if 'System' in self.retrofit_scenario:
self.report.add_subsection('Retrofitted HVAC and DHW Systems')
self.report.add_text('Figure 6 shows a comparison between total monthly energy consumption in the selected '
'buildings before and after retrofitting.')
consumption_comparison = self.energy_consumption_comparison(self.current_status_data['monthly_consumptions'],
self.retrofitted_data['monthly_consumptions'],
'energy_consumption_comparison_in_city',
'Total Monthly Energy Consumption Comparison in '
'Buildings')
self.report.add_image(str(consumption_comparison).replace('\\', '/'),
caption='Comparison of Total Monthly Energy Consumption in City Buildings',
placement='H')
self.yearly_consumption_comparison()
self.report.add_text('Figure 7 shows the fuel consumption breakdown in the area after the retrofit.')
self.report.add_image(str(retrofitted_consumption_breakdown_path).replace('\\', '/'),
caption=f'Fuel Consumption Breakdown After {self.retrofit_scenario}',
placement='H')
self.report.add_subsection('Life Cycle Cost Analysis')
self.report.add_image(str(life_cycle_cost_sqm_stacked_bar_chart_path).replace('\\', '/'),
caption='Average Life Cycle Cost Components',
placement='H')
# Save and compile the report
self.report.save_report()
self.report.compile_to_pdf()

View File

@ -1,68 +1,176 @@
import hub.helpers.constants as cte
def system_results(buildings):
system_performance_summary = {}
fields = ["Energy System Archetype", "Heating Equipments", "Cooling Equipments", "DHW Equipments",
"Photovoltaic System Capacity", "Heating Fuel", "Yearly HVAC Energy Consumption (MWh)",
"DHW Energy Consumption (MWH)", "PV Yearly Production (kWh)", "LCC Analysis Duration (Years)",
"Energy System Capital Cost (CAD)", "Energy System Average Yearly Operational Cost (CAD)",
"Energy System Life Cycle Cost (CAD)"]
for building in buildings:
system_performance_summary[f'{building.name}'] = {}
for field in fields:
system_performance_summary[f'{building.name}'][field] = '-'
for building in buildings:
fuels = []
system_performance_summary[f'{building.name}']['Energy System Archetype'] = building.energy_systems_archetype_name
energy_systems = building.energy_systems
def hourly_electricity_consumption_profile(building):
hourly_electricity_consumption = []
energy_systems = building.energy_systems
appliance = building.appliances_electrical_demand[cte.HOUR]
lighting = building.lighting_electrical_demand[cte.HOUR]
elec_heating = 0
elec_cooling = 0
elec_dhw = 0
if cte.HEATING in building.energy_consumption_breakdown[cte.ELECTRICITY]:
elec_heating = 1
if cte.COOLING in building.energy_consumption_breakdown[cte.ELECTRICITY]:
elec_cooling = 1
if cte.DOMESTIC_HOT_WATER in building.energy_consumption_breakdown[cte.ELECTRICITY]:
elec_dhw = 1
heating = None
cooling = None
dhw = None
if elec_heating == 1:
for energy_system in energy_systems:
demand_types = energy_system.demand_types
for demand_type in demand_types:
if demand_type == cte.COOLING:
equipments = []
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
equipments.append(generation_system.name or generation_system.system_type)
cooling_equipments = ", ".join(equipments)
system_performance_summary[f'{building.name}']['Cooling Equipments'] = cooling_equipments
elif demand_type == cte.HEATING:
equipments = []
for generation_system in energy_system.generation_systems:
if generation_system.nominal_heat_output is not None:
equipments.append(generation_system.name or generation_system.system_type)
fuels.append(generation_system.fuel_type)
heating_equipments = ", ".join(equipments)
system_performance_summary[f'{building.name}']['Heating Equipments'] = heating_equipments
elif demand_type == cte.DOMESTIC_HOT_WATER:
equipments = []
for generation_system in energy_system.generation_systems:
equipments.append(generation_system.name or generation_system.system_type)
dhw_equipments = ", ".join(equipments)
system_performance_summary[f'{building.name}']['DHW Equipments'] = dhw_equipments
for generation_system in energy_system.generation_systems:
if generation_system.system_type == cte.PHOTOVOLTAIC:
system_performance_summary[f'{building.name}'][
'Photovoltaic System Capacity'] = generation_system.nominal_electricity_output or str(0)
heating_fuels = ", ".join(fuels)
system_performance_summary[f'{building.name}']['Heating Fuel'] = heating_fuels
system_performance_summary[f'{building.name}']['Yearly HVAC Energy Consumption (MWh)'] = format(
(building.heating_consumption[cte.YEAR][0] + building.cooling_consumption[cte.YEAR][0]) / 3.6e9, '.2f')
system_performance_summary[f'{building.name}']['DHW Energy Consumption (MWH)'] = format(
building.domestic_hot_water_consumption[cte.YEAR][0] / 1e6, '.2f')
return system_performance_summary
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
if cte.HEATING in generation_system.energy_consumption:
heating = generation_system.energy_consumption[cte.HEATING][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
heating = [x / 2 for x in building.heating_consumption[cte.HOUR]]
else:
heating = building.heating_consumption[cte.HOUR]
if elec_dhw == 1:
for energy_system in energy_systems:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if generation_system.fuel_type == cte.ELECTRICITY:
if cte.DOMESTIC_HOT_WATER in generation_system.energy_consumption:
dhw = generation_system.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
dhw = [x / 2 for x in building.domestic_hot_water_consumption[cte.HOUR]]
else:
dhw = building.domestic_hot_water_consumption[cte.HOUR]
if elec_cooling == 1:
for energy_system in energy_systems:
if cte.COOLING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
if cte.COOLING in generation_system.energy_consumption:
cooling = generation_system.energy_consumption[cte.COOLING][cte.HOUR]
else:
if len(energy_system.generation_systems) > 1:
cooling = [x / 2 for x in building.cooling_consumption[cte.HOUR]]
else:
cooling = building.cooling_consumption[cte.HOUR]
for i in range(len(building.heating_demand[cte.HOUR])):
hourly = 0
hourly += appliance[i] / 3600
hourly += lighting[i] / 3600
if heating is not None:
hourly += heating[i] / 3600
if cooling is not None:
hourly += cooling[i] / 3600
if dhw is not None:
hourly += dhw[i] / 3600
hourly_electricity_consumption.append(hourly)
return hourly_electricity_consumption
def new_system_results(buildings):
new_system_performance_summary = {}
fields = ["Energy System Archetype", "Heating Equipments", "Cooling Equipments", "DHW Equipments",
"Photovoltaic System Capacity", "Heating Fuel", "Yearly HVAC Energy Consumption (MWh)",
"DHW Energy Consumption (MWH)", "PV Yearly Production (kWh)", "LCC Analysis Duration (Years)",
"Energy System Capital Cost (CAD)", "Energy System Average Yearly Operational Cost (CAD)",
"Energy System Life Cycle Cost (CAD)"]
for building in buildings:
new_system_performance_summary[f'{building.name}'] = {}
for field in fields:
new_system_performance_summary[f'{building.name}'][field] = '-'
return new_system_performance_summary
def consumption_data(city):
energy_consumption_data = {}
for building in city.buildings:
hourly_electricity_consumption = hourly_electricity_consumption_profile(building)
energy_consumption_data[f'{building.name}'] = {'heating_consumption': building.heating_consumption,
'cooling_consumption': building.cooling_consumption,
'domestic_hot_water_consumption':
building.domestic_hot_water_consumption,
'energy_consumption_breakdown':
building.energy_consumption_breakdown,
'hourly_electricity_consumption': hourly_electricity_consumption}
peak_electricity_consumption = 0
for building in energy_consumption_data:
peak_electricity_consumption += max(energy_consumption_data[building]['hourly_electricity_consumption'])
heating_demand_monthly = []
cooling_demand_monthly = []
dhw_demand_monthly = []
lighting_appliance_monthly = []
heating_consumption_monthly = []
cooling_consumption_monthly = []
dhw_consumption_monthly = []
for i in range(12):
heating_demand = 0
cooling_demand = 0
dhw_demand = 0
lighting_appliance_demand = 0
heating_consumption = 0
cooling_consumption = 0
dhw_consumption = 0
for building in city.buildings:
heating_demand += building.heating_demand[cte.MONTH][i] / 3.6e6
cooling_demand += building.cooling_demand[cte.MONTH][i] / 3.6e6
dhw_demand += building.domestic_hot_water_heat_demand[cte.MONTH][i] / 3.6e6
lighting_appliance_demand += building.lighting_electrical_demand[cte.MONTH][i] / 3.6e6
heating_consumption += building.heating_consumption[cte.MONTH][i] / 3.6e6
if building.cooling_consumption[cte.YEAR][0] == 0:
cooling_consumption += building.cooling_demand[cte.MONTH][i] / (3.6e6 * 2)
else:
cooling_consumption += building.cooling_consumption[cte.MONTH][i] / 3.6e6
dhw_consumption += building.domestic_hot_water_consumption[cte.MONTH][i] / 3.6e6
heating_demand_monthly.append(heating_demand)
cooling_demand_monthly.append(cooling_demand)
dhw_demand_monthly.append(dhw_demand)
lighting_appliance_monthly.append(lighting_appliance_demand)
heating_consumption_monthly.append(heating_consumption)
cooling_consumption_monthly.append(cooling_consumption)
dhw_consumption_monthly.append(dhw_consumption)
monthly_demands = {'heating': heating_demand_monthly,
'cooling': cooling_demand_monthly,
'dhw': dhw_demand_monthly,
'lighting_appliance': lighting_appliance_monthly}
monthly_consumptions = {'heating': heating_consumption_monthly,
'cooling': cooling_consumption_monthly,
'dhw': dhw_consumption_monthly}
yearly_heating = 0
yearly_cooling = 0
yearly_dhw = 0
yearly_appliance = 0
yearly_lighting = 0
for building in city.buildings:
yearly_appliance += building.appliances_electrical_demand[cte.YEAR][0] / 3.6e9
yearly_lighting += building.lighting_electrical_demand[cte.YEAR][0] / 3.6e9
yearly_heating += building.heating_consumption[cte.YEAR][0] / 3.6e9
yearly_cooling += building.cooling_consumption[cte.YEAR][0] / 3.6e9
yearly_dhw += building.domestic_hot_water_consumption[cte.YEAR][0] / 3.6e9
total_consumption = yearly_heating + yearly_cooling + yearly_dhw + yearly_appliance + yearly_lighting
energy_consumption_data['monthly_demands'] = monthly_demands
energy_consumption_data['monthly_consumptions'] = monthly_consumptions
energy_consumption_data['total_consumption'] = total_consumption
energy_consumption_data['maximum_hourly_electricity_consumption'] = peak_electricity_consumption
return energy_consumption_data
def cost_data(building, lcc_dataframe, cost_retrofit_scenario):
total_floor_area = 0
for thermal_zone in building.thermal_zones_from_internal_zones:
total_floor_area += thermal_zone.total_floor_area
capital_cost = lcc_dataframe.loc['total_capital_costs_systems', f'Scenario {cost_retrofit_scenario}']
operational_cost = lcc_dataframe.loc['total_operational_costs', f'Scenario {cost_retrofit_scenario}']
maintenance_cost = lcc_dataframe.loc['total_maintenance_costs', f'Scenario {cost_retrofit_scenario}']
end_of_life_cost = lcc_dataframe.loc['end_of_life_costs', f'Scenario {cost_retrofit_scenario}']
operational_income = lcc_dataframe.loc['operational_incomes', f'Scenario {cost_retrofit_scenario}']
total_life_cycle_cost = capital_cost + operational_cost + maintenance_cost + end_of_life_cost + operational_income
specific_capital_cost = capital_cost / total_floor_area
specific_operational_cost = operational_cost / total_floor_area
specific_maintenance_cost = maintenance_cost / total_floor_area
specific_end_of_life_cost = end_of_life_cost / total_floor_area
specific_operational_income = operational_income / total_floor_area
specific_life_cycle_cost = total_life_cycle_cost / total_floor_area
life_cycle_cost_analysis = {'capital_cost': capital_cost,
'capital_cost_per_sqm': specific_capital_cost,
'operational_cost': operational_cost,
'operational_cost_per_sqm': specific_operational_cost,
'maintenance_cost': maintenance_cost,
'maintenance_cost_per_sqm': specific_maintenance_cost,
'end_of_life_cost': end_of_life_cost,
'end_of_life_cost_per_sqm': specific_end_of_life_cost,
'operational_income': operational_income,
'operational_income_per_sqm': specific_operational_income,
'total_life_cycle_cost': total_life_cycle_cost,
'total_life_cycle_cost_per_sqm': specific_life_cycle_cost}
return life_cycle_cost_analysis

View File

@ -52,17 +52,17 @@ class SystemSizing:
if cte.HEATING in demand_types:
if len(generation_systems) == 1:
for generation in generation_systems:
generation.nominal_heat_output = building.heating_peak_load[cte.YEAR][0] / 3600
generation.nominal_heat_output = building.heating_peak_load[cte.YEAR][0]
else:
for generation in generation_systems:
generation.nominal_heat_output = building.heating_peak_load[cte.YEAR][0] / (len(generation_systems) * 3600)
generation.nominal_heat_output = building.heating_peak_load[cte.YEAR][0] / (len(generation_systems))
elif cte.COOLING in demand_types:
if len(generation_systems) == 1:
for generation in generation_systems:
generation.nominal_cooling_output = building.cooling_peak_load[cte.YEAR][0] / 3600
generation.nominal_cooling_output = building.cooling_peak_load[cte.YEAR][0]
else:
for generation in generation_systems:
generation.nominal_heat_output = building.cooling_peak_load[cte.YEAR][0] / (len(generation_systems) * 3600)
generation.nominal_heat_output = building.cooling_peak_load[cte.YEAR][0] / (len(generation_systems))

View File

@ -6,7 +6,9 @@ Project Coder Saeed Ranjbar saeed.ranjbar@mail.concordia.ca
"""
from scripts.system_simulation_models.archetype13 import Archetype13
from scripts.system_simulation_models.archetype13_stratified_tes import Archetype13Stratified
from scripts.system_simulation_models.archetype1 import Archetype1
from scripts.system_simulation_models.archetypes14_15 import Archetype14_15
class EnergySystemsSimulationFactory:
@ -35,6 +37,15 @@ class EnergySystemsSimulationFactory:
self._building.level_of_detail.energy_systems = 2
self._building.level_of_detail.energy_systems = 2
def _archetype14_15(self):
"""
Enrich the city by using the sizing and simulation model developed for archetype14 and archetype15 of
montreal_future_systems
"""
Archetype14_15(self._building, self._output_path).enrich_buildings()
self._building.level_of_detail.energy_systems = 2
self._building.level_of_detail.energy_systems = 2
def enrich(self):
"""
Enrich the city given to the class using the class given handler

View File

@ -9,10 +9,10 @@ from hub.imports.results_factory import ResultFactory
sys.path.append('./')
def energy_plus_workflow(city):
def energy_plus_workflow(city, output_path):
try:
# city = city
out_path = (Path(__file__).parent.parent / 'out_files')
out_path = output_path
files = glob.glob(f'{out_path}/*')
# for file in files:

View File

@ -4,13 +4,16 @@ from shapely import Point
from pathlib import Path
def process_geojson(x, y, diff):
def process_geojson(x, y, diff, expansion=False):
selection_box = Polygon([[x + diff, y - diff],
[x - diff, y - diff],
[x - diff, y + diff],
[x + diff, y + diff]])
geojson_file = Path('./data/collinear_clean 2.geojson').resolve()
output_file = Path('./input_files/output_buildings.geojson').resolve()
if not expansion:
output_file = Path('./input_files/output_buildings.geojson').resolve()
else:
output_file = Path('./input_files/output_buildings_expanded.geojson').resolve()
buildings_in_region = []
with open(geojson_file, 'r') as file:

37
scripts/pv_feasibility.py Normal file
View File

@ -0,0 +1,37 @@
from pathlib import Path
import subprocess
from hub.imports.geometry_factory import GeometryFactory
from scripts.geojson_creator import process_geojson
from hub.helpers.dictionaries import Dictionaries
from hub.imports.weather_factory import WeatherFactory
from hub.imports.results_factory import ResultFactory
from hub.exports.exports_factory import ExportsFactory
def pv_feasibility(current_x, current_y, current_diff, selected_buildings):
input_files_path = (Path(__file__).parent.parent / 'input_files')
output_path = (Path(__file__).parent.parent / 'out_files').resolve()
sra_output_path = output_path / 'sra_outputs' / 'extended_city_sra_outputs'
sra_output_path.mkdir(parents=True, exist_ok=True)
new_diff = current_diff * 5
geojson_file = process_geojson(x=current_x, y=current_y, diff=new_diff, expansion=True)
file_path = input_files_path / 'output_buildings.geojson'
city = GeometryFactory('geojson',
path=file_path,
height_field='height',
year_of_construction_field='year_of_construction',
function_field='function',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
WeatherFactory('epw', city).enrich()
ExportsFactory('sra', city, sra_output_path).export()
sra_path = (sra_output_path / f'{city.name}_sra.xml').resolve()
subprocess.run(['sra', str(sra_path)])
ResultFactory('sra', city, sra_output_path).enrich()
for selected_building in selected_buildings:
for building in city.buildings:
if selected_building.name == building.name:
selected_building.roofs[0].global_irradiance = building.roofs[0].global_irradiance

View File

@ -0,0 +1,59 @@
import math
from scripts.radiation_tilted import RadiationTilted
import hub.helpers.constants as cte
from hub.helpers.monthly_values import MonthlyValues
class PVSizingSimulation(RadiationTilted):
def __init__(self, building, solar_angles, tilt_angle, module_height, module_width, ghi):
super().__init__(building, solar_angles, tilt_angle, ghi)
self.module_height = module_height
self.module_width = module_width
self.total_number_of_panels = 0
self.enrich()
def available_space(self):
roof_area = self.building.roofs[0].perimeter_area
maintenance_factor = 0.1
orientation_factor = 0.2
if self.building.function == cte.RESIDENTIAL:
mechanical_equipment_factor = 0.2
else:
mechanical_equipment_factor = 0.3
available_roof = (maintenance_factor + orientation_factor + mechanical_equipment_factor) * roof_area
return available_roof
def inter_row_spacing(self):
winter_solstice = self.df[(self.df['AST'].dt.month == 12) &
(self.df['AST'].dt.day == 21) &
(self.df['AST'].dt.hour == 12)]
solar_altitude = winter_solstice['solar altitude'].values[0]
solar_azimuth = winter_solstice['solar azimuth'].values[0]
distance = ((self.module_height * abs(math.cos(math.radians(solar_azimuth)))) /
math.tan(math.radians(solar_altitude)))
distance = float(format(distance, '.1f'))
return distance
def number_of_panels(self, available_roof, inter_row_distance):
space_dimension = math.sqrt(available_roof)
space_dimension = float(format(space_dimension, '.2f'))
panels_per_row = math.ceil(space_dimension / self.module_width)
number_of_rows = math.ceil(space_dimension / inter_row_distance)
self.total_number_of_panels = panels_per_row * number_of_rows
return panels_per_row, number_of_rows
def pv_output(self):
radiation = self.total_radiation_tilted
pv_module_area = self.module_width * self.module_height
available_roof = self.available_space()
inter_row_spacing = self.inter_row_spacing()
self.number_of_panels(available_roof, inter_row_spacing)
self.building.roofs[0].installed_solar_collector_area = pv_module_area * self.total_number_of_panels
system_efficiency = 0.2
pv_hourly_production = [x * system_efficiency * self.total_number_of_panels * pv_module_area *
cte.WATTS_HOUR_TO_JULES for x in radiation]
self.building.onsite_electrical_production[cte.HOUR] = pv_hourly_production
self.building.onsite_electrical_production[cte.MONTH] = (
MonthlyValues.get_total_month(self.building.onsite_electrical_production[cte.HOUR]))
self.building.onsite_electrical_production[cte.YEAR] = [sum(self.building.onsite_electrical_production[cte.MONTH])]

113
scripts/radiation_tilted.py Normal file
View File

@ -0,0 +1,113 @@
import pandas as pd
import math
import hub.helpers.constants as cte
from hub.helpers.monthly_values import MonthlyValues
class RadiationTilted:
def __init__(self, building, solar_angles, tilt_angle, ghi, solar_constant=1366.1, maximum_clearness_index=1,
min_cos_zenith=0.065, maximum_zenith_angle=87):
self.building = building
self.ghi = ghi
self.tilt_angle = tilt_angle
self.zeniths = solar_angles['zenith'].tolist()[:-1]
self.incidents = solar_angles['incident angle'].tolist()[:-1]
self.date_time = solar_angles['DateTime'].tolist()[:-1]
self.ast = solar_angles['AST'].tolist()[:-1]
self.solar_azimuth = solar_angles['solar azimuth'].tolist()[:-1]
self.solar_altitude = solar_angles['solar altitude'].tolist()[:-1]
data = {'DateTime': self.date_time, 'AST': self.ast, 'solar altitude': self.solar_altitude, 'zenith': self.zeniths,
'solar azimuth': self.solar_azimuth, 'incident angle': self.incidents, 'ghi': self.ghi}
self.df = pd.DataFrame(data)
self.df['DateTime'] = pd.to_datetime(self.df['DateTime'])
self.df['AST'] = pd.to_datetime(self.df['AST'])
self.df.set_index('DateTime', inplace=True)
self.solar_constant = solar_constant
self.maximum_clearness_index = maximum_clearness_index
self.min_cos_zenith = min_cos_zenith
self.maximum_zenith_angle = maximum_zenith_angle
self.i_on = []
self.i_oh = []
self.k_t = []
self.fraction_diffuse = []
self.diffuse_horizontal = []
self.beam_horizontal = []
self.dni = []
self.beam_tilted = []
self.diffuse_tilted = []
self.total_radiation_tilted = []
self.calculate()
def dni_extra(self):
for i in range(len(self.df)):
self.i_on.append(self.solar_constant * (1 + 0.033 * math.cos(math.radians(360 * self.df.index.dayofyear[i] / 365))))
self.df['extraterrestrial normal radiation (Wh/m2)'] = self.i_on
def clearness_index(self):
for i in range(len(self.df)):
self.i_oh.append(self.i_on[i] * max(math.cos(math.radians(self.zeniths[i])), self.min_cos_zenith))
self.k_t.append(self.ghi[i] / self.i_oh[i])
self.k_t[i] = max(0, self.k_t[i])
self.k_t[i] = min(self.maximum_clearness_index, self.k_t[i])
self.df['extraterrestrial radiation on horizontal (Wh/m2)'] = self.i_oh
self.df['clearness index'] = self.k_t
def diffuse_fraction(self):
for i in range(len(self.df)):
if self.k_t[i] <= 0.22:
self.fraction_diffuse.append(1 - 0.09 * self.k_t[i])
elif self.k_t[i] <= 0.8:
self.fraction_diffuse.append(0.9511 - 0.1604 * self.k_t[i] + 4.388 * self.k_t[i] ** 2 -
16.638 * self.k_t[i] ** 3 + 12.336 * self.k_t[i] ** 4)
else:
self.fraction_diffuse.append(0.165)
if self.zeniths[i] > self.maximum_zenith_angle:
self.fraction_diffuse[i] = 1
self.df['diffuse fraction'] = self.fraction_diffuse
def radiation_components_horizontal(self):
for i in range(len(self.df)):
self.diffuse_horizontal.append(self.ghi[i] * self.fraction_diffuse[i])
self.beam_horizontal.append(self.ghi[i] - self.diffuse_horizontal[i])
self.dni.append((self.ghi[i] - self.diffuse_horizontal[i]) / math.cos(math.radians(self.zeniths[i])))
if self.zeniths[i] > self.maximum_zenith_angle or self.dni[i] < 0:
self.dni[i] = 0
self.df['diffuse horizontal (Wh/m2)'] = self.diffuse_horizontal
self.df['dni (Wh/m2)'] = self.dni
self.df['beam horizontal (Wh/m2)'] = self.beam_horizontal
def radiation_components_tilted(self):
for i in range(len(self.df)):
self.beam_tilted.append(self.dni[i] * math.cos(math.radians(self.incidents[i])))
self.beam_tilted[i] = max(self.beam_tilted[i], 0)
self.diffuse_tilted.append(self.diffuse_horizontal[i] * ((1 + math.cos(math.radians(self.tilt_angle))) / 2))
self.total_radiation_tilted.append(self.beam_tilted[i] + self.diffuse_tilted[i])
self.df['beam tilted (Wh/m2)'] = self.beam_tilted
self.df['diffuse tilted (Wh/m2)'] = self.diffuse_tilted
self.df['total radiation tilted (Wh/m2)'] = self.total_radiation_tilted
def calculate(self) -> pd.DataFrame:
self.dni_extra()
self.clearness_index()
self.diffuse_fraction()
self.radiation_components_horizontal()
self.radiation_components_tilted()
return self.df
def enrich(self):
tilted_radiation = self.total_radiation_tilted
self.building.roofs[0].global_irradiance_tilted[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES for x in
tilted_radiation]
self.building.roofs[0].global_irradiance_tilted[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES for x in
tilted_radiation]
self.building.roofs[0].global_irradiance_tilted[cte.MONTH] = (
MonthlyValues.get_total_month(self.building.roofs[0].global_irradiance_tilted[cte.HOUR]))
self.building.roofs[0].global_irradiance_tilted[cte.YEAR] = \
[sum(self.building.roofs[0].global_irradiance_tilted[cte.MONTH])]

View File

@ -1,73 +1,119 @@
import subprocess
import datetime
import os
from pathlib import Path
class LatexReport:
def __init__(self, file_name):
self.file_name = file_name
self.content = []
self.content.append(r'\documentclass{article}')
self.content.append(r'\usepackage[margin=2.5cm]{geometry}') # Adjust page margins
self.content.append(r'\usepackage{graphicx}')
self.content.append(r'\usepackage{tabularx}')
self.content.append(r'\begin{document}')
# Get current date and time
current_datetime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.content.append(r'\title{Energy System Analysis Report - ' + current_datetime + r'}')
self.content.append(r'\author{Next-Generation Cities Institute}')
self.content.append(r'\date{}') # Remove the date field, as it's included in the title now
self.content.append(r'\maketitle')
def __init__(self, file_name, title, subtitle, output_path):
self.file_name = file_name
self.output_path = Path(output_path) / 'report'
self.output_path.mkdir(parents=True, exist_ok=True)
self.file_path = self.output_path / f"{file_name}.tex"
self.content = []
self.content.append(r'\documentclass{article}')
self.content.append(r'\usepackage[margin=2.5cm]{geometry}')
self.content.append(r'\usepackage{graphicx}')
self.content.append(r'\usepackage{tabularx}')
self.content.append(r'\usepackage{multirow}')
self.content.append(r'\usepackage{float}')
self.content.append(r'\begin{document}')
current_datetime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.content.append(r'\title{' + title + '}')
self.content.append(r'\author{Next-Generation Cities Institute}')
self.content.append(r'\date{}')
self.content.append(r'\maketitle')
self.content.append(r'\begin{center}')
self.content.append(r'\large ' + subtitle + r'\\')
self.content.append(r'\large ' + current_datetime)
self.content.append(r'\end{center}')
def add_section(self, section_title):
self.content.append(r'\section{' + section_title + r'}')
self.content.append(r'\section{' + section_title + r'}')
def add_subsection(self, subsection_title):
self.content.append(r'\subsection{' + subsection_title + r'}')
self.content.append(r'\subsection{' + subsection_title + r'}')
def add_subsubsection(self, subsection_title):
self.content.append(r'\subsubsection{' + subsection_title + r'}')
def add_text(self, text):
self.content.append(text)
self.content.append(text)
def add_table(self, table_data, caption=None, first_column_width=None):
def add_table(self, table_data, caption=None, first_column_width=None, merge_first_column=False):
num_columns = len(table_data[0])
total_width = 0.9 # Default total width
total_width = 0.9
first_column_width_str = ''
if first_column_width is not None:
first_column_width_str = str(first_column_width) + 'cm'
total_width -= first_column_width / 16.0 # Adjust total width for the first column
total_width -= first_column_width / 16.0
if caption:
self.content.append(r'\begin{table}[htbp]')
self.content.append(r'\caption{' + caption + r'}')
self.content.append(r'\centering')
self.content.append(r'\begin{tabularx}{\textwidth}{|p{' + first_column_width_str + r'}|' + '|'.join(['X'] * (
num_columns - 1)) + '|}' if first_column_width is not None else r'\begin{tabularx}{\textwidth}{|' + '|'.join(
['X'] * num_columns) + '|}')
column_format = '|p{' + first_column_width_str + r'}|' + '|'.join(
['X'] * (num_columns - 1)) + '|' if first_column_width is not None else '|' + '|'.join(['X'] * num_columns) + '|'
self.content.append(r'\begin{tabularx}{\textwidth}{' + column_format + '}')
self.content.append(r'\hline')
for row in table_data:
self.content.append(' & '.join(row) + r' \\')
previous_first_column = None
rowspan_count = 1
for i, row in enumerate(table_data):
if merge_first_column and i > 0 and row[0] == previous_first_column:
rowspan_count += 1
self.content.append(' & '.join(['' if j == 0 else cell for j, cell in enumerate(row)]) + r' \\')
else:
if merge_first_column and i > 0 and rowspan_count > 1:
self.content[-rowspan_count] = self.content[-rowspan_count].replace(r'\multirow{1}',
r'\multirow{' + str(rowspan_count) + '}')
rowspan_count = 1
if merge_first_column and i < len(table_data) - 1 and row[0] == table_data[i + 1][0]:
self.content.append(r'\multirow{1}{*}{' + row[0] + '}' + ' & ' + ' & '.join(row[1:]) + r' \\')
else:
self.content.append(' & '.join(row) + r' \\')
previous_first_column = row[0]
self.content.append(r'\hline')
if merge_first_column and rowspan_count > 1:
self.content[-rowspan_count] = self.content[-rowspan_count].replace(r'\multirow{1}',
r'\multirow{' + str(rowspan_count) + '}')
self.content.append(r'\end{tabularx}')
if caption:
self.content.append(r'\end{table}')
def add_image(self, image_path, caption=None):
def add_image(self, image_path, caption=None, placement='ht'):
if caption:
self.content.append(r'\begin{figure}[htbp]')
self.content.append(r'\begin{figure}[' + placement + r']')
self.content.append(r'\centering')
self.content.append(r'\includegraphics[width=0.8\textwidth]{' + image_path + r'}')
self.content.append(r'\includegraphics[width=\textwidth]{' + image_path + r'}')
self.content.append(r'\caption{' + caption + r'}')
self.content.append(r'\end{figure}')
else:
self.content.append(r'\begin{figure}[htbp]')
self.content.append(r'\begin{figure}[' + placement + r']')
self.content.append(r'\centering')
self.content.append(r'\includegraphics[width=0.8\textwidth]{' + image_path + r'}')
self.content.append(r'\includegraphics[width=\textwidth]{' + image_path + r'}')
self.content.append(r'\end{figure}')
def add_itemize(self, items):
self.content.append(r'\begin{itemize}')
for item in items:
self.content.append(r'\item ' + item)
self.content.append(r'\end{itemize}')
def save_report(self):
self.content.append(r'\end{document}') # Add this line to close the document
with open(self.file_name, 'w') as f:
self.content.append(r'\end{document}')
with open(self.file_path, 'w') as f:
f.write('\n'.join(self.content))
def compile_to_pdf(self):
subprocess.run(['pdflatex', self.file_name])
subprocess.run(['pdflatex', '-output-directory', str(self.output_path), str(self.file_path)])

146
scripts/solar_angles.py Normal file
View File

@ -0,0 +1,146 @@
import math
import pandas as pd
from datetime import datetime
from pathlib import Path
class CitySolarAngles:
def __init__(self, file_name, location_latitude, location_longitude, tilt_angle, surface_azimuth_angle,
standard_meridian=-75):
self.file_name = file_name
self.location_latitude = location_latitude
self.location_longitude = location_longitude
self.location_latitude_rad = math.radians(location_latitude)
self.surface_azimuth_angle = surface_azimuth_angle
self.surface_azimuth_rad = math.radians(surface_azimuth_angle)
self.tilt_angle = tilt_angle
self.tilt_angle_rad = math.radians(tilt_angle)
self.standard_meridian = standard_meridian
self.longitude_correction = (location_longitude - standard_meridian) * 4
self.timezone = 'Etc/GMT+5'
self.eot = []
self.ast = []
self.hour_angles = []
self.declinations = []
self.solar_altitudes = []
self.solar_azimuths = []
self.zeniths = []
self.incidents = []
self.beam_tilted = []
self.factor = []
self.times = pd.date_range(start='2023-01-01', end='2024-01-01', freq='H', tz=self.timezone)
self.df = pd.DataFrame(index=self.times)
self.day_of_year = self.df.index.dayofyear
def solar_time(self, datetime_val, day_of_year):
b = (day_of_year - 81) * 2 * math.pi / 364
eot = 9.87 * math.sin(2 * b) - 7.53 * math.cos(b) - 1.5 * math.sin(b)
self.eot.append(eot)
# Calculate Local Solar Time (LST)
lst_hour = datetime_val.hour
lst_minute = datetime_val.minute
lst_second = datetime_val.second
lst = lst_hour + lst_minute / 60 + lst_second / 3600
# Calculate Apparent Solar Time (AST) in decimal hours
ast_decimal = lst + eot / 60 + self.longitude_correction / 60
ast_hours = int(ast_decimal)
ast_minutes = round((ast_decimal - ast_hours) * 60)
# Ensure ast_minutes is within valid range
if ast_minutes == 60:
ast_hours += 1
ast_minutes = 0
elif ast_minutes < 0:
ast_minutes = 0
ast_time = datetime(year=datetime_val.year, month=datetime_val.month, day=datetime_val.day,
hour=ast_hours, minute=ast_minutes)
self.ast.append(ast_time)
return ast_time
def declination_angle(self, day_of_year):
declination = 23.45 * math.sin(math.radians(360 / 365 * (284 + day_of_year)))
declination_radian = math.radians(declination)
self.declinations.append(declination)
return declination_radian
def hour_angle(self, ast_time):
hour_angle = ((ast_time.hour * 60 + ast_time.minute) - 720) / 4
hour_angle_radian = math.radians(hour_angle)
self.hour_angles.append(hour_angle)
return hour_angle_radian
def solar_altitude(self, declination_radian, hour_angle_radian):
solar_altitude_radians = math.asin(math.cos(self.location_latitude_rad) * math.cos(declination_radian) *
math.cos(hour_angle_radian) + math.sin(self.location_latitude_rad) *
math.sin(declination_radian))
solar_altitude = math.degrees(solar_altitude_radians)
self.solar_altitudes.append(solar_altitude)
return solar_altitude_radians
def zenith(self, solar_altitude_radians):
solar_altitude = math.degrees(solar_altitude_radians)
zenith_degree = 90 - solar_altitude
zenith_radian = math.radians(zenith_degree)
self.zeniths.append(zenith_degree)
return zenith_radian
def solar_azimuth_analytical(self, hourangle, declination, zenith):
numer = (math.cos(zenith) * math.sin(self.location_latitude_rad) - math.sin(declination))
denom = (math.sin(zenith) * math.cos(self.location_latitude_rad))
if math.isclose(denom, 0.0, abs_tol=1e-8):
cos_azi = 1.0
else:
cos_azi = numer / denom
cos_azi = max(-1.0, min(1.0, cos_azi))
sign_ha = math.copysign(1, hourangle)
solar_azimuth_radians = sign_ha * math.acos(cos_azi) + math.pi
solar_azimuth_degrees = math.degrees(solar_azimuth_radians)
self.solar_azimuths.append(solar_azimuth_degrees)
return solar_azimuth_radians
def incident_angle(self, solar_altitude_radians, solar_azimuth_radians):
incident_radian = math.acos(math.cos(solar_altitude_radians) *
math.cos(abs(solar_azimuth_radians - self.surface_azimuth_rad)) *
math.sin(self.tilt_angle_rad) + math.sin(solar_altitude_radians) *
math.cos(self.tilt_angle_rad))
incident_angle_degrees = math.degrees(incident_radian)
self.incidents.append(incident_angle_degrees)
return incident_radian
@property
def calculate(self) -> pd.DataFrame:
for i in range(len(self.times)):
datetime_val = self.times[i]
day_of_year = self.day_of_year[i]
declination_radians = self.declination_angle(day_of_year)
ast_time = self.solar_time(datetime_val, day_of_year)
hour_angle_radians = self.hour_angle(ast_time)
solar_altitude_radians = self.solar_altitude(declination_radians, hour_angle_radians)
zenith_radians = self.zenith(solar_altitude_radians)
solar_azimuth_radians = self.solar_azimuth_analytical(hour_angle_radians, declination_radians, zenith_radians)
incident_angle_radian = self.incident_angle(solar_altitude_radians, solar_azimuth_radians)
self.df['DateTime'] = self.times
self.df['AST'] = self.ast
self.df['hour angle'] = self.hour_angles
self.df['eot'] = self.eot
self.df['declination angle'] = self.declinations
self.df['solar altitude'] = self.solar_altitudes
self.df['zenith'] = self.zeniths
self.df['solar azimuth'] = self.solar_azimuths
self.df['incident angle'] = self.incidents
return self.df

View File

@ -1,135 +0,0 @@
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, out_path):
self.building = building
self.energy_systems = building.energy_systems
self.heating_demand = [0] + 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
self.out_path = out_path
def archetype1(self):
out_path = self.out_path
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 and cte.HEATING in energy_system.demand_types:
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 * 3600)
t_return = T[i + 1] - self.heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * 3600)
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 * 3600)
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] / 3600):
q_aux[i + 1] = (self.heating_demand[i + 1] / 3600) - tes_output
aux_fuel[i + 1] = (q_aux[i + 1] * dt) / 35.8e6
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, T_sup
def enrich(self):
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 = (
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:
if generation_system.system_type == cte.HEAT_PUMP:
generation_system.heat_supply_temperature = supply_temperature
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_fuel_consumption_disaggregated = disaggregated_consumption
return self.building

View File

@ -128,7 +128,7 @@ class Archetype1:
hp = self.hvac_sizing()[0]
eer_curve_coefficients = [float(coefficient) for coefficient in hp.cooling_efficiency_curve.coefficients]
cooling_efficiency = float(hp.cooling_efficiency)
demand = self._hourly_heating_demand
demand = self._hourly_cooling_demand
hp.source_temperature = self._t_out
variable_names = ["t_sup_hp", "t_ret", "m", "q_hp", "hp_electricity", "hp_eer"]
num_hours = len(demand)

View File

@ -1,49 +1,73 @@
import math
import hub.helpers.constants as cte
import csv
from hub.helpers.monthly_values import MonthlyValues
class Archetype13:
def __init__(self, building, output_path):
self._building = building
self._name = building.name
self._pv_system = building.energy_systems[0]
self._hvac_system = building.energy_systems[1]
self._dhw_system = building.energy_systems[-1]
self._dhw_peak_flow_rate = (building.thermal_zones_from_internal_zones[0].total_floor_area *
building.thermal_zones_from_internal_zones[0].domestic_hot_water.peak_flow *
cte.WATER_DENSITY)
self._heating_peak_load = building.heating_peak_load[cte.YEAR][0]
self._cooling_peak_load = building.cooling_peak_load[cte.YEAR][0]
self._domestic_hot_water_peak_load = building.domestic_hot_water_peak_load[cte.YEAR][0]
self._hourly_heating_demand = [0] + [demand / 3600 for demand in building.heating_demand[cte.HOUR]]
self._hourly_cooling_demand = [demand / 3600 for demand in building.cooling_demand[cte.HOUR]]
self._hourly_dhw_demand = building.domestic_hot_water_heat_demand[cte.HOUR]
self._hourly_heating_demand = [demand / cte.WATTS_HOUR_TO_JULES for demand in building.heating_demand[cte.HOUR]]
self._hourly_cooling_demand = [demand / cte.WATTS_HOUR_TO_JULES for demand in building.cooling_demand[cte.HOUR]]
self._hourly_dhw_demand = [demand / cte.WATTS_HOUR_TO_JULES for demand in
building.domestic_hot_water_heat_demand[cte.HOUR]]
self._output_path = output_path
self._t_out = building.external_temperature
self._t_out = building.external_temperature[cte.HOUR]
self.results = {}
self.dt = 900
def hvac_sizing(self):
storage_factor = 3
heat_pump = self._hvac_system.generation_systems[0]
boiler = self._hvac_system.generation_systems[1]
thermal_storage = heat_pump.energy_storage_systems[0]
heat_pump.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
heat_pump.nominal_cooling_output = round(self._cooling_peak_load / 3600)
boiler.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
heat_pump = self._hvac_system.generation_systems[1]
boiler = self._hvac_system.generation_systems[0]
thermal_storage = boiler.energy_storage_systems[0]
heat_pump.nominal_heat_output = round(0.5 * self._heating_peak_load)
heat_pump.nominal_cooling_output = round(self._cooling_peak_load)
boiler.nominal_heat_output = round(0.5 * self._heating_peak_load)
thermal_storage.volume = round(
(self._heating_peak_load * storage_factor) / (cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 30))
(self._heating_peak_load * storage_factor * cte.WATTS_HOUR_TO_JULES) /
(cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 25))
return heat_pump, boiler, thermal_storage
def hvac_simulation(self):
def dhw_sizing(self):
storage_factor = 3
dhw_hp = self._dhw_system.generation_systems[0]
dhw_hp.nominal_heat_output = 0.7 * self._domestic_hot_water_peak_load
dhw_hp.source_temperature = self._t_out
dhw_tes = dhw_hp.energy_storage_systems[0]
dhw_tes.volume = round(
(self._domestic_hot_water_peak_load * storage_factor * 3600) / (cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 10))
return dhw_hp, dhw_tes
def heating_system_simulation(self):
hp, boiler, tes = self.hvac_sizing()
if hp.source_medium == cte.AIR:
hp.source_temperature = self._t_out[cte.HOUR]
# Heating System Simulation
variable_names = ["t_sup", "t_tank", "t_ret", "m_ch", "m_dis", "q_hp", "q_boiler", "hp_cop",
"hp_electricity", "boiler_gas", "boiler_consumption", "heating_consumption"]
num_hours = len(self._hourly_heating_demand)
cop_curve_coefficients = [float(coefficient) for coefficient in hp.heat_efficiency_curve.coefficients]
number_of_ts = int(cte.HOUR_TO_SECONDS / self.dt)
demand = [0] + [x for x in self._hourly_heating_demand for _ in range(number_of_ts)]
t_out = [0] + [x for x in self._t_out for _ in range(number_of_ts)]
hp.source_temperature = self._t_out
variable_names = ["t_sup_hp", "t_tank", "t_ret", "m_ch", "m_dis", "q_hp", "q_boiler", "hp_cop",
"hp_electricity", "boiler_gas_consumption", "t_sup_boiler", "boiler_energy_consumption",
"heating_consumption"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup, t_tank, t_ret, m_ch, m_dis, q_hp, q_boiler, hp_cop,
hp_electricity, boiler_gas, boiler_consumption, heating_consumption) = [variables[name] for name in variable_names]
t_tank[0] = 30
dt = 3600
(t_sup_hp, t_tank, t_ret, m_ch, m_dis, q_hp, q_boiler, hp_cop,
hp_electricity, boiler_gas_consumption, t_sup_boiler, boiler_energy_consumption, heating_consumption) = \
[variables[name] for name in variable_names]
t_tank[0] = 55
hp_heating_cap = hp.nominal_heat_output
hp_efficiency = float(hp.heat_efficiency)
boiler_heating_cap = boiler.nominal_heat_output
hp_delta_t = 5
boiler_efficiency = float(boiler.heat_efficiency)
v, h = float(tes.volume), float(tes.height)
r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
@ -53,48 +77,312 @@ class Archetype13:
a_side = math.pi * d * h
a_top = math.pi * d ** 2 / 4
ua = u_tot * (2 * a_top + a_side)
for i in range(len(self._hourly_heating_demand) - 1):
# storage temperature prediction
for i in range(len(demand) - 1):
t_tank[i + 1] = (t_tank[i] +
((m_ch[i] * (t_sup[i] - t_tank[i])) +
(ua * (self._t_out[i] - t_tank[i] + 5)) / cte.WATER_HEAT_CAPACITY -
m_dis[i] * (t_tank[i] - t_ret[i])) * (dt / (cte.WATER_DENSITY * v)))
(m_ch[i] * (t_sup_boiler[i] - t_tank[i]) +
(ua * (t_out[i] - t_tank[i])) / cte.WATER_HEAT_CAPACITY -
m_dis[i] * (t_tank[i] - t_ret[i])) * (self.dt / (cte.WATER_DENSITY * v)))
# hp operation
if t_tank[i + 1] < 40:
q_hp[i + 1] = hp_heating_cap
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_tank[i + 1]
elif 45 <= t_tank[i + 1] < 55 and q_hp[i] == 0:
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t_tank[i + 1]
elif 40 <= t_tank[i + 1] < 55 and q_hp[i] == 0:
q_hp[i + 1] = 0
m_ch[i + 1] = 0
t_sup[i + 1] = t_tank[i + 1]
elif 45 <= t_tank[i + 1] < 55 and q_hp[i] > 0:
t_sup_hp[i + 1] = t_tank[i + 1]
elif 40 <= t_tank[i + 1] < 55 and q_hp[i] > 0:
q_hp[i + 1] = hp_heating_cap
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_tank[i + 1]
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t_tank[i + 1]
else:
q_hp[i + 1], m_ch[i + 1], t_sup[i + 1] = 0, 0, t_tank[i + 1]
hp_electricity[i + 1] = q_hp[i + 1] / hp_efficiency
if self._hourly_heating_demand[i + 1] == 0:
m_dis[i + 1], t_return, t_ret[i + 1] = 0, t_tank[i + 1], t_tank[i + 1]
q_hp[i + 1], m_ch[i + 1], t_sup_hp[i + 1] = 0, 0, t_tank[i + 1]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i + 1] + 32
t_out_fahrenheit = 1.8 * t_out[i + 1] + 32
if q_hp[i + 1] > 0:
hp_cop[i + 1] = (cop_curve_coefficients[0] +
cop_curve_coefficients[1] * t_sup_hp_fahrenheit +
cop_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
cop_curve_coefficients[3] * t_out_fahrenheit +
cop_curve_coefficients[4] * t_out_fahrenheit ** 2 +
cop_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i + 1] = q_hp[i + 1] / hp_cop[i + 1]
else:
if self._hourly_heating_demand[i + 1] > 0.5 * self._heating_peak_load:
hp_cop[i + 1] = 0
hp_electricity[i + 1] = 0
# boiler operation
if q_hp[i + 1] > 0:
if t_sup_hp[i + 1] < 45:
q_boiler[i + 1] = boiler_heating_cap
elif demand[i + 1] > 0.5 * self._heating_peak_load / self.dt:
q_boiler[i + 1] = 0.5 * boiler_heating_cap
boiler_energy_consumption[i + 1] = q_boiler[i + 1] / boiler_efficiency
boiler_gas_consumption[i + 1] = (q_boiler[i + 1] * self.dt) / (boiler_efficiency * cte.NATURAL_GAS_LHV)
t_sup_boiler[i + 1] = t_sup_hp[i + 1] + (q_boiler[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY))
# storage discharging
if demand[i + 1] == 0:
m_dis[i + 1] = 0
t_ret[i + 1] = t_tank[i + 1]
else:
if demand[i + 1] > 0.5 * self._heating_peak_load:
factor = 8
else:
factor = 4
m_dis[i + 1] = self._heating_peak_load / (cte.WATER_HEAT_CAPACITY * factor * 3600)
t_return = t_tank[i + 1] - self._hourly_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_tank[i + 1])
m_dis[i + 1] = self._heating_peak_load / (cte.WATER_HEAT_CAPACITY * factor)
t_ret[i + 1] = t_tank[i + 1] - demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
tes.temperature = []
hp_electricity_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in hp_electricity]
boiler_consumption_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in boiler_energy_consumption]
hp_hourly = []
boiler_hourly = []
boiler_sum = 0
hp_sum = 0
for i in range(1, len(demand)):
hp_sum += hp_electricity_j[i]
boiler_sum += boiler_consumption_j[i]
if (i - 1) % number_of_ts == 0:
tes.temperature.append(t_tank[i])
hp_hourly.append(hp_sum)
boiler_hourly.append(boiler_sum)
hp_sum = 0
boiler_sum = 0
hp.energy_consumption[cte.HEATING] = {}
hp.energy_consumption[cte.HEATING][cte.HOUR] = hp_hourly
hp.energy_consumption[cte.HEATING][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.HEATING][cte.HOUR])
hp.energy_consumption[cte.HEATING][cte.YEAR] = [
sum(hp.energy_consumption[cte.HEATING][cte.MONTH])]
boiler.energy_consumption[cte.HEATING] = {}
boiler.energy_consumption[cte.HEATING][cte.HOUR] = boiler_hourly
boiler.energy_consumption[cte.HEATING][cte.MONTH] = MonthlyValues.get_total_month(
boiler.energy_consumption[cte.HEATING][cte.HOUR])
boiler.energy_consumption[cte.HEATING][cte.YEAR] = [
sum(boiler.energy_consumption[cte.HEATING][cte.MONTH])]
self.results['Heating Demand (W)'] = demand
self.results['HP Heat Output (W)'] = q_hp
self.results['HP Source Temperature'] = t_out
self.results['HP Supply Temperature'] = t_sup_hp
self.results['HP COP'] = hp_cop
self.results['HP Electricity Consumption (W)'] = hp_electricity
self.results['Boiler Heat Output (W)'] = q_boiler
self.results['Boiler Supply Temperature'] = t_sup_boiler
self.results['Boiler Gas Consumption'] = boiler_gas_consumption
self.results['TES Temperature'] = t_tank
self.results['TES Charging Flow Rate (kg/s)'] = m_ch
self.results['TES Discharge Flow Rate (kg/s)'] = m_dis
self.results['Heating Loop Return Temperature'] = t_ret
return hp_hourly, boiler_hourly
def cooling_system_simulation(self):
hp = self.hvac_sizing()[0]
eer_curve_coefficients = [float(coefficient) for coefficient in hp.cooling_efficiency_curve.coefficients]
cooling_efficiency = float(hp.cooling_efficiency)
number_of_ts = int(cte.HOUR_TO_SECONDS / self.dt)
demand = [0] + [x for x in self._hourly_cooling_demand for _ in range(number_of_ts)]
t_out = [0] + [x for x in self._t_out for _ in range(number_of_ts)]
hp.source_temperature = self._t_out
variable_names = ["t_sup_hp", "t_ret", "m", "q_hp", "hp_electricity", "hp_eer"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t_ret, m, q_hp, hp_electricity, hp_eer) = [variables[name] for name in variable_names]
t_ret[0] = 13
for i in range(1, len(demand)):
if demand[i] > 0.15 * self._cooling_peak_load:
m[i] = hp.nominal_cooling_output / (cte.WATER_HEAT_CAPACITY * 5)
if t_ret[i - 1] >= 13:
if demand[i] < 0.25 * self._cooling_peak_load:
q_hp[i] = 0.25 * hp.nominal_cooling_output
elif demand[i] < 0.5 * self._cooling_peak_load:
q_hp[i] = 0.5 * hp.nominal_cooling_output
else:
q_hp[i] = hp.nominal_cooling_output
t_sup_hp[i] = t_ret[i - 1] - q_hp[i] / (m[i] * cte.WATER_HEAT_CAPACITY)
else:
t_ret[i + 1] = t_tank[i + 1] - self._hourly_heating_demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * 3600)
tes_output = m_dis[i + 1] * cte.WATER_HEAT_CAPACITY * (t_tank[i + 1] - t_ret[i + 1])
if tes_output < (self._hourly_heating_demand[i + 1] / 3600):
q_boiler[i + 1] = (self._hourly_heating_demand[i + 1] / 3600) - tes_output
boiler_gas[i + 1] = (q_boiler[i + 1] * dt) / 50e6
boiler_consumption[i + 1] = q_boiler[i + 1] / boiler_efficiency
heating_consumption[i + 1] = boiler_consumption[i + 1] + hp_electricity[i + 1]
data = list(zip(t_tank, t_sup, t_ret, m_ch, m_dis, q_hp, hp_electricity, boiler_gas, q_boiler,
self._hourly_heating_demand))
q_hp[i] = 0
t_sup_hp[i] = t_ret[i - 1]
if m[i] == 0:
t_ret[i] = t_sup_hp[i]
else:
t_ret[i] = t_sup_hp[i] + demand[i] / (m[i] * cte.WATER_HEAT_CAPACITY)
else:
m[i] = 0
q_hp[i] = 0
t_sup_hp[i] = t_ret[i - 1]
t_ret[i] = t_ret[i - 1]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i] + 32
t_out_fahrenheit = 1.8 * t_out[i] + 32
if q_hp[i] > 0:
hp_eer[i] = (eer_curve_coefficients[0] +
eer_curve_coefficients[1] * t_sup_hp_fahrenheit +
eer_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
eer_curve_coefficients[3] * t_out_fahrenheit +
eer_curve_coefficients[4] * t_out_fahrenheit ** 2 +
eer_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i] = q_hp[i] / cooling_efficiency
else:
hp_eer[i] = 0
hp_electricity[i] = 0
hp_electricity_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in hp_electricity]
hp_hourly = []
hp_sum = 0
for i in range(1, len(demand)):
hp_sum += hp_electricity_j[i]
if (i - 1) % number_of_ts == 0:
hp_hourly.append(hp_sum)
hp_sum = 0
hp.energy_consumption[cte.COOLING] = {}
hp.energy_consumption[cte.COOLING][cte.HOUR] = hp_hourly
hp.energy_consumption[cte.COOLING][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.COOLING][cte.HOUR])
hp.energy_consumption[cte.COOLING][cte.YEAR] = [
sum(hp.energy_consumption[cte.COOLING][cte.MONTH])]
self.results['Cooling Demand (W)'] = demand
self.results['HP Cooling Output (W)'] = q_hp
self.results['HP Cooling Supply Temperature'] = t_sup_hp
self.results['HP Cooling COP'] = hp_eer
self.results['HP Electricity Consumption'] = hp_electricity
self.results['Cooling Loop Flow Rate (kg/s)'] = m
self.results['Cooling Loop Return Temperature'] = t_ret
return hp_hourly
def dhw_system_simulation(self):
hp, tes = self.dhw_sizing()
cop_curve_coefficients = [float(coefficient) for coefficient in hp.heat_efficiency_curve.coefficients]
number_of_ts = int(cte.HOUR_TO_SECONDS / self.dt)
demand = [0] + [x for x in self._hourly_dhw_demand for _ in range(number_of_ts)]
t_out = [0] + [x for x in self._t_out for _ in range(number_of_ts)]
variable_names = ["t_sup_hp", "t_tank", "m_ch", "m_dis", "q_hp", "q_coil", "hp_cop",
"hp_electricity", "available hot water (m3)", "refill flow rate (kg/s)"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t_tank, m_ch, m_dis, m_refill, q_hp, q_coil, hp_cop, hp_electricity, v_dhw) = \
[variables[name] for name in variable_names]
t_tank[0] = 70
v_dhw[0] = tes.volume
hp_heating_cap = hp.nominal_heat_output
hp_delta_t = 8
v, h = float(tes.volume), float(tes.height)
r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
tes.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)
freshwater_temperature = 18
for i in range(len(demand) - 1):
delta_t_demand = demand[i] * (self.dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if t_tank[i] < 65:
q_hp[i] = hp_heating_cap
delta_t_hp = q_hp[i] * (self.dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if demand[i] > 0:
dhw_needed = (demand[i] * cte.HOUR_TO_SECONDS) / (cte.WATER_HEAT_CAPACITY * t_tank[i] * cte.WATER_DENSITY)
m_dis[i] = dhw_needed * cte.WATER_DENSITY / cte.HOUR_TO_SECONDS
m_refill[i] = m_dis[i]
delta_t_freshwater = m_refill[i] * (t_tank[i] - freshwater_temperature) * (self.dt / (v * cte.WATER_DENSITY))
diff = delta_t_freshwater + delta_t_demand - delta_t_hp
if diff > 0:
if diff > 0:
power = diff * (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v) / self.dt
if power <= float(tes.heating_coil_capacity):
q_coil[i] = power
else:
q_coil[i] = float(tes.heating_coil_capacity)
delta_t_coil = q_coil[i] * (self.dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if q_hp[i] > 0:
m_ch[i] = q_hp[i] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i] = (q_hp[i] / (m_ch[i] * cte.WATER_HEAT_CAPACITY)) + t_tank[i]
else:
m_ch[i] = 0
t_sup_hp[i] = t_tank[i]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i] + 32
t_out_fahrenheit = 1.8 * t_out[i] + 32
if q_hp[i] > 0:
hp_cop[i] = (cop_curve_coefficients[0] +
cop_curve_coefficients[1] * t_sup_hp_fahrenheit +
cop_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
cop_curve_coefficients[3] * t_out_fahrenheit +
cop_curve_coefficients[4] * t_out_fahrenheit ** 2 +
cop_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i] = q_hp[i] / hp_cop[i]
else:
hp_cop[i] = 0
hp_electricity[i] = 0
t_tank[i + 1] = t_tank[i] + (delta_t_hp - delta_t_freshwater - delta_t_demand + delta_t_coil)
tes.temperature = []
hp_electricity_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in hp_electricity]
heating_coil_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in q_coil]
hp_hourly = []
coil_hourly = []
coil_sum = 0
hp_sum = 0
for i in range(1, len(demand)):
hp_sum += hp_electricity_j[i]
coil_sum += heating_coil_j[i]
if (i - 1) % number_of_ts == 0:
tes.temperature.append(t_tank[i])
hp_hourly.append(hp_sum)
coil_hourly.append(coil_sum)
hp_sum = 0
coil_sum = 0
hp.energy_consumption[cte.DOMESTIC_HOT_WATER] = {}
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR] = hp_hourly
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR])
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.YEAR] = [
sum(hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.MONTH])]
tes.heating_coil_energy_consumption = {}
tes.heating_coil_energy_consumption[cte.HOUR] = coil_hourly
tes.heating_coil_energy_consumption[cte.MONTH] = MonthlyValues.get_total_month(
tes.heating_coil_energy_consumption[cte.HOUR])
tes.heating_coil_energy_consumption[cte.YEAR] = [
sum(tes.heating_coil_energy_consumption[cte.MONTH])]
tes.temperature = t_tank
self.results['DHW Demand (W)'] = demand
self.results['DHW HP Heat Output (W)'] = q_hp
self.results['DHW HP Electricity Consumption (W)'] = hp_electricity
self.results['DHW HP Source Temperature'] = t_out
self.results['DHW HP Supply Temperature'] = t_sup_hp
self.results['DHW HP COP'] = hp_cop
self.results['DHW TES Heating Coil Heat Output (W)'] = q_coil
self.results['DHW TES Temperature'] = t_tank
self.results['DHW TES Charging Flow Rate (kg/s)'] = m_ch
self.results['DHW Flow Rate (kg/s)'] = m_dis
self.results['DHW TES Refill Flow Rate (kg/s)'] = m_refill
self.results['Available Water in Tank (m3)'] = v_dhw
return hp_hourly, coil_hourly
def enrich_buildings(self):
self.hvac_sizing()
hp_heating, boiler_consumption = self.heating_system_simulation()
hp_cooling = self.cooling_system_simulation()
hp_dhw, heating_coil = self.dhw_system_simulation()
heating_consumption = [hp_heating[i] + boiler_consumption[i] for i in range(len(hp_heating))]
dhw_consumption = [hp_dhw[i] + heating_coil[i] for i in range(len(hp_dhw))]
self._building.heating_consumption[cte.HOUR] = 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])]
self._building.cooling_consumption[cte.HOUR] = hp_cooling
self._building.cooling_consumption[cte.MONTH] = (
MonthlyValues.get_total_month(self._building.cooling_consumption[cte.HOUR]))
self._building.cooling_consumption[cte.YEAR] = [sum(self._building.cooling_consumption[cte.MONTH])]
self._building.domestic_hot_water_consumption[cte.HOUR] = dhw_consumption
self._building.domestic_hot_water_consumption[cte.MONTH] = (
MonthlyValues.get_total_month(self._building.domestic_hot_water_consumption[cte.HOUR]))
self._building.domestic_hot_water_consumption[cte.YEAR] = [
sum(self._building.domestic_hot_water_consumption[cte.MONTH])]
file_name = f'energy_system_simulation_results_{self._name}.csv'
with open(self._output_path / file_name, 'w', newline='') as csvfile:
output_file = csv.writer(csvfile)
# Write header
output_file.writerow(self.results.keys())
# Write data
output_file.writerows(zip(*self.results.values()))

View File

@ -0,0 +1,392 @@
import math
import hub.helpers.constants as cte
import csv
from hub.helpers.monthly_values import MonthlyValues
import numpy as np
class Archetype13Stratified:
def __init__(self, building, output_path):
self._building = building
self._name = building.name
self._pv_system = building.energy_systems[0]
self._hvac_system = building.energy_systems[1]
self._dhw_system = building.energy_systems[-1]
self._dhw_peak_flow_rate = (building.thermal_zones_from_internal_zones[0].total_floor_area *
building.thermal_zones_from_internal_zones[0].domestic_hot_water.peak_flow *
cte.WATER_DENSITY)
self._heating_peak_load = building.heating_peak_load[cte.YEAR][0]
self._cooling_peak_load = building.cooling_peak_load[cte.YEAR][0]
self._domestic_hot_water_peak_load = building.domestic_hot_water_peak_load[cte.YEAR][0]
self._hourly_heating_demand = [demand / 3600 for demand in building.heating_demand[cte.HOUR]]
self._hourly_cooling_demand = [demand / 3600 for demand in building.cooling_demand[cte.HOUR]]
self._hourly_dhw_demand = [0] + building.domestic_hot_water_heat_demand[cte.HOUR]
self._output_path = output_path
self._t_out = building.external_temperature[cte.HOUR]
self.results = {}
def hvac_sizing(self):
storage_factor = 3
heat_pump = self._hvac_system.generation_systems[1]
boiler = self._hvac_system.generation_systems[0]
thermal_storage = boiler.energy_storage_systems[0]
heat_pump.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
heat_pump.nominal_cooling_output = round(self._cooling_peak_load / 3600)
boiler.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
thermal_storage.volume = round(
(self._heating_peak_load * storage_factor) / (cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 25))
return heat_pump, boiler, thermal_storage
def dhw_sizing(self):
storage_factor = 3
dhw_hp = self._dhw_system.generation_systems[0]
dhw_hp.nominal_heat_output = 0.7 * self._domestic_hot_water_peak_load
dhw_hp.source_temperature = self._t_out
dhw_tes = dhw_hp.energy_storage_systems[0]
dhw_tes.volume = round(
(self._domestic_hot_water_peak_load * storage_factor * 3600) / (cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 10))
return dhw_hp, dhw_tes
def heating_system_simulation_stratified(self):
hp, boiler, tes = self.hvac_sizing()
cop_curve_coefficients = [float(coefficient) for coefficient in hp.heat_efficiency_curve.coefficients]
demand = [0] + [x for x in self._hourly_heating_demand for _ in range(12)]
hp.source_temperature = self._t_out
t_out = [0] + [x for x in self._t_out for _ in range(12)]
variable_names = ["t_sup_hp", "t1", "t2", "t3", "t4", "t_tank", "t_ret", "m_ch", "m_dis", "q_hp", "q_boiler",
"hp_cop", "hp_electricity", "boiler_gas_consumption", "t_sup_boiler", "boiler_energy_consumption",
"heating_consumption"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t1, t2, t3, t4, t_tank, t_ret, m_ch, m_dis, q_hp, q_boiler, hp_cop,
hp_electricity, boiler_gas_consumption, t_sup_boiler, boiler_energy_consumption, heating_consumption) = \
[variables[name] for name in variable_names]
t_tank[0] = 55
t1[0] = 55
t2[0] = 55
t3[0] = 55
t4[0] = 55
dt = 300
hp_heating_cap = hp.nominal_heat_output
boiler_heating_cap = boiler.nominal_heat_output
hp_delta_t = 5
boiler_efficiency = float(boiler.heat_efficiency)
v, h = float(tes.volume) / 4, float(tes.height) / 4
r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
tes.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_side = u_tot * a_side
ua_top_bottom = u_tot * (a_top + a_side)
# storage temperature prediction
for i in range(len(demand) - 1):
t1[i + 1] = t1[i] + ((m_ch[i] * (t_sup_boiler[i] - t1[i])) + (
np.heaviside((m_dis[i] - m_ch[i]), 0) * (m_ch[i] - m_dis[i]) * (t1[i] - t2[i])) + (
ua_top_bottom * (t_out[i] - t1[i])) / cte.WATER_HEAT_CAPACITY - cte.WATER_THERMAL_CONDUCTIVITY * (a_top * (t1[i] - t2[i])) / (
cte.WATER_HEAT_CAPACITY * h)) * (dt / (cte.WATER_DENSITY * v))
t2[i + 1] = t2[i] + ((np.heaviside((m_dis[i] - m_ch[i]), 0) * (m_ch[i] - m_dis[i]) * (t2[i] - t3[i])) + (
ua_side * (t_out[i] - t2[i])) / cte.WATER_HEAT_CAPACITY - (cte.WATER_THERMAL_CONDUCTIVITY * (a_top * (t2[i] - t1[i])) / (cte.WATER_HEAT_CAPACITY * h)) - (
cte.WATER_THERMAL_CONDUCTIVITY * (a_top * (t2[i] - t3[i])) / (cte.WATER_HEAT_CAPACITY * h)) + (
np.heaviside((m_ch[i] - m_dis[i]), 0) * (m_ch[i] - m_dis[i]) * (
t1[i] - t2[i]))) * (dt / (cte.WATER_DENSITY * v))
t3[i + 1] = t3[i] + ((np.heaviside((m_dis[i] - m_ch[i]), 0) * (m_ch[i] - m_dis[i]) * (t3[i] - t4[i])) + (
ua_side * (t_out[i] - t3[i])) / cte.WATER_HEAT_CAPACITY - (cte.WATER_THERMAL_CONDUCTIVITY * (a_top * (t3[i] - t2[i])) / (cte.WATER_HEAT_CAPACITY * h)) - (
cte.WATER_THERMAL_CONDUCTIVITY * (a_top * (t3[i] - t4[i])) / (cte.WATER_HEAT_CAPACITY * h)) + (
np.heaviside((m_ch[i] - m_dis[i]), 0) * (m_ch[i] - m_dis[i]) * (
t2[i] - t3[i]))) * (dt / (cte.WATER_DENSITY * v))
t4[i + 1] = t4[i] + (np.heaviside((m_ch[i] - m_dis[i]), 0) * ((m_ch[i] - m_dis[i]) * (t3[i] - t4[i])) + (
ua_top_bottom * (t_out[i] - t4[-1])) / cte.WATER_HEAT_CAPACITY - m_dis[i] * ((t4[i] - t_ret[i])) - (
cte.WATER_THERMAL_CONDUCTIVITY * (a_top * (t4[i] - t3[i])) / (cte.WATER_HEAT_CAPACITY * h))) * (dt / (cte.WATER_DENSITY * v))
# hp operation
if t1[i + 1] < 40:
q_hp[i + 1] = hp_heating_cap
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t4[i + 1]
elif 40 <= t1[i + 1] < 55 and q_hp[i] == 0:
q_hp[i + 1] = 0
m_ch[i + 1] = 0
t_sup_hp[i + 1] = t4[i + 1]
elif 40 <= t1[i + 1] < 55 and q_hp[i] > 0:
q_hp[i + 1] = hp_heating_cap
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t4[i + 1]
else:
q_hp[i + 1], m_ch[i + 1], t_sup_hp[i + 1] = 0, 0, t4[i + 1]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i + 1] + 32
t_out_fahrenheit = 1.8 * t_out[i + 1] + 32
if q_hp[i + 1] > 0:
hp_cop[i + 1] = (cop_curve_coefficients[0] +
cop_curve_coefficients[1] * t_sup_hp_fahrenheit +
cop_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
cop_curve_coefficients[3] * t_out_fahrenheit +
cop_curve_coefficients[4] * t_out_fahrenheit ** 2 +
cop_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i + 1] = q_hp[i + 1] / hp_cop[i + 1]
else:
hp_cop[i + 1] = 0
hp_electricity[i + 1] = 0
# boiler operation
if q_hp[i + 1] > 0:
if t_sup_hp[i + 1] < 45:
q_boiler[i + 1] = boiler_heating_cap
elif demand[i + 1] > 0.5 * self._heating_peak_load / dt:
q_boiler[i + 1] = 0.5 * boiler_heating_cap
boiler_energy_consumption[i + 1] = q_boiler[i + 1] / boiler_efficiency
boiler_gas_consumption[i + 1] = (q_boiler[i + 1] * dt) / (boiler_efficiency * cte.NATURAL_GAS_LHV)
t_sup_boiler[i + 1] = t_sup_hp[i + 1] + (q_boiler[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY))
# storage discharging
if demand[i + 1] == 0:
m_dis[i + 1] = 0
t_ret[i + 1] = t1[i + 1]
else:
if demand[i + 1] > 0.5 * self._heating_peak_load / cte.HOUR_TO_SECONDS:
factor = 8
else:
factor = 4
m_dis[i + 1] = self._heating_peak_load / (cte.WATER_HEAT_CAPACITY * factor * cte.HOUR_TO_SECONDS)
t_ret[i + 1] = t1[i + 1] - demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
hp_electricity_wh = [x / 12 for x in hp_electricity]
boiler_consumption_wh = [x / 12 for x in boiler_energy_consumption]
hp_hourly = []
boiler_hourly = []
tes.temperature = {}
tes.temperature['layer_1'] = []
tes.temperature['layer_2'] = []
tes.temperature['layer_3'] = []
tes.temperature['layer_4'] = []
for i in range(1, len(demand), 12):
tes.temperature['layer_1'].append(t1[i])
tes.temperature['layer_2'].append(t2[i])
tes.temperature['layer_3'].append(t3[i])
tes.temperature['layer_4'].append(t4[i])
demand_modified = demand[1:]
hp_hourly.append(hp_electricity[1])
boiler_hourly.append(boiler_energy_consumption[1])
boiler_sum = 0
hp_sum = 0
for i in range(1, len(demand_modified) + 1):
hp_sum += hp_electricity_wh[i]
boiler_sum += boiler_consumption_wh[i]
if i % 12 == 0:
hp_hourly.append(hp_sum)
boiler_hourly.append(boiler_sum)
hp_sum = 0
boiler_sum = 0
hp.energy_consumption[cte.HEATING] = {}
hp.energy_consumption[cte.HEATING][cte.HOUR] = hp_hourly
hp.energy_consumption[cte.HEATING][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.HEATING][cte.HOUR])
hp.energy_consumption[cte.HEATING][cte.YEAR] = [
sum(hp.energy_consumption[cte.HEATING][cte.MONTH])]
boiler.energy_consumption[cte.HEATING] = {}
boiler.energy_consumption[cte.HEATING][cte.HOUR] = boiler_hourly
boiler.energy_consumption[cte.HEATING][cte.MONTH] = MonthlyValues.get_total_month(
boiler.energy_consumption[cte.HEATING][cte.HOUR])
boiler.energy_consumption[cte.HEATING][cte.YEAR] = [
sum(boiler.energy_consumption[cte.HEATING][cte.MONTH])]
self.results['Heating Demand (W)'] = demand
self.results['HP Heat Output (W)'] = q_hp
self.results['HP Source Temperature'] = t_out
self.results['HP Supply Temperature'] = t_sup_hp
self.results['HP COP'] = hp_cop
self.results['HP Electricity Consumption (W)'] = hp_electricity
self.results['Boiler Heat Output (W)'] = q_boiler
self.results['Boiler Supply Temperature'] = t_sup_boiler
self.results['Boiler Gas Consumption'] = boiler_gas_consumption
self.results['TES Layer 1 Temperature'] = t1
self.results['TES Layer 2 Temperature'] = t2
self.results['TES Layer 3 Temperature'] = t3
self.results['TES Layer 4 Temperature'] = t4
self.results['TES Charging Flow Rate (kg/s)'] = m_ch
self.results['TES Discharge Flow Rate (kg/s)'] = m_dis
self.results['Heating Loop Return Temperature'] = t_ret
return hp_electricity, boiler_energy_consumption
def cooling_system_simulation(self):
hp = self.hvac_sizing()[0]
eer_curve_coefficients = [float(coefficient) for coefficient in hp.cooling_efficiency_curve.coefficients]
cooling_efficiency = float(hp.cooling_efficiency)
demand = self._hourly_cooling_demand
hp.source_temperature = self._t_out
variable_names = ["t_sup_hp", "t_ret", "m", "q_hp", "hp_electricity", "hp_eer"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t_ret, m, q_hp, hp_electricity, hp_eer) = [variables[name] for name in variable_names]
t_ret[0] = 13
dt = 3600
for i in range(len(demand) - 1):
if demand[i] > 0:
m[i] = self._cooling_peak_load / (cte.WATER_HEAT_CAPACITY * 5 * dt)
if t_ret[i] > 13:
if demand[i] < 0.25 * self._cooling_peak_load / dt:
q_hp[i] = 0.25 * hp.nominal_cooling_output
elif demand[i] < 0.5 * self._cooling_peak_load / dt:
q_hp[i] = 0.5 * hp.nominal_cooling_output
else:
q_hp[i] = hp.nominal_cooling_output
t_sup_hp[i] = t_ret[i] - q_hp[i] / (m[i] * cte.WATER_HEAT_CAPACITY)
else:
q_hp[i] = 0
t_sup_hp[i] = t_ret[i]
t_ret[i + 1] = t_sup_hp[i] + demand[i] / (m[i] * cte.WATER_HEAT_CAPACITY)
else:
m[i] = 0
q_hp[i] = 0
t_sup_hp[i] = t_ret[i]
t_ret[i + 1] = t_ret[i]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i] + 32
t_out_fahrenheit = 1.8 * self._t_out[i] + 32
if q_hp[i] > 0:
hp_eer[i] = (eer_curve_coefficients[0] +
eer_curve_coefficients[1] * t_sup_hp_fahrenheit +
eer_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
eer_curve_coefficients[3] * t_out_fahrenheit +
eer_curve_coefficients[4] * t_out_fahrenheit ** 2 +
eer_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i] = q_hp[i] / cooling_efficiency
else:
hp_eer[i] = 0
hp_electricity[i] = 0
hp.energy_consumption[cte.COOLING] = {}
hp.energy_consumption[cte.COOLING][cte.HOUR] = hp_electricity
hp.energy_consumption[cte.COOLING][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.COOLING][cte.HOUR])
hp.energy_consumption[cte.COOLING][cte.YEAR] = [
sum(hp.energy_consumption[cte.COOLING][cte.MONTH])]
# self.results['Cooling Demand (W)'] = demand
# self.results['HP Cooling Output (W)'] = q_hp
# self.results['HP Cooling Supply Temperature'] = t_sup_hp
# self.results['HP Cooling COP'] = hp_eer
# self.results['HP Electricity Consumption'] = hp_electricity
# self.results['Cooling Loop Flow Rate (kg/s)'] = m
# self.results['Cooling Loop Return Temperature'] = t_ret
return hp_electricity
def dhw_system_simulation(self):
hp, tes = self.dhw_sizing()
cop_curve_coefficients = [float(coefficient) for coefficient in hp.heat_efficiency_curve.coefficients]
demand = self._hourly_dhw_demand
variable_names = ["t_sup_hp", "t_tank", "m_ch", "m_dis", "q_hp", "q_coil", "hp_cop",
"hp_electricity", "available hot water (m3)", "refill flow rate (kg/s)"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t_tank, m_ch, m_dis, m_refill, q_hp, q_coil, hp_cop, hp_electricity, v_dhw) = \
[variables[name] for name in variable_names]
t_tank[0] = 70
v_dhw[0] = tes.volume
dt = 3600
hp_heating_cap = hp.nominal_heat_output
hp_delta_t = 8
v, h = float(tes.volume), float(tes.height)
r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
tes.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)
freshwater_temperature = 18
for i in range(len(demand) - 1):
delta_t_demand = demand[i] * (dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if t_tank[i] < 65:
q_hp[i] = hp_heating_cap
delta_t_hp = q_hp[i] * (dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if demand[i] > 0:
dhw_needed = (demand[i] * cte.HOUR_TO_SECONDS) / (cte.WATER_HEAT_CAPACITY * t_tank[i] * cte.WATER_DENSITY)
m_dis[i] = dhw_needed * cte.WATER_DENSITY / cte.HOUR_TO_SECONDS
m_refill[i] = m_dis[i]
delta_t_freshwater = m_refill[i] * (t_tank[i] - freshwater_temperature) * (dt / (v * cte.WATER_DENSITY))
diff = delta_t_freshwater + delta_t_demand - delta_t_hp
if diff > 0:
if diff > 0:
power = diff * (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v) / dt
if power <= float(tes.heating_coil_capacity):
q_coil[i] = power
else:
q_coil[i] = float(tes.heating_coil_capacity)
elif t_tank[i] < 65:
q_coil[i] = float(tes.heating_coil_capacity)
delta_t_coil = q_coil[i] * (dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if q_hp[i] > 0:
m_ch[i] = q_hp[i] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i] = (q_hp[i] / (m_ch[i] * cte.WATER_HEAT_CAPACITY)) + t_tank[i]
else:
m_ch[i] = 0
t_sup_hp[i] = t_tank[i]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i] + 32
t_out_fahrenheit = 1.8 * self._t_out[i] + 32
if q_hp[i] > 0:
hp_cop[i] = (cop_curve_coefficients[0] +
cop_curve_coefficients[1] * t_sup_hp_fahrenheit +
cop_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
cop_curve_coefficients[3] * t_out_fahrenheit +
cop_curve_coefficients[4] * t_out_fahrenheit ** 2 +
cop_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i] = q_hp[i] / 3.5
else:
hp_cop[i] = 0
hp_electricity[i] = 0
t_tank[i + 1] = t_tank[i] + (delta_t_hp - delta_t_freshwater - delta_t_demand + delta_t_coil)
hp.energy_consumption[cte.DOMESTIC_HOT_WATER] = {}
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR] = hp_electricity
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR])
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.YEAR] = [
sum(hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.MONTH])]
tes.heating_coil_energy_consumption = {}
tes.heating_coil_energy_consumption[cte.HOUR] = q_coil
tes.heating_coil_energy_consumption[cte.MONTH] = MonthlyValues.get_total_month(
tes.heating_coil_energy_consumption[cte.HOUR])
tes.heating_coil_energy_consumption[cte.YEAR] = [
sum(tes.heating_coil_energy_consumption[cte.MONTH])]
tes.temperature = t_tank
# self.results['DHW Demand (W)'] = demand
# self.results['DHW HP Heat Output (W)'] = q_hp
# self.results['DHW HP Electricity Consumption (W)'] = hp_electricity
# self.results['DHW HP Source Temperature'] = self._t_out
# self.results['DHW HP Supply Temperature'] = t_sup_hp
# self.results['DHW HP COP'] = hp_cop
# self.results['DHW TES Heating Coil Heat Output (W)'] = q_coil
# self.results['DHW TES Temperature'] = t_tank
# self.results['DHW TES Charging Flow Rate (kg/s)'] = m_ch
# self.results['DHW Flow Rate (kg/s)'] = m_dis
# self.results['DHW TES Refill Flow Rate (kg/s)'] = m_refill
# self.results['Available Water in Tank (m3)'] = v_dhw
return hp_electricity, q_coil
def enrich_buildings(self):
hp_heating, boiler_consumption = self.heating_system_simulation_stratified()
# hp_cooling = self.cooling_system_simulation()
# hp_dhw, heating_coil = self.dhw_system_simulation()
heating_consumption = [hp_heating[i] + boiler_consumption[i] for i in range(len(hp_heating))]
# dhw_consumption = [hp_dhw[i] + heating_coil[i] for i in range(len(hp_dhw))]
# self._building.heating_consumption[cte.HOUR] = 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])
# self._building.cooling_consumption[cte.HOUR] = hp_cooling
# self._building.cooling_consumption[cte.MONTH] = (
# MonthlyValues.get_total_month(self._building.cooling_consumption[cte.HOUR]))
# self._building.cooling_consumption[cte.YEAR] = sum(self._building.cooling_consumption[cte.MONTH])
# self._building.domestic_hot_water_consumption[cte.HOUR] = dhw_consumption
# self._building.domestic_hot_water_consumption[cte.MONTH] = (
# MonthlyValues.get_total_month(self._building.domestic_hot_water_consumption[cte.HOUR]))
# self._building.domestic_hot_water_consumption[cte.YEAR] = (
# sum(self._building.domestic_hot_water_consumption[cte.MONTH]))
file_name = f'energy_system_simulation_results_{self._name}.csv'
with open(self._output_path / file_name, 'w', newline='') as csvfile:
output_file = csv.writer(csvfile)
# Write header
output_file.writerow(self.results.keys())
# Write data
output_file.writerows(zip(*self.results.values()))

View File

@ -0,0 +1,402 @@
import math
import hub.helpers.constants as cte
import csv
from hub.helpers.monthly_values import MonthlyValues
class Archetype14_15:
def __init__(self, building, output_path):
self._building = building
self._name = building.name
if 'PV' in building.energy_systems_archetype_name:
i = 1
self._pv_system = building.energy_systems[0]
else:
i = 0
self._dhw_system = building.energy_systems[i]
self._heating_system = building.energy_systems[i + 1]
self._cooling_system = building.energy_systems[i + 2]
self._dhw_peak_flow_rate = (building.thermal_zones_from_internal_zones[0].total_floor_area *
building.thermal_zones_from_internal_zones[0].domestic_hot_water.peak_flow *
cte.WATER_DENSITY)
self._heating_peak_load = building.heating_peak_load[cte.YEAR][0]
self._cooling_peak_load = building.cooling_peak_load[cte.YEAR][0]
self._domestic_hot_water_peak_load = building.domestic_hot_water_peak_load[cte.YEAR][0]
self._hourly_heating_demand = [demand / cte.WATTS_HOUR_TO_JULES for demand in building.heating_demand[cte.HOUR]]
self._hourly_cooling_demand = [demand / cte.WATTS_HOUR_TO_JULES for demand in building.cooling_demand[cte.HOUR]]
self._hourly_dhw_demand = [demand / cte.WATTS_HOUR_TO_JULES for demand in
building.domestic_hot_water_heat_demand[cte.HOUR]]
self._output_path = output_path
self._t_out = building.external_temperature[cte.HOUR]
self.results = {}
self.dt = 900
def heating_system_sizing(self):
storage_factor = 3
heat_pump = self._heating_system.generation_systems[1]
heat_pump.source_temperature = self._t_out
boiler = self._heating_system.generation_systems[0]
thermal_storage = boiler.energy_storage_systems[0]
heat_pump.nominal_heat_output = round(0.5 * self._heating_peak_load)
boiler.nominal_heat_output = round(0.5 * self._heating_peak_load)
thermal_storage.volume = round(
(self._heating_peak_load * storage_factor * cte.WATTS_HOUR_TO_JULES) /
(cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 25))
return heat_pump, boiler, thermal_storage
def cooling_system_sizing(self):
heat_pump = self._cooling_system.generation_systems[0]
heat_pump.nominal_cooling_output = heat_pump.nominal_cooling_output = round(self._cooling_peak_load)
heat_pump.source_temperature = self._t_out
return heat_pump
def dhw_system_sizing(self):
storage_factor = 3
dhw_hp = self._dhw_system.generation_systems[0]
dhw_hp.nominal_heat_output = round(0.7 * self._domestic_hot_water_peak_load)
dhw_hp.source_temperature = self._t_out
dhw_tes = dhw_hp.energy_storage_systems[0]
dhw_tes.volume = round(
(self._domestic_hot_water_peak_load * storage_factor * cte.WATTS_HOUR_TO_JULES) /
(cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 10))
return dhw_hp, dhw_tes
def heating_system_simulation(self):
hp, boiler, tes = self.heating_system_sizing()
cop_curve_coefficients = [float(coefficient) for coefficient in hp.heat_efficiency_curve.coefficients]
number_of_ts = int(cte.HOUR_TO_SECONDS / self.dt)
demand = [0] + [x for x in self._hourly_heating_demand for _ in range(number_of_ts)]
t_out = [0] + [x for x in self._t_out for _ in range(number_of_ts)]
hp.source_temperature = self._t_out
variable_names = ["t_sup_hp", "t_tank", "t_ret", "m_ch", "m_dis", "q_hp", "q_boiler", "hp_cop",
"hp_electricity", "boiler_gas_consumption", "t_sup_boiler", "boiler_energy_consumption",
"heating_consumption"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t_tank, t_ret, m_ch, m_dis, q_hp, q_boiler, hp_cop,
hp_electricity, boiler_gas_consumption, t_sup_boiler, boiler_energy_consumption, heating_consumption) = \
[variables[name] for name in variable_names]
t_tank[0] = 55
hp_heating_cap = hp.nominal_heat_output
boiler_heating_cap = boiler.nominal_heat_output
hp_delta_t = 5
boiler_efficiency = float(boiler.heat_efficiency)
v, h = float(tes.volume), float(tes.height)
r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
tes.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)
# storage temperature prediction
for i in range(len(demand) - 1):
t_tank[i + 1] = (t_tank[i] +
(m_ch[i] * (t_sup_boiler[i] - t_tank[i]) +
(ua * (t_out[i] - t_tank[i])) / cte.WATER_HEAT_CAPACITY -
m_dis[i] * (t_tank[i] - t_ret[i])) * (self.dt / (cte.WATER_DENSITY * v)))
# hp operation
if t_tank[i + 1] < 40:
q_hp[i + 1] = hp_heating_cap
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t_tank[i + 1]
elif 40 <= t_tank[i + 1] < 55 and q_hp[i] == 0:
q_hp[i + 1] = 0
m_ch[i + 1] = 0
t_sup_hp[i + 1] = t_tank[i + 1]
elif 40 <= t_tank[i + 1] < 55 and q_hp[i] > 0:
q_hp[i + 1] = hp_heating_cap
m_ch[i + 1] = q_hp[i + 1] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i + 1] = (q_hp[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY)) + t_tank[i + 1]
else:
q_hp[i + 1], m_ch[i + 1], t_sup_hp[i + 1] = 0, 0, t_tank[i + 1]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i + 1] + 32
t_out_fahrenheit = 1.8 * t_out[i + 1] + 32
if q_hp[i + 1] > 0:
hp_cop[i + 1] = (cop_curve_coefficients[0] +
cop_curve_coefficients[1] * t_sup_hp_fahrenheit +
cop_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
cop_curve_coefficients[3] * t_out_fahrenheit +
cop_curve_coefficients[4] * t_out_fahrenheit ** 2 +
cop_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i + 1] = q_hp[i + 1] / hp_cop[i + 1]
else:
hp_cop[i + 1] = 0
hp_electricity[i + 1] = 0
# boiler operation
if q_hp[i + 1] > 0:
if t_sup_hp[i + 1] < 45:
q_boiler[i + 1] = boiler_heating_cap
elif demand[i + 1] > 0.5 * self._heating_peak_load / self.dt:
q_boiler[i + 1] = 0.5 * boiler_heating_cap
boiler_energy_consumption[i + 1] = q_boiler[i + 1] / boiler_efficiency
boiler_gas_consumption[i + 1] = (q_boiler[i + 1] * self.dt) / (boiler_efficiency * cte.NATURAL_GAS_LHV)
t_sup_boiler[i + 1] = t_sup_hp[i + 1] + (q_boiler[i + 1] / (m_ch[i + 1] * cte.WATER_HEAT_CAPACITY))
# storage discharging
if demand[i + 1] == 0:
m_dis[i + 1] = 0
t_ret[i + 1] = t_tank[i + 1]
else:
if demand[i + 1] > 0.5 * self._heating_peak_load / cte.HOUR_TO_SECONDS:
factor = 8
else:
factor = 4
m_dis[i + 1] = self._heating_peak_load / (cte.WATER_HEAT_CAPACITY * factor * cte.HOUR_TO_SECONDS)
t_ret[i + 1] = t_tank[i + 1] - demand[i + 1] / (m_dis[i + 1] * cte.WATER_HEAT_CAPACITY)
tes.temperature = []
hp_electricity_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in hp_electricity]
boiler_consumption_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in boiler_energy_consumption]
hp_hourly = []
boiler_hourly = []
boiler_sum = 0
hp_sum = 0
for i in range(1, len(demand)):
hp_sum += hp_electricity_j[i]
boiler_sum += boiler_consumption_j[i]
if (i - 1) % number_of_ts == 0:
tes.temperature.append(t_tank[i])
hp_hourly.append(hp_sum)
boiler_hourly.append(boiler_sum)
hp_sum = 0
boiler_sum = 0
hp.energy_consumption[cte.HEATING] = {}
hp.energy_consumption[cte.HEATING][cte.HOUR] = hp_hourly
hp.energy_consumption[cte.HEATING][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.HEATING][cte.HOUR])
hp.energy_consumption[cte.HEATING][cte.YEAR] = [
sum(hp.energy_consumption[cte.HEATING][cte.MONTH])]
boiler.energy_consumption[cte.HEATING] = {}
boiler.energy_consumption[cte.HEATING][cte.HOUR] = boiler_hourly
boiler.energy_consumption[cte.HEATING][cte.MONTH] = MonthlyValues.get_total_month(
boiler.energy_consumption[cte.HEATING][cte.HOUR])
boiler.energy_consumption[cte.HEATING][cte.YEAR] = [
sum(boiler.energy_consumption[cte.HEATING][cte.MONTH])]
self.results['Heating Demand (W)'] = demand
self.results['HP Heat Output (W)'] = q_hp
self.results['HP Source Temperature'] = t_out
self.results['HP Supply Temperature'] = t_sup_hp
self.results['HP COP'] = hp_cop
self.results['HP Electricity Consumption (W)'] = hp_electricity
self.results['Boiler Heat Output (W)'] = q_boiler
self.results['Boiler Supply Temperature'] = t_sup_boiler
self.results['Boiler Gas Consumption'] = boiler_gas_consumption
self.results['TES Temperature'] = t_tank
self.results['TES Charging Flow Rate (kg/s)'] = m_ch
self.results['TES Discharge Flow Rate (kg/s)'] = m_dis
self.results['Heating Loop Return Temperature'] = t_ret
return hp_hourly, boiler_hourly
def cooling_system_simulation(self):
hp = self.cooling_system_sizing()
eer_curve_coefficients = [float(coefficient) for coefficient in hp.cooling_efficiency_curve.coefficients]
cooling_efficiency = float(hp.cooling_efficiency)
number_of_ts = int(cte.HOUR_TO_SECONDS / self.dt)
demand = [0] + [x for x in self._hourly_cooling_demand for _ in range(number_of_ts)]
t_out = [0] + [x for x in self._t_out for _ in range(number_of_ts)]
hp.source_temperature = self._t_out
variable_names = ["t_sup_hp", "t_ret", "m", "q_hp", "hp_electricity", "hp_eer"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t_ret, m, q_hp, hp_electricity, hp_eer) = [variables[name] for name in variable_names]
t_ret[0] = 13
for i in range(1, len(demand)):
if demand[i] > 0:
m[i] = self._cooling_peak_load / (cte.WATER_HEAT_CAPACITY * 5 * cte.HOUR_TO_SECONDS)
if t_ret[i - 1] >= 13:
if demand[i] < 0.25 * self._cooling_peak_load / cte.HOUR_TO_SECONDS:
q_hp[i] = 0.25 * hp.nominal_cooling_output
elif demand[i] < 0.5 * self._cooling_peak_load / cte.HOUR_TO_SECONDS:
q_hp[i] = 0.5 * hp.nominal_cooling_output
else:
q_hp[i] = hp.nominal_cooling_output
t_sup_hp[i] = t_ret[i - 1] - q_hp[i] / (m[i] * cte.WATER_HEAT_CAPACITY)
else:
q_hp[i] = 0
t_sup_hp[i] = t_ret[i - 1]
if m[i] == 0:
t_ret[i] = t_sup_hp[i]
else:
t_ret[i] = t_sup_hp[i] + demand[i] / (m[i] * cte.WATER_HEAT_CAPACITY)
else:
m[i] = 0
q_hp[i] = 0
t_sup_hp[i] = t_ret[i -1]
t_ret[i] = t_ret[i - 1]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i] + 32
t_out_fahrenheit = 1.8 * t_out[i] + 32
if q_hp[i] > 0:
hp_eer[i] = (eer_curve_coefficients[0] +
eer_curve_coefficients[1] * t_sup_hp_fahrenheit +
eer_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
eer_curve_coefficients[3] * t_out_fahrenheit +
eer_curve_coefficients[4] * t_out_fahrenheit ** 2 +
eer_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i] = q_hp[i] / hp_eer[i]
else:
hp_eer[i] = 0
hp_electricity[i] = 0
hp_electricity_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in hp_electricity]
hp_hourly = []
hp_sum = 0
for i in range(1, len(demand)):
hp_sum += hp_electricity_j[i]
if (i - 1) % number_of_ts == 0:
hp_hourly.append(hp_sum)
hp_sum = 0
hp.energy_consumption[cte.COOLING] = {}
hp.energy_consumption[cte.COOLING][cte.HOUR] = hp_hourly
hp.energy_consumption[cte.COOLING][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.COOLING][cte.HOUR])
hp.energy_consumption[cte.COOLING][cte.YEAR] = [
sum(hp.energy_consumption[cte.COOLING][cte.MONTH])]
self.results['Cooling Demand (W)'] = demand
self.results['HP Cooling Output (W)'] = q_hp
self.results['HP Cooling Supply Temperature'] = t_sup_hp
self.results['HP Cooling COP'] = hp_eer
self.results['HP Electricity Consumption'] = hp_electricity
self.results['Cooling Loop Flow Rate (kg/s)'] = m
self.results['Cooling Loop Return Temperature'] = t_ret
return hp_hourly
def dhw_system_simulation(self):
hp, tes = self.dhw_system_sizing()
cop_curve_coefficients = [float(coefficient) for coefficient in hp.heat_efficiency_curve.coefficients]
number_of_ts = int(cte.HOUR_TO_SECONDS / self.dt)
demand = [0] + [x for x in self._hourly_dhw_demand for _ in range(number_of_ts)]
t_out = [0] + [x for x in self._t_out for _ in range(number_of_ts)]
variable_names = ["t_sup_hp", "t_tank", "m_ch", "m_dis", "q_hp", "q_coil", "hp_cop",
"hp_electricity", "available hot water (m3)", "refill flow rate (kg/s)"]
num_hours = len(demand)
variables = {name: [0] * num_hours for name in variable_names}
(t_sup_hp, t_tank, m_ch, m_dis, m_refill, q_hp, q_coil, hp_cop, hp_electricity, v_dhw) = \
[variables[name] for name in variable_names]
t_tank[0] = 70
v_dhw[0] = tes.volume
hp_heating_cap = hp.nominal_heat_output
hp_delta_t = 8
v, h = float(tes.volume), float(tes.height)
r_tot = sum(float(layer.thickness) / float(layer.material.conductivity) for layer in
tes.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)
freshwater_temperature = 18
for i in range(len(demand) - 1):
delta_t_demand = demand[i] * (self.dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if t_tank[i] < 65:
q_hp[i] = hp_heating_cap
delta_t_hp = q_hp[i] * (self.dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if demand[i] > 0:
dhw_needed = (demand[i] * cte.HOUR_TO_SECONDS) / (cte.WATER_HEAT_CAPACITY * t_tank[i] * cte.WATER_DENSITY)
m_dis[i] = dhw_needed * cte.WATER_DENSITY / cte.HOUR_TO_SECONDS
m_refill[i] = m_dis[i]
delta_t_freshwater = m_refill[i] * (t_tank[i] - freshwater_temperature) * (self.dt / (v * cte.WATER_DENSITY))
diff = delta_t_freshwater + delta_t_demand - delta_t_hp
if diff > 0:
if diff > 0:
power = diff * (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v) / self.dt
if power <= float(tes.heating_coil_capacity):
q_coil[i] = power
else:
q_coil[i] = float(tes.heating_coil_capacity)
delta_t_coil = q_coil[i] * (self.dt / (cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * v))
if q_hp[i] > 0:
m_ch[i] = q_hp[i] / (cte.WATER_HEAT_CAPACITY * hp_delta_t)
t_sup_hp[i] = (q_hp[i] / (m_ch[i] * cte.WATER_HEAT_CAPACITY)) + t_tank[i]
else:
m_ch[i] = 0
t_sup_hp[i] = t_tank[i]
t_sup_hp_fahrenheit = 1.8 * t_sup_hp[i] + 32
t_out_fahrenheit = 1.8 * t_out[i] + 32
if q_hp[i] > 0:
hp_cop[i] = (cop_curve_coefficients[0] +
cop_curve_coefficients[1] * t_sup_hp_fahrenheit +
cop_curve_coefficients[2] * t_sup_hp_fahrenheit ** 2 +
cop_curve_coefficients[3] * t_out_fahrenheit +
cop_curve_coefficients[4] * t_out_fahrenheit ** 2 +
cop_curve_coefficients[5] * t_sup_hp_fahrenheit * t_out_fahrenheit)
hp_electricity[i] = q_hp[i] / hp_cop[i]
else:
hp_cop[i] = 0
hp_electricity[i] = 0
t_tank[i + 1] = t_tank[i] + (delta_t_hp - delta_t_freshwater - delta_t_demand + delta_t_coil)
tes.temperature = []
hp_electricity_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in hp_electricity]
heating_coil_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in q_coil]
hp_hourly = []
coil_hourly = []
coil_sum = 0
hp_sum = 0
for i in range(1, len(demand)):
hp_sum += hp_electricity_j[i]
coil_sum += heating_coil_j[i]
if (i - 1) % number_of_ts == 0:
tes.temperature.append(t_tank[i])
hp_hourly.append(hp_sum)
coil_hourly.append(coil_sum)
hp_sum = 0
coil_sum = 0
hp.energy_consumption[cte.DOMESTIC_HOT_WATER] = {}
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR] = hp_hourly
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.MONTH] = MonthlyValues.get_total_month(
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR])
hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.YEAR] = [
sum(hp.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.MONTH])]
tes.heating_coil_energy_consumption = {}
tes.heating_coil_energy_consumption[cte.HOUR] = coil_hourly
tes.heating_coil_energy_consumption[cte.MONTH] = MonthlyValues.get_total_month(
tes.heating_coil_energy_consumption[cte.HOUR])
tes.heating_coil_energy_consumption[cte.YEAR] = [
sum(tes.heating_coil_energy_consumption[cte.MONTH])]
tes.temperature = t_tank
self.results['DHW Demand (W)'] = demand
self.results['DHW HP Heat Output (W)'] = q_hp
self.results['DHW HP Electricity Consumption (W)'] = hp_electricity
self.results['DHW HP Source Temperature'] = t_out
self.results['DHW HP Supply Temperature'] = t_sup_hp
self.results['DHW HP COP'] = hp_cop
self.results['DHW TES Heating Coil Heat Output (W)'] = q_coil
self.results['DHW TES Temperature'] = t_tank
self.results['DHW TES Charging Flow Rate (kg/s)'] = m_ch
self.results['DHW Flow Rate (kg/s)'] = m_dis
self.results['DHW TES Refill Flow Rate (kg/s)'] = m_refill
self.results['Available Water in Tank (m3)'] = v_dhw
return hp_hourly, coil_hourly
def enrich_buildings(self):
hp_heating, boiler_consumption = self.heating_system_simulation()
hp_cooling = self.cooling_system_simulation()
hp_dhw, heating_coil = self.dhw_system_simulation()
heating_consumption = [hp_heating[i] + boiler_consumption[i] for i in range(len(hp_heating))]
dhw_consumption = [hp_dhw[i] + heating_coil[i] for i in range(len(hp_dhw))]
self._building.heating_consumption[cte.HOUR] = 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])]
self._building.cooling_consumption[cte.HOUR] = hp_cooling
self._building.cooling_consumption[cte.MONTH] = (
MonthlyValues.get_total_month(self._building.cooling_consumption[cte.HOUR]))
self._building.cooling_consumption[cte.YEAR] = [sum(self._building.cooling_consumption[cte.MONTH])]
self._building.domestic_hot_water_consumption[cte.HOUR] = dhw_consumption
self._building.domestic_hot_water_consumption[cte.MONTH] = (
MonthlyValues.get_total_month(self._building.domestic_hot_water_consumption[cte.HOUR]))
self._building.domestic_hot_water_consumption[cte.YEAR] = (
sum(self._building.domestic_hot_water_consumption[cte.MONTH]))
file_name = f'energy_system_simulation_results_{self._name}.csv'
with open(self._output_path / file_name, 'w', newline='') as csvfile:
output_file = csv.writer(csvfile)
# Write header
output_file.writerow(self.results.keys())
# Write data
output_file.writerows(zip(*self.results.values()))

67
simulation_result_test.py Normal file
View File

@ -0,0 +1,67 @@
from pathlib import Path
import subprocess
from scripts.ep_run_enrich import energy_plus_workflow
from hub.imports.geometry_factory import GeometryFactory
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
from hub.imports.results_factory import ResultFactory
from scripts.energy_system_retrofit_report import EnergySystemRetrofitReport
from scripts.geojson_creator import process_geojson
from scripts import random_assignation
from hub.imports.energy_systems_factory import EnergySystemsFactory
from scripts.energy_system_sizing import SystemSizing
from scripts.solar_angles import CitySolarAngles
from scripts.pv_sizing_and_simulation import PVSizingSimulation
from scripts.energy_system_retrofit_results import consumption_data, cost_data
from scripts.energy_system_sizing_and_simulation_factory import EnergySystemsSimulationFactory
from scripts.costs.cost import Cost
from scripts.costs.constants import SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS
import hub.helpers.constants as cte
from hub.exports.exports_factory import ExportsFactory
from scripts.pv_feasibility import pv_feasibility
# Specify the GeoJSON file path
input_files_path = (Path(__file__).parent / 'input_files')
input_files_path.mkdir(parents=True, exist_ok=True)
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0001)
geojson_file_path = input_files_path / 'output_buildings.geojson'
output_path = (Path(__file__).parent / 'out_files').resolve()
output_path.mkdir(parents=True, exist_ok=True)
energy_plus_output_path = output_path / 'energy_plus_outputs'
energy_plus_output_path.mkdir(parents=True, exist_ok=True)
simulation_results_path = (Path(__file__).parent / 'out_files' / 'simulation_results').resolve()
simulation_results_path.mkdir(parents=True, exist_ok=True)
sra_output_path = output_path / 'sra_outputs'
sra_output_path.mkdir(parents=True, exist_ok=True)
cost_analysis_output_path = output_path / 'cost_analysis'
cost_analysis_output_path.mkdir(parents=True, exist_ok=True)
city = GeometryFactory(file_type='geojson',
path=geojson_file_path,
height_field='height',
year_of_construction_field='year_of_construction',
function_field='function',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
energy_plus_workflow(city, energy_plus_output_path)
random_assignation.call_random(city.buildings, random_assignation.residential_systems_percentage)
EnergySystemsFactory('montreal_custom', city).enrich()
SystemSizing(city.buildings).montreal_custom()
for i in range(12):
monthly_cooling = 0
for building in city.buildings:
monthly_cooling += building.cooling_consumption[cte.MONTH][i] / (cte.WATTS_HOUR_TO_JULES * 1000)
print(monthly_cooling)
random_assignation.call_random(city.buildings, random_assignation.residential_new_systems_percentage)
EnergySystemsFactory('montreal_future', city).enrich()
for building in city.buildings:
if building.energy_systems_archetype_name == 'PV+4Pipe+DHW':
EnergySystemsSimulationFactory('archetype13', building=building, output_path=simulation_results_path).enrich()
for i in range(12):
monthly_cooling = 0
for building in city.buildings:
monthly_cooling += building.cooling_consumption[cte.MONTH][i] / (cte.WATTS_HOUR_TO_JULES * 1000)
print(monthly_cooling)

View File

@ -81,7 +81,7 @@ class TestConstructionFactory(TestCase):
self.assertEqual(len(building.external_temperature), 0, 'building external temperature is calculated')
self.assertEqual(len(building.global_horizontal), 0, 'building global horizontal is calculated')
self.assertEqual(len(building.diffuse), 0, 'building diffuse is calculated')
self.assertEqual(len(building.beam), 0, 'building beam is calculated')
self.assertEqual(len(building.direct_normal), 0, 'building beam is calculated')
self.assertIsNotNone(building.lower_corner, 'building lower corner is none')
self.assertEqual(len(building.sensors), 0, 'building sensors are assigned')
self.assertIsNotNone(building.internal_zones, 'no internal zones created')

View File

@ -52,7 +52,7 @@ class TestGeometryFactory(TestCase):
self.assertEqual(len(building.external_temperature), 0, 'building external temperature is calculated')
self.assertEqual(len(building.global_horizontal), 0, 'building global horizontal is calculated')
self.assertEqual(len(building.diffuse), 0, 'building diffuse is calculated')
self.assertEqual(len(building.beam), 0, 'building beam is calculated')
self.assertEqual(len(building.direct_normal), 0, 'building beam is calculated')
self.assertIsNotNone(building.lower_corner, 'building lower corner is none')
self.assertEqual(len(building.sensors), 0, 'building sensors are assigned')
self.assertIsNotNone(building.internal_zones, 'no internal zones created')

View File

@ -38,10 +38,10 @@ class TestSystemsCatalog(TestCase):
catalog = EnergySystemsCatalogFactory('montreal_future').catalog
catalog_categories = catalog.names()
archetypes = catalog.names('archetypes')
self.assertEqual(13, len(archetypes['archetypes']))
archetypes = catalog.names()
self.assertEqual(15, len(archetypes['archetypes']))
systems = catalog.names('systems')
self.assertEqual(10, len(systems['systems']))
self.assertEqual(12, len(systems['systems']))
generation_equipments = catalog.names('generation_equipments')
self.assertEqual(27, len(generation_equipments['generation_equipments']))
with self.assertRaises(ValueError):

View File

@ -44,7 +44,7 @@ class TestUsageFactory(TestCase):
self.assertEqual(len(building.external_temperature), 0, 'building external temperature is calculated')
self.assertEqual(len(building.global_horizontal), 0, 'building global horizontal is calculated')
self.assertEqual(len(building.diffuse), 0, 'building diffuse is calculated')
self.assertEqual(len(building.beam), 0, 'building beam is calculated')
self.assertEqual(len(building.direct_normal), 0, 'building beam is calculated')
self.assertIsNotNone(building.lower_corner, 'building lower corner is none')
self.assertEqual(len(building.sensors), 0, 'building sensors are assigned')
self.assertIsNotNone(building.internal_zones, 'no internal zones created')