fix: different fuel pricings are added, operational and maintenance cost calculations are modified, cost catalogue adjusted to the changes #10
@ -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')
|
||||
|
||||
@ -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
|
||||
|
@ -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],
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
62
hub/catalog_factories/data_models/cost/pricing_rate.py
Normal file
62
hub/catalog_factories/data_models/cost/pricing_rate.py
Normal 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
|
@ -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 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
|
||||
@ -484,7 +485,7 @@ class Building(CityObject):
|
||||
if monthly_values is None:
|
||||
return None
|
||||
results[cte.MONTH] = [x for x in monthly_values]
|
||||
results[cte.YEAR] = [max(monthly_values)]
|
||||
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
|
||||
return results
|
||||
|
||||
@property
|
||||
@ -911,3 +912,11 @@ class Building(CityObject):
|
||||
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
|
||||
|
||||
@property
|
||||
def pv_generation(self) -> dict:
|
||||
return self._pv_generation
|
||||
|
||||
@pv_generation.setter
|
||||
def pv_generation(self, value):
|
||||
self._pv_generation = value
|
||||
|
@ -47,6 +47,7 @@ class Surface:
|
||||
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):
|
||||
@ -401,3 +402,19 @@ class Surface:
|
||||
: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
|
106
hub/data/costs/fuel_rates.json
Normal file
106
hub/data/costs/fuel_rates.json
Normal 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
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
||||
@ -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>
|
||||
|
45
main.py
45
main.py
@ -1,45 +0,0 @@
|
||||
from scripts.geojson_creator import process_geojson
|
||||
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_analysis_report import EnergySystemAnalysisReport
|
||||
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.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
|
||||
import hub.helpers.constants as cte
|
||||
from hub.exports.exports_factory import ExportsFactory
|
||||
# Specify the GeoJSON file path
|
||||
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0001)
|
||||
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()
|
||||
energy_plus_workflow(city)
|
||||
random_assignation.call_random(city.buildings, random_assignation.residential_new_systems_percentage)
|
||||
EnergySystemsFactory('montreal_future', city).enrich()
|
||||
|
||||
for building in city.buildings:
|
||||
EnergySystemsSimulationFactory('archetype13', building=building, output_path=output_path).enrich()
|
||||
|
||||
print('test')
|
@ -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)
|
||||
from scripts.costs.cost_base import CostBase
|
||||
|
||||
|
||||
@ -36,7 +37,6 @@ class CapitalCosts(CostBase):
|
||||
'D3050_other_hvac_ahu',
|
||||
'D3060_storage_systems',
|
||||
'D40_dhw',
|
||||
'D5020_lighting_and_branch_wiring'
|
||||
],
|
||||
dtype='float'
|
||||
)
|
||||
@ -50,7 +50,6 @@ class CapitalCosts(CostBase):
|
||||
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, '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 +69,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 +107,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):
|
||||
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,18 +149,13 @@ 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_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':
|
||||
capital_cost_heating_and_cooling_equipment += chapter.item(component).initial_investment[0] * component_sizes[i]
|
||||
@ -171,26 +168,31 @@ 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
|
||||
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):
|
||||
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)
|
||||
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)
|
||||
|
||||
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'] = (
|
||||
@ -228,23 +230,7 @@ class CapitalCosts(CostBase):
|
||||
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):
|
||||
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
|
||||
)
|
||||
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] == 'generation':
|
||||
@ -259,6 +245,17 @@ class CapitalCosts(CostBase):
|
||||
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
|
||||
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
|
||||
)
|
||||
|
||||
def system_components(self):
|
||||
system_components = []
|
||||
@ -308,7 +305,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
|
||||
|
||||
|
@ -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
|
||||
|
@ -11,9 +11,11 @@ CURRENT_STATUS = 0
|
||||
SKIN_RETROFIT = 1
|
||||
SYSTEM_RETROFIT_AND_PV = 2
|
||||
SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV = 3
|
||||
PV = 4
|
||||
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
|
||||
]
|
||||
|
@ -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:
|
||||
@ -94,7 +98,6 @@ class Cost:
|
||||
global_capital_costs['D3050_other_hvac_ahu'] +
|
||||
global_capital_costs['D3060_storage_systems'] +
|
||||
global_capital_costs['D40_dhw'] +
|
||||
global_capital_costs['D5020_lighting_and_branch_wiring'] +
|
||||
global_capital_costs['D2010_photovoltaic_system']
|
||||
)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -25,6 +25,7 @@ class TotalMaintenanceCosts(CostBase):
|
||||
columns=[
|
||||
'Heating_maintenance',
|
||||
'Cooling_maintenance',
|
||||
'DHW_maintenance',
|
||||
'PV_maintenance'
|
||||
],
|
||||
dtype='float'
|
||||
@ -39,15 +40,76 @@ 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.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
|
||||
|
||||
print(dhw_equipments)
|
||||
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 +120,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
|
||||
|
||||
|
||||
|
@ -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:
|
||||
dhw += 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
|
||||
|
||||
|
||||
|
||||
|
@ -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))
|
||||
|
||||
|
||||
|
||||
|
@ -15,8 +15,8 @@ from hub.city_model_structure.building import Building
|
||||
energy_systems_format = 'montreal_custom'
|
||||
|
||||
# parameters:
|
||||
residential_systems_percentage = {'system 1 gas': 44,
|
||||
'system 1 electricity': 6,
|
||||
residential_systems_percentage = {'system 1 gas': 100,
|
||||
'system 1 electricity': 0,
|
||||
'system 2 gas': 0,
|
||||
'system 2 electricity': 0,
|
||||
'system 3 and 4 gas': 0,
|
||||
@ -25,8 +25,8 @@ residential_systems_percentage = {'system 1 gas': 44,
|
||||
'system 5 electricity': 0,
|
||||
'system 6 gas': 0,
|
||||
'system 6 electricity': 0,
|
||||
'system 8 gas': 44,
|
||||
'system 8 electricity': 6}
|
||||
'system 8 gas': 0,
|
||||
'system 8 electricity': 0}
|
||||
|
||||
residential_new_systems_percentage = {'PV+ASHP+GasBoiler+TES': 0,
|
||||
'PV+4Pipe+DHW': 100,
|
||||
|
Loading…
Reference in New Issue
Block a user