""" Total operational costs module SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2024 Project Coder Saeed Ranjbar saeed.ranjbar@mail.concordia.ca Code contributor Oriol Gavalda Torrellas oriol.gavalda@concordia.ca """ import math import pandas as pd from hub.city_model_structure.building import Building import hub.helpers.constants as cte from costing_package.configuration import Configuration from costing_package.cost_base import CostBase from costing_package.peak_load import PeakLoad class TotalOperationalCosts(CostBase): """ Total Operational costs class """ def __init__(self, building: Building, configuration: Configuration): super().__init__(building, configuration) columns_list = self.columns() self._yearly_operational_costs = pd.DataFrame( index=self._rng, columns=columns_list, dtype='float' ) def calculate(self) -> pd.DataFrame: """ Calculate total operational costs :return: pd.DataFrame """ building = self._building fuel_consumption_breakdown = building.energy_consumption_breakdown archetype = self._archetype total_floor_area = self._total_floor_area if archetype.function == 'residential': factor = total_floor_area / 80 else: factor = 1 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 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 * float(fuel.variable.values[0]) / 1000 ) else: 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: 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()) / ( 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 def columns(self): columns_list = [] fuels = [key for key in self._building.energy_consumption_breakdown.keys()] for fuel in fuels: if fuel == cte.ELECTRICITY: columns_list.append('Fixed Costs Electricity Peak') columns_list.append('Fixed Costs Electricity Monthly') columns_list.append('Variable Costs Electricity') else: columns_list.append(f'Fixed Costs {fuel}') columns_list.append(f'Variable Costs {fuel}') return columns_list def search_fuel(self, system_fuel, tariff): fuels = self._archetype.operational_cost.fuels for fuel in fuels: if system_fuel == fuel.type and tariff == fuel.variable.name: return fuel raise KeyError(f'fuel {system_fuel} with {tariff} tariff not found') def hourly_fuel_consumption_profile(self, fuel_type): hourly_fuel_consumption = [] energy_systems = self._building.energy_systems if fuel_type == cte.ELECTRICITY: appliance = self._building.appliances_electrical_demand[cte.HOUR] lighting = self._building.lighting_electrical_demand[cte.HOUR] elec_heating = 0 elec_cooling = 0 elec_dhw = 0 if cte.HEATING in self._building.energy_consumption_breakdown[cte.ELECTRICITY]: elec_heating = 1 if cte.COOLING in self._building.energy_consumption_breakdown[cte.ELECTRICITY]: elec_cooling = 1 if cte.DOMESTIC_HOT_WATER in self._building.energy_consumption_breakdown[cte.ELECTRICITY]: elec_dhw = 1 heating = None cooling = None dhw = None if elec_heating == 1: for energy_system in energy_systems: if cte.HEATING in energy_system.demand_types: for generation_system in energy_system.generation_systems: if generation_system.fuel_type == cte.ELECTRICITY: if cte.HEATING in generation_system.energy_consumption: heating = generation_system.energy_consumption[cte.HEATING][cte.HOUR] else: if len(energy_system.generation_systems) > 1: heating = [x / 2 for x in self._building.heating_consumption[cte.HOUR]] else: heating = self._building.heating_consumption[cte.HOUR] if elec_dhw == 1: for energy_system in energy_systems: if cte.DOMESTIC_HOT_WATER in energy_system.demand_types: for generation_system in energy_system.generation_systems: if generation_system.fuel_type == cte.ELECTRICITY: if cte.DOMESTIC_HOT_WATER in generation_system.energy_consumption: dhw = generation_system.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR] else: if len(energy_system.generation_systems) > 1: dhw = [x / 2 for x in self._building.domestic_hot_water_consumption[cte.HOUR]] else: dhw = self._building.domestic_hot_water_consumption[cte.HOUR] if elec_cooling == 1: for energy_system in energy_systems: if cte.COOLING in energy_system.demand_types: for generation_system in energy_system.generation_systems: if cte.COOLING in generation_system.energy_consumption: cooling = generation_system.energy_consumption[cte.COOLING][cte.HOUR] else: if len(energy_system.generation_systems) > 1: cooling = [x / 2 for x in self._building.cooling_consumption[cte.HOUR]] else: cooling = self._building.cooling_consumption[cte.HOUR] for i in range(len(self._building.heating_demand[cte.HOUR])): hourly = 0 hourly += appliance[i] / 3600 hourly += lighting[i] / 3600 if heating is not None: hourly += heating[i] / 3600 if cooling is not None: hourly += cooling[i] / 3600 if dhw is not None: hourly += dhw[i] / 3600 hourly_fuel_consumption.append(hourly) else: heating = None dhw = None if cte.HEATING in self._building.energy_consumption_breakdown[fuel_type]: for energy_system in energy_systems: if cte.HEATING in energy_system.demand_types: for generation_system in energy_system.generation_systems: if cte.HEATING in generation_system.energy_consumption: heating = generation_system.energy_consumption[cte.HEATING][cte.HOUR] else: if len(energy_system.generation_systems) > 1: heating = [x / 2 for x in self._building.heating_consumption[cte.HOUR]] else: heating = self._building.heating_consumption[cte.HOUR] if cte.DOMESTIC_HOT_WATER in self._building.energy_consumption_breakdown[fuel_type]: for energy_system in energy_systems: if cte.DOMESTIC_HOT_WATER in energy_system.demand_types: for generation_system in energy_system.generation_systems: if cte.DOMESTIC_HOT_WATER in generation_system.energy_consumption: dhw = generation_system.energy_consumption[cte.DOMESTIC_HOT_WATER][cte.HOUR] else: if len(energy_system.generation_systems) > 1: dhw = [x / 2 for x in self._building.domestic_hot_water_consumption[cte.HOUR]] else: dhw = self._building.domestic_hot_water_consumption[cte.HOUR] for i in range(len(self._building.heating_demand[cte.HOUR])): hourly = 0 if heating is not None: hourly += heating[i] / 3600 if dhw is not None: hourly += dhw[i] / 3600 hourly_fuel_consumption.append(hourly) return hourly_fuel_consumption