From 2ef3be7fe354c41fab71f2268e2519fc7d07f4e7 Mon Sep 17 00:00:00 2001 From: s_ranjbar Date: Tue, 25 Jun 2024 19:57:22 -0400 Subject: [PATCH] fix: cost workflow finalized --- main.py | 68 +++++++++++++ scripts/costs/capital_costs.py | 122 +++++++++++++++++------ scripts/costs/constants.py | 4 +- scripts/costs/cost.py | 10 +- scripts/costs/total_maintenance_costs.py | 17 ++-- scripts/random_assignation.py | 6 +- 6 files changed, 178 insertions(+), 49 deletions(-) diff --git a/main.py b/main.py index e69de29b..a0383a6d 100644 --- a/main.py +++ b/main.py @@ -0,0 +1,68 @@ +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 import random_assignation +from hub.imports.energy_systems_factory import EnergySystemsFactory +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, SYSTEM_RETROFIT +import hub.helpers.constants as cte +from scripts.solar_angles import CitySolarAngles +from scripts.pv_sizing_and_simulation import PVSizingSimulation +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() +ExportsFactory('sra', city, output_path).export() +sra_path = (output_path / f'{city.name}_sra.xml').resolve() +subprocess.run(['sra', str(sra_path)]) +ResultFactory('sra', city, output_path).enrich() +solar_angles = CitySolarAngles(city.name, + city.latitude, + city.longitude, + tilt_angle=45, + surface_azimuth_angle=180).calculate +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() + if 'PV' in building.energy_systems_archetype_name: + ghi = [x / cte.WATTS_HOUR_TO_JULES for x in building.roofs[0].global_irradiance[cte.HOUR]] + pv_sizing_simulation = PVSizingSimulation(building, + solar_angles, + tilt_angle=45, + module_height=1, + module_width=2, + ghi=ghi) + pv_sizing_simulation.pv_output() +for building in city.buildings: + costs = Cost(building=building, retrofit_scenario=SYSTEM_RETROFIT).life_cycle + costs.to_csv(output_path / f'{building.name}_lcc.csv') + (costs.loc['global_operational_costs', f'Scenario {SYSTEM_RETROFIT}']. + to_csv(output_path / f'{building.name}_op.csv')) + costs.loc['global_capital_costs', f'Scenario {SYSTEM_RETROFIT}'].to_csv( + output_path / f'{building.name}_cc.csv') + costs.loc['global_maintenance_costs', f'Scenario {SYSTEM_RETROFIT}'].to_csv( + output_path / f'{building.name}_m.csv') \ No newline at end of file diff --git a/scripts/costs/capital_costs.py b/scripts/costs/capital_costs.py index c87f3eba..832aeb7d 100644 --- a/scripts/costs/capital_costs.py +++ b/scripts/costs/capital_costs.py @@ -13,7 +13,7 @@ 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, CURRENT_STATUS, PV) + SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS, PV, SYSTEM_RETROFIT) from scripts.costs.cost_base import CostBase @@ -32,10 +32,12 @@ class CapitalCosts(CostBase): 'B3010_opaque_roof', 'B1010_superstructure', 'D2010_photovoltaic_system', - 'D3020_heat_and_cooling_generating_systems', - 'D3040_distribution_systems', - 'D3050_other_hvac_ahu', - 'D3060_storage_systems', + 'D3020_simultaneous_heat_and_cooling_generating_systems', + 'D3030_heating_systems', + 'D3040_cooling_systems', + 'D3050_distribution_systems', + 'D3060_other_hvac_ahu', + 'D3070_storage_systems', 'D40_dhw', ], dtype='float' @@ -45,10 +47,12 @@ class CapitalCosts(CostBase): self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = 0 self._yearly_capital_costs.loc[0, 'B1010_superstructure'] = 0 self._yearly_capital_costs.loc[0, 'D2010_photovoltaic_system'] = 0 - self._yearly_capital_costs.loc[0, 'D3020_heat_and_cooling_generating_systems'] = 0 - self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = 0 - self._yearly_capital_costs.loc[0, 'D3080_other_hvac_ahu'] = 0 - self._yearly_capital_costs.loc[0, 'D3060_storage_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3020_simultaneous_heat_and_cooling_generating_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3030_heating_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3040_cooling_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3050_distribution_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3060_other_hvac_ahu'] = 0 + self._yearly_capital_costs.loc[0, 'D3070_storage_systems'] = 0 self._yearly_capital_costs.loc[0, 'D40_dhw'] = 0 self._yearly_capital_incomes = pd.DataFrame( @@ -107,7 +111,7 @@ 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] - if self._configuration.retrofit_scenario not in (SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS, PV): + if self._configuration.retrofit_scenario not in (SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS, PV, SYSTEM_RETROFIT): self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = capital_cost_opaque * self._own_capital self._yearly_capital_costs.loc[0, 'B2020_transparent'] = capital_cost_transparent * self._own_capital self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = capital_cost_roof * self._own_capital @@ -151,14 +155,20 @@ class CapitalCosts(CostBase): chapter = self._capital_costs_chapter.chapter('D_services') system_components, component_categories, component_sizes = self.system_components() capital_cost_heating_and_cooling_equipment = 0 + capital_cost_heating_equipment = 0 + capital_cost_cooling_equipment = 0 capital_cost_domestic_hot_water_equipment = 0 capital_cost_energy_storage_equipment = 0 capital_cost_distribution_equipment = 0 capital_cost_lighting = 0 capital_cost_pv = self._surface_pv * chapter.item('D2010_photovoltaic_system').initial_investment[0] for (i, component) in enumerate(system_components): - if component_categories[i] == 'generation': + if component_categories[i] == 'multi_generation': capital_cost_heating_and_cooling_equipment += chapter.item(component).initial_investment[0] * component_sizes[i] + elif component_categories[i] == 'heating': + capital_cost_heating_equipment += chapter.item(component).initial_investment[0] * component_sizes[i] + elif component_categories[i] == 'cooling': + capital_cost_cooling_equipment += chapter.item(component).initial_investment[0] * component_sizes[i] elif component_categories[i] == 'dhw': capital_cost_domestic_hot_water_equipment += chapter.item(component).initial_investment[0] * \ component_sizes[i] @@ -170,19 +180,25 @@ class CapitalCosts(CostBase): 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'] = ( + if (self._configuration.retrofit_scenario in + (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT)): + self._yearly_capital_costs.loc[0, 'D3020_simultaneous_heat_and_cooling_generating_systems'] = ( capital_cost_heating_and_cooling_equipment * self._own_capital) - self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = ( + self._yearly_capital_costs.loc[0, 'D3030_heating_systems'] = ( + capital_cost_heating_equipment * self._own_capital) + self._yearly_capital_costs.loc[0, 'D3040_cooling_systems'] = ( + capital_cost_cooling_equipment * self._own_capital) + self._yearly_capital_costs.loc[0, 'D3050_distribution_systems'] = ( capital_cost_distribution_equipment * self._own_capital) - self._yearly_capital_costs.loc[0, 'D3060_storage_systems'] = ( + self._yearly_capital_costs.loc[0, 'D3070_storage_systems'] = ( capital_cost_energy_storage_equipment * self._own_capital) self._yearly_capital_costs.loc[0, 'D40_dhw'] = ( capital_cost_domestic_hot_water_equipment * self._own_capital) capital_cost_hvac = (capital_cost_heating_and_cooling_equipment + capital_cost_distribution_equipment + capital_cost_energy_storage_equipment + capital_cost_domestic_hot_water_equipment) - return (capital_cost_pv, capital_cost_heating_and_cooling_equipment, capital_cost_distribution_equipment, - capital_cost_energy_storage_equipment, capital_cost_domestic_hot_water_equipment, capital_cost_lighting, capital_cost_hvac) + return (capital_cost_pv, capital_cost_heating_and_cooling_equipment, capital_cost_heating_equipment, + capital_cost_distribution_equipment, capital_cost_cooling_equipment, capital_cost_energy_storage_equipment, + capital_cost_domestic_hot_water_equipment, capital_cost_lighting, capital_cost_hvac) def yearly_energy_system_costs(self): chapter = self._capital_costs_chapter.chapter('D_services') @@ -202,49 +218,79 @@ class CapitalCosts(CostBase): system_investment_costs[0] * self._configuration.percentage_credit ) ) - self._yearly_capital_costs.loc[year, 'D3020_heat_and_cooling_generating_systems'] = ( + self._yearly_capital_costs.loc[year, 'D3020_simultaneous_heat_and_cooling_generating_systems'] = ( -npf.pmt( self._configuration.interest_rate, self._configuration.credit_years, system_investment_costs[1] * self._configuration.percentage_credit ) ) - self._yearly_capital_costs.loc[year, 'D3040_distribution_systems'] = ( + self._yearly_capital_costs.loc[year, 'D3030_heating_systems'] = ( -npf.pmt( self._configuration.interest_rate, self._configuration.credit_years, system_investment_costs[2] * self._configuration.percentage_credit ) ) - self._yearly_capital_costs.loc[year, 'D3060_storage_systems'] = ( + self._yearly_capital_costs.loc[year, 'D3040_cooling_systems'] = ( -npf.pmt( self._configuration.interest_rate, self._configuration.credit_years, system_investment_costs[3] * self._configuration.percentage_credit ) ) - self._yearly_capital_costs.loc[year, 'D40_dhw'] = ( + self._yearly_capital_costs.loc[year, 'D3050_distribution_systems'] = ( -npf.pmt( self._configuration.interest_rate, self._configuration.credit_years, system_investment_costs[4] * self._configuration.percentage_credit ) ) + self._yearly_capital_costs.loc[year, 'D3070_storage_systems'] = ( + -npf.pmt( + self._configuration.interest_rate, + self._configuration.credit_years, + system_investment_costs[5] * self._configuration.percentage_credit + ) + ) + self._yearly_capital_costs.loc[year, 'D40_dhw'] = ( + -npf.pmt( + self._configuration.interest_rate, + self._configuration.credit_years, + system_investment_costs[6] * self._configuration.percentage_credit + ) + ) if self._configuration.retrofit_scenario not in (SKIN_RETROFIT, PV): for (i, component) in enumerate(system_components): if (year % chapter.item(component).lifetime) == 0 and year != (self._configuration.number_of_years - 1): - if component_categories[i] == 'generation': - reposition_cost_heating_and_cooling_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase - self._yearly_capital_costs.loc[year, 'D3020_heat_and_cooling_generating_systems'] += reposition_cost_heating_and_cooling_equipment + if component_categories[i] == 'multi_generation': + reposition_cost_heating_and_cooling_equipment = (chapter.item(component).reposition[0] * + component_sizes[i] * costs_increase) + self._yearly_capital_costs.loc[year, 'D3020_simultaneous_heat_and_cooling_generating_systems'] += ( + reposition_cost_heating_and_cooling_equipment) + elif component_categories[i] == 'heating': + reposition_cost_heating_equipment = (chapter.item(component).reposition[0] * + component_sizes[i] * costs_increase) + self._yearly_capital_costs.loc[year, 'D3030_heating_systems'] += ( + reposition_cost_heating_equipment) + elif component_categories[i] == 'cooling': + reposition_cost_cooling_equipment = (chapter.item(component).reposition[0] * + component_sizes[i] * costs_increase) + self._yearly_capital_costs.loc[year, 'D3040_cooling_systems'] += ( + reposition_cost_cooling_equipment) elif component_categories[i] == 'dhw': - reposition_cost_domestic_hot_water_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase + reposition_cost_domestic_hot_water_equipment = ( + chapter.item(component).reposition[0] * component_sizes[i] * costs_increase) self._yearly_capital_costs.loc[year, 'D40_dhw'] += reposition_cost_domestic_hot_water_equipment elif component_categories[i] == 'distribution': - reposition_cost_distribution_equipment = chapter.item(component).reposition[0] * component_sizes[i] * costs_increase - self._yearly_capital_costs.loc[year, 'D3040_distribution_systems'] += reposition_cost_distribution_equipment + reposition_cost_distribution_equipment = ( + chapter.item(component).reposition[0] * component_sizes[i] * costs_increase) + self._yearly_capital_costs.loc[year, 'D3050_distribution_systems'] += ( + reposition_cost_distribution_equipment) else: - reposition_cost_energy_storage_equipment = chapter.item(component).initial_investment[0] * component_sizes[i] * costs_increase - self._yearly_capital_costs.loc[year, 'D3060_storage_systems'] += reposition_cost_energy_storage_equipment + reposition_cost_energy_storage_equipment = ( + chapter.item(component).initial_investment[0] * component_sizes[i] * costs_increase) + self._yearly_capital_costs.loc[year, 'D3070_storage_systems'] += reposition_cost_energy_storage_equipment if self._configuration.retrofit_scenario == CURRENT_STATUS and pv: if (year % chapter.item('D2010_photovoltaic_system').lifetime) == 0: self._yearly_capital_costs.loc[year, 'D2010_photovoltaic_system'] += ( @@ -280,8 +326,11 @@ class CapitalCosts(CostBase): system_components.append(self.boiler_type(generation_system)) else: system_components.append('D302010_template_heat') - elif cte.HEATING or cte.COOLING in demand_types: - component_categories.append('generation') + elif cte.HEATING in demand_types: + if cte.COOLING in demand_types and generation_system.fuel_type == cte.ELECTRICITY: + component_categories.append('multi_generation') + else: + component_categories.append('heating') sizes.append(installed_capacity) if generation_system.system_type == cte.HEAT_PUMP: item_type = self.heat_pump_type(generation_system) @@ -290,11 +339,18 @@ class CapitalCosts(CostBase): item_type = self.boiler_type(generation_system) system_components.append(item_type) else: - if cte.COOLING in demand_types and cte.HEATING not in demand_types: + if cooling_capacity > heating_capacity: system_components.append('D302090_template_cooling') else: system_components.append('D302010_template_heat') - + elif cte.COOLING in demand_types: + component_categories.append('cooling') + sizes.append(installed_capacity) + if generation_system.system_type == cte.HEAT_PUMP: + item_type = self.heat_pump_type(generation_system) + system_components.append(item_type) + else: + system_components.append('D302090_template_cooling') if generation_system.energy_storage_systems is not None: energy_storage_systems = generation_system.energy_storage_systems for storage_system in energy_storage_systems: diff --git a/scripts/costs/constants.py b/scripts/costs/constants.py index 18543adf..87372d3d 100644 --- a/scripts/costs/constants.py +++ b/scripts/costs/constants.py @@ -12,10 +12,12 @@ SKIN_RETROFIT = 1 SYSTEM_RETROFIT_AND_PV = 2 SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV = 3 PV = 4 +SYSTEM_RETROFIT = 5 RETROFITTING_SCENARIOS = [ CURRENT_STATUS, SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, - PV + PV, + SYSTEM_RETROFIT ] diff --git a/scripts/costs/cost.py b/scripts/costs/cost.py index 2ebd1ffc..91a13034 100644 --- a/scripts/costs/cost.py +++ b/scripts/costs/cost.py @@ -93,10 +93,12 @@ class Cost: global_capital_costs['B1010_superstructure'] ) df_capital_costs_systems = ( - global_capital_costs['D3020_heat_and_cooling_generating_systems'] + - global_capital_costs['D3040_distribution_systems'] + - global_capital_costs['D3050_other_hvac_ahu'] + - global_capital_costs['D3060_storage_systems'] + + global_capital_costs['D3020_simultaneous_heat_and_cooling_generating_systems'] + + global_capital_costs['D3030_heating_systems'] + + global_capital_costs['D3040_cooling_systems'] + + global_capital_costs['D3050_distribution_systems'] + + global_capital_costs['D3060_other_hvac_ahu'] + + global_capital_costs['D3070_storage_systems'] + global_capital_costs['D40_dhw'] + global_capital_costs['D2010_photovoltaic_system'] ) diff --git a/scripts/costs/total_maintenance_costs.py b/scripts/costs/total_maintenance_costs.py index 1e44f3d0..7a11b9b6 100644 --- a/scripts/costs/total_maintenance_costs.py +++ b/scripts/costs/total_maintenance_costs.py @@ -57,14 +57,15 @@ class TotalMaintenanceCosts(CostBase): 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 generation_system.fuel_type == cte.ELECTRICITY: + if generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.AIR: + cooling_equipments['air_source_heat_pump'] = generation_system.nominal_cooling_output / 1000 + elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.GROUND: + cooling_equipments['ground_source_heat_pump'] = generation_system.nominal_cooling_output / 1000 + elif generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.WATER: + cooling_equipments['water_source_heat_pump'] = generation_system.nominal_cooling_output / 1000 + else: + cooling_equipments['general_cooling_equipment'] = generation_system.nominal_cooling_output / 1000 if cte.HEATING in energy_system.demand_types: for generation_system in energy_system.generation_systems: if generation_system.system_type == cte.HEAT_PUMP and generation_system.source_medium == cte.AIR: diff --git a/scripts/random_assignation.py b/scripts/random_assignation.py index ac6eb454..7483cced 100644 --- a/scripts/random_assignation.py +++ b/scripts/random_assignation.py @@ -29,9 +29,9 @@ residential_systems_percentage = {'system 1 gas': 100, 'system 8 electricity': 0} residential_new_systems_percentage = {'PV+ASHP+GasBoiler+TES': 0, - 'PV+4Pipe+DHW': 0, - 'Central Heating+Unitary Cooling+Unitary DHW': 50, - 'Central Heating+Unitary Cooling+Unitary DHW+PV': 50, + 'PV+4Pipe+DHW': 100, + 'Central Heating+Unitary Cooling+Unitary DHW': 0, + 'Central Heating+Unitary Cooling+Unitary DHW+PV': 0, 'PV+ASHP+ElectricBoiler+TES': 0, 'PV+GSHP+GasBoiler+TES': 0, 'PV+GSHP+ElectricBoiler+TES': 0, -- 2.39.2