diff --git a/costs/README.md b/costs/README.md index c0298ea..bae8105 100644 --- a/costs/README.md +++ b/costs/README.md @@ -1,3 +1,4 @@ -# costs_workflow +# Cerc costs -This workflow is a test to check that the process of calculating costs is correct before creating the API. +Uses the cerc-hub as a base for cost calculation, it's intended to be used after executing the complete monthly energy +balance workflow called building by building diff --git a/costs/__main__.py b/costs/__main__.py index b8b6ab3..87e2e44 100644 --- a/costs/__main__.py +++ b/costs/__main__.py @@ -4,4 +4,3 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributor Oriol Gavalda Torrellas oriol.gavalda@concordia.ca """ - diff --git a/costs/capital_costs.py b/costs/capital_costs.py index c40d125..ce7835a 100644 --- a/costs/capital_costs.py +++ b/costs/capital_costs.py @@ -9,32 +9,17 @@ from hub.city_model_structure.building import Building import hub.helpers.constants as cte from configuration import Configuration from costs import SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV +from costs.cost_base import CostBase -class CapitalCosts: +class CapitalCosts(CostBase): """ Capital costs class """ def __init__(self, building: Building, configuration: Configuration): - self._building = building - self._configuration = configuration - self._total_floor_area = 0 - for internal_zone in building.internal_zones: - for thermal_zone in internal_zone.thermal_zones: - self._total_floor_area += thermal_zone.total_floor_area - self._archetype = None - for archetype in self._configuration.cost_catalog.entries('archetypes').archetype: - if str(building.function) == str(archetype.function): - self._archetype = archetype - self._capital_costs_chapter = self._archetype.capital_cost - break - if not self._archetype: - raise KeyError('archetype not found') - - self._capital_costs_chapter = None - rng = range(configuration.number_of_years) + super().__init__(building, configuration) self._yearly_capital_costs = pd.DataFrame( - index=rng, + index=self._rng, columns=[ 'B2010_opaque_walls', 'B2020_transparent', @@ -60,7 +45,7 @@ class CapitalCosts: self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = 0 self._yearly_capital_incomes = pd.DataFrame( - index=rng, + index=self._rng, columns=[ 'Subsidies construction', 'Subsidies HVAC', @@ -111,7 +96,7 @@ class CapitalCosts: surface_pv += roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor self._yearly_capital_costs.fillna(0, inplace=True) - own_capital = (1 - self._configuration.percentage_credit) + own_capital = 1 - self._configuration.percentage_credit if self._configuration.retrofit_scenario in (SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV): chapter = self._capital_costs_chapter.chapter('B_shell') capital_cost_opaque = surface_opaque * chapter.item('B2010_opaque_walls').refurbishment[0] diff --git a/costs/configuration.py b/costs/configuration.py index 4e87da4..b7929d7 100644 --- a/costs/configuration.py +++ b/costs/configuration.py @@ -203,8 +203,14 @@ class Configuration: @property def retrofit_scenario(self): + """ + Get retrofit scenario + """ return self._retrofit_scenario @property def fuel_type(self): + """ + Get fuel type (0: Electricity, 1: Gas) + """ return self._fuel_type diff --git a/costs/cost.py b/costs/cost.py index f47c824..94a02ef 100644 --- a/costs/cost.py +++ b/costs/cost.py @@ -46,6 +46,20 @@ class Cost: retrofit_scenario, fuel_type) + @property + def building(self) -> Building: + """ + Get current building. + """ + return self._building + + @building.setter + def building(self, value: Building): + """ + Set current building. + """ + self._building = value + def _npv_from_list(self, list_cashflow): return npf.npv(self._configuration.discount_rate, list_cashflow) diff --git a/costs/cost_base.py b/costs/cost_base.py new file mode 100644 index 0000000..0ff5102 --- /dev/null +++ b/costs/cost_base.py @@ -0,0 +1,37 @@ +""" +Cost base module +""" + +from hub.city_model_structure.building import Building + +from configuration import Configuration + + +class CostBase: + """ + Abstract base class for the costs + """ + def __init__(self, building: Building, configuration: Configuration): + self._building = building + self._configuration = configuration + self._total_floor_area = 0 + for internal_zone in building.internal_zones: + for thermal_zone in internal_zone.thermal_zones: + self._total_floor_area += thermal_zone.total_floor_area + self._archetype = None + for archetype in self._configuration.cost_catalog.entries('archetypes').archetype: + if str(building.function) == str(archetype.function): + self._archetype = archetype + self._capital_costs_chapter = self._archetype.capital_cost + break + if not self._archetype: + raise KeyError('archetype not found') + + self._capital_costs_chapter = None + self._rng = range(configuration.number_of_years) + + def calculate(self): + """ + Raises not implemented exception + """ + raise NotImplementedError() diff --git a/costs/end_of_life_costs.py b/costs/end_of_life_costs.py index bf45384..7f7cf41 100644 --- a/costs/end_of_life_costs.py +++ b/costs/end_of_life_costs.py @@ -6,30 +6,16 @@ import pandas as pd from hub.city_model_structure.building import Building from configuration import Configuration +from costs.cost_base import CostBase -class EndOfLifeCosts: +class EndOfLifeCosts(CostBase): """ End of life costs class """ def __init__(self, building: Building, configuration: Configuration): - self._building = building - self._configuration = configuration - self._total_floor_area = 0 - for internal_zone in building.internal_zones: - for thermal_zone in internal_zone.thermal_zones: - self._total_floor_area += thermal_zone.total_floor_area - self._archetype = None - for archetype in self._configuration.cost_catalog.entries('archetypes').archetype: - if str(building.function) == str(archetype.function): - self._archetype = archetype - self._capital_costs_chapter = self._archetype.capital_cost - break - if not self._archetype: - raise KeyError('archetype not found') - - rng = range(configuration.number_of_years) - self._yearly_end_of_life_costs = pd.DataFrame(index=rng, columns=['End_of_life_costs'], dtype='float') + super().__init__(building, configuration) + self._yearly_end_of_life_costs = pd.DataFrame(index=self._rng, columns=['End_of_life_costs'], dtype='float') def calculate(self): """ diff --git a/costs/total_maintenance_costs.py b/costs/total_maintenance_costs.py index 42a7121..8dce3b8 100644 --- a/costs/total_maintenance_costs.py +++ b/costs/total_maintenance_costs.py @@ -7,31 +7,17 @@ from hub.city_model_structure.building import Building import hub.helpers.constants as cte from configuration import Configuration +from costs.cost_base import CostBase -class TotalMaintenanceCosts: +class TotalMaintenanceCosts(CostBase): """ Total maintenance costs class """ def __init__(self, building: Building, configuration: Configuration): - self._building = building - self._configuration = configuration - self._total_floor_area = 0 - for internal_zone in building.internal_zones: - for thermal_zone in internal_zone.thermal_zones: - self._total_floor_area += thermal_zone.total_floor_area - self._archetype = None - for archetype in self._configuration.cost_catalog.entries('archetypes').archetype: - if str(building.function) == str(archetype.function): - self._archetype = archetype - self._capital_costs_chapter = self._archetype.capital_cost - break - if not self._archetype: - raise KeyError('archetype not found') - - rng = range(configuration.number_of_years) + super().__init__(building, configuration) self._yearly_maintenance_costs = pd.DataFrame( - index=rng, + index=self._rng, columns=[ 'Heating_maintenance', 'Cooling_maintenance', diff --git a/costs/total_operational_costs.py b/costs/total_operational_costs.py index 9759ddb..a6513e5 100644 --- a/costs/total_operational_costs.py +++ b/costs/total_operational_costs.py @@ -8,31 +8,17 @@ from hub.city_model_structure.building import Building import hub.helpers.constants as cte from configuration import Configuration +from costs.cost_base import CostBase -class TotalOperationalCosts: +class TotalOperationalCosts(CostBase): """ End of life costs class """ def __init__(self, building: Building, configuration: Configuration): - self._building = building - self._configuration = configuration - self._total_floor_area = 0 - for internal_zone in building.internal_zones: - for thermal_zone in internal_zone.thermal_zones: - self._total_floor_area += thermal_zone.total_floor_area - self._archetype = None - for archetype in self._configuration.cost_catalog.entries('archetypes').archetype: - if str(building.function) == str(archetype.function): - self._archetype = archetype - self._capital_costs_chapter = self._archetype.capital_cost - break - if not self._archetype: - raise KeyError('archetype not found') - - rng = range(configuration.number_of_years) + super().__init__(building, configuration) self._yearly_operational_costs = pd.DataFrame( - index=rng, + index=self._rng, columns=[ 'Fixed_costs_electricity_peak', 'Fixed_costs_electricity_monthly', diff --git a/costs/total_operational_incomes.py b/costs/total_operational_incomes.py index 386c1a2..c8af92c 100644 --- a/costs/total_operational_incomes.py +++ b/costs/total_operational_incomes.py @@ -7,30 +7,16 @@ from hub.city_model_structure.building import Building import hub.helpers.constants as cte from configuration import Configuration +from costs.cost_base import CostBase -class TotalOperationalIncomes: +class TotalOperationalIncomes(CostBase): """ Total operational incomes class """ def __init__(self, building: Building, configuration: Configuration): - self._building = building - self._configuration = configuration - self._total_floor_area = 0 - for internal_zone in building.internal_zones: - for thermal_zone in internal_zone.thermal_zones: - self._total_floor_area += thermal_zone.total_floor_area - self._archetype = None - for archetype in self._configuration.cost_catalog.entries('archetypes').archetype: - if str(building.function) == str(archetype.function): - self._archetype = archetype - self._capital_costs_chapter = self._archetype.capital_cost - break - if not self._archetype: - raise KeyError('archetype not found') - - rng = range(configuration.number_of_years) - self._yearly_operational_incomes = pd.DataFrame(index=rng, columns=['Incomes electricity'], dtype='float') + super().__init__(building, configuration) + self._yearly_operational_incomes = pd.DataFrame(index=self._rng, columns=['Incomes electricity'], dtype='float') def calculate(self) -> pd.DataFrame: """