From ef21ad949d3dc03b3a02d5fa0c292c147095b120 Mon Sep 17 00:00:00 2001 From: s_ranjbar Date: Thu, 20 Jun 2024 09:39:47 -0400 Subject: [PATCH] fix: different fuel pricings are added, operational and maintenance cost calculations are modified, cost catalogue adjusted to the changes --- .../cost/montreal_complete_cost_catalog.py | 68 ++++-- .../data_models/cost/fuel.py | 14 +- .../data_models/cost/item_description.py | 18 +- .../data_models/cost/operational_cost.py | 27 +-- .../data_models/cost/pricing_rate.py | 62 ++++++ hub/city_model_structure/building.py | 19 +- .../building_demand/surface.py | 17 ++ hub/data/costs/fuel_rates.json | 106 +++++++++ hub/data/costs/montreal_costs_completed.xml | 88 ++++++-- main.py | 45 ---- scripts/costs/capital_costs.py | 97 ++++----- scripts/costs/configuration.py | 11 +- scripts/costs/constants.py | 4 +- scripts/costs/cost.py | 9 +- scripts/costs/peak_load.py | 2 +- scripts/costs/total_maintenance_costs.py | 86 +++++++- scripts/costs/total_operational_costs.py | 201 +++++++++++++++--- scripts/energy_system_sizing.py | 8 +- scripts/random_assignation.py | 8 +- 19 files changed, 678 insertions(+), 212 deletions(-) create mode 100644 hub/catalog_factories/data_models/cost/pricing_rate.py create mode 100644 hub/data/costs/fuel_rates.json diff --git a/hub/catalog_factories/cost/montreal_complete_cost_catalog.py b/hub/catalog_factories/cost/montreal_complete_cost_catalog.py index 7d6e8ade..5e3927ee 100644 --- a/hub/catalog_factories/cost/montreal_complete_cost_catalog.py +++ b/hub/catalog_factories/cost/montreal_complete_cost_catalog.py @@ -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 diff --git a/hub/catalog_factories/data_models/cost/fuel.py b/hub/catalog_factories/data_models/cost/fuel.py index 5eb4866c..560b4da9 100644 --- a/hub/catalog_factories/data_models/cost/fuel.py +++ b/hub/catalog_factories/data_models/cost/fuel.py @@ -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], diff --git a/hub/catalog_factories/data_models/cost/item_description.py b/hub/catalog_factories/data_models/cost/item_description.py index a193bb23..192d7503 100644 --- a/hub/catalog_factories/data_models/cost/item_description.py +++ b/hub/catalog_factories/data_models/cost/item_description.py @@ -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] } } diff --git a/hub/catalog_factories/data_models/cost/operational_cost.py b/hub/catalog_factories/data_models/cost/operational_cost.py index 1275830a..4f69cceb 100644 --- a/hub/catalog_factories/data_models/cost/operational_cost.py +++ b/hub/catalog_factories/data_models/cost/operational_cost.py @@ -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 } diff --git a/hub/catalog_factories/data_models/cost/pricing_rate.py b/hub/catalog_factories/data_models/cost/pricing_rate.py new file mode 100644 index 00000000..fe1c219c --- /dev/null +++ b/hub/catalog_factories/data_models/cost/pricing_rate.py @@ -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 diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py index 660f0f7e..ac284d29 100644 --- a/hub/city_model_structure/building.py +++ b/hub/city_model_structure/building.py @@ -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 diff --git a/hub/city_model_structure/building_demand/surface.py b/hub/city_model_structure/building_demand/surface.py index f54d21e1..65f90ae3 100644 --- a/hub/city_model_structure/building_demand/surface.py +++ b/hub/city_model_structure/building_demand/surface.py @@ -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 \ No newline at end of file diff --git a/hub/data/costs/fuel_rates.json b/hub/data/costs/fuel_rates.json new file mode 100644 index 00000000..0841e818 --- /dev/null +++ b/hub/data/costs/fuel_rates.json @@ -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 + ] + } + ] + } + } +} \ No newline at end of file diff --git a/hub/data/costs/montreal_costs_completed.xml b/hub/data/costs/montreal_costs_completed.xml index 81b67768..fc23634a 100644 --- a/hub/data/costs/montreal_costs_completed.xml +++ b/hub/data/costs/montreal_costs_completed.xml @@ -25,8 +25,8 @@ - 0 - 0 + 300 + 300 25 @@ -124,34 +124,58 @@ - 12.27 - 0 - 0.075 - - + 12.27 + 0 + Electricity-D + + + 12.27 + 0 + Electricity-Flex-D 17.71 - 0.4 + Gas-Energir 0.777 47.1 - 1.2 + Diesel-Fixed 0.846 42.6 - 0.04 + Biomass-Fixed 18 - 40 - 40 + + + 100 + + + 60 + + + 50 + + + 50 + + + 100 + + + 60 + + + 50 + + 1 30 @@ -294,31 +318,57 @@ 12.27 0 - 0.075 + Electricity-D + + + 12.27 + 0 + Electricity-Flex-D 17.71 - 0.0640 + Gas-Energir 0.777 47.1 - 1.2 + Diesel-Fixed 0.846 42.6 - 0.04 + Biomass-Fixed 18 - 40 - 40 - 0 + + + 100 + + + 60 + + + 50 + + + 50 + + + 100 + + + 60 + + + 50 + + + 1 30 diff --git a/main.py b/main.py index 798b5d4c..e69de29b 100644 --- a/main.py +++ b/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') diff --git a/scripts/costs/capital_costs.py b/scripts/costs/capital_costs.py index 68d751d8..c87f3eba 100644 --- a/scripts/costs/capital_costs.py +++ b/scripts/costs/capital_costs.py @@ -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 diff --git a/scripts/costs/configuration.py b/scripts/costs/configuration.py index f868da79..3d5b9485 100644 --- a/scripts/costs/configuration.py +++ b/scripts/costs/configuration.py @@ -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 diff --git a/scripts/costs/constants.py b/scripts/costs/constants.py index cbf11e57..18543adf 100644 --- a/scripts/costs/constants.py +++ b/scripts/costs/constants.py @@ -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 ] diff --git a/scripts/costs/cost.py b/scripts/costs/cost.py index 996c4724..2ebd1ffc 100644 --- a/scripts/costs/cost.py +++ b/scripts/costs/cost.py @@ -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'] ) diff --git a/scripts/costs/peak_load.py b/scripts/costs/peak_load.py index 108f748a..422f563b 100644 --- a/scripts/costs/peak_load.py +++ b/scripts/costs/peak_load.py @@ -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, diff --git a/scripts/costs/total_maintenance_costs.py b/scripts/costs/total_maintenance_costs.py index 81a88de8..0f5b7dfc 100644 --- a/scripts/costs/total_maintenance_costs.py +++ b/scripts/costs/total_maintenance_costs.py @@ -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 + + diff --git a/scripts/costs/total_operational_costs.py b/scripts/costs/total_operational_costs.py index 6b0c1e27..dc672fa1 100644 --- a/scripts/costs/total_operational_costs.py +++ b/scripts/costs/total_operational_costs.py @@ -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 + + + diff --git a/scripts/energy_system_sizing.py b/scripts/energy_system_sizing.py index e626bc7d..77f876b4 100644 --- a/scripts/energy_system_sizing.py +++ b/scripts/energy_system_sizing.py @@ -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)) diff --git a/scripts/random_assignation.py b/scripts/random_assignation.py index 958f269d..f82ab89f 100644 --- a/scripts/random_assignation.py +++ b/scripts/random_assignation.py @@ -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,