From 81ac7bc0c33beb76a5924d9104eca5481810d728 Mon Sep 17 00:00:00 2001 From: jgavalda Date: Mon, 10 Jul 2023 17:54:05 -0400 Subject: [PATCH] Ongoing developments for the course workshop, including graphs implementation --- costs/Individualplot.py | 95 ++++++++++++++++++++++++++++++++ costs/__main__.py | 110 +++++++++++++++++++++++++------------- costs/life_cycle_costs.py | 18 +++---- costs/printing_results.py | 4 +- 4 files changed, 177 insertions(+), 50 deletions(-) create mode 100644 costs/Individualplot.py diff --git a/costs/Individualplot.py b/costs/Individualplot.py new file mode 100644 index 0000000..8b2f542 --- /dev/null +++ b/costs/Individualplot.py @@ -0,0 +1,95 @@ +import plotly.graph_objects as go +import matplotlib.pyplot as plt +import plotly.express as px + +def individualplot(output_yearly_graph,retrofitting_scenario) : + # Sample data + categories = output_yearly_graph.index + bar_data_1 = output_yearly_graph['Capital'] + bar_data_2 = -output_yearly_graph['Capital incomes'] + bar_data_3 = output_yearly_graph['End of life'] + bar_data_4 = output_yearly_graph['Operational total'] + bar_data_5 = -output_yearly_graph['Operational income'] + line_data = output_yearly_graph['Common addition'] + + # Create bar trace 1 + bar_trace_1 = go.Bar( + x=categories, + y=bar_data_1, + name='Capital', + yaxis='y1' + ) + + # Create bar trace 2 + bar_trace_2 = go.Bar( + x=categories, + y=bar_data_2, + name='Capital incomes', + yaxis='y1', + marker=dict(color='red') + ) + # Create bar trace 2 + bar_trace_3 = go.Bar( + x=categories, + y=bar_data_3, + name='End of life', + yaxis='y1' + ) + # Create bar trace 2 + bar_trace_4 = go.Bar( + x=categories, + y=bar_data_4, + name='Operational total', + yaxis='y1' + ) + # Create bar trace 2 + bar_trace_5 = go.Bar( + x=categories, + y=bar_data_5, + name='Operational income', + yaxis='y1', + marker=dict(color='red') + ) + + # Create line trace + line_trace = go.Scatter( + x=categories, + y=line_data, + mode='lines', + name='Common addition', + yaxis='y2' + ) + + # Create layout + layout = go.Layout( + title='Stacked Bar Chart with Negative Values and Line', + xaxis=dict(title='Categories'), + yaxis=dict(title='Bar Values', side='left', showgrid=False), + yaxis2=dict(title='Line Values', side='right', overlaying='y', showgrid=False), + barmode='stack' + ) + + # Create figure + fig = go.Figure(data=[bar_trace_1, bar_trace_2, bar_trace_3, bar_trace_4, bar_trace_5, line_trace], layout=layout) + + fig.show() + + fig, ax1 = plt.subplots() + bottom = [0]*len(bar_data_1) + ax1.bar(categories, bar_data_1, label='Capital costs', color='green') + ax1.bar(categories, bar_data_3, label='End of life costs', color='grey') + ax1.bar(categories, bar_data_4, label='Operational costs', color='brown') + ax1.bar(categories, bar_data_2, label='Capital incomes', color='red', bottom=bottom) + ax1.bar(categories, bar_data_5, label='Operational incomes', color='orange', bottom=bar_data_2) + + ax1.set_ylabel('Values') + ax1.set_title('Stacked Bar Chart with Line') + ax1.legend() + + # Create the line chart on a secondary y-axis + ax2 = ax1.twinx() + ax2.plot(categories, line_data, marker='o', linestyle='-', color='blue', label='Line') + ax2.set_ylabel('Line Values') + ax2.legend() + + plt.show() \ No newline at end of file diff --git a/costs/__main__.py b/costs/__main__.py index 8463a8a..be370bf 100644 --- a/costs/__main__.py +++ b/costs/__main__.py @@ -19,6 +19,7 @@ from hub.imports.weather_factory import WeatherFactory from monthly_energy_balance_engine import MonthlyEnergyBalanceEngine from sra_engine import SraEngine from printing_results import * +from Individualplot import * from hub.helpers import constants as cte from life_cycle_costs import LifeCycleCosts @@ -59,45 +60,56 @@ out_path = (Path(__file__).parent.parent / 'out_files') tmp_folder = (Path(__file__).parent / 'tmp') print('[simulation start]') -city = GeometryFactory('geojson', - path=file_path, - height_field='citygml_me', - year_of_construction_field='ANNEE_CONS', - function_field='CODE_UTILI', - function_to_hub=Dictionaries().montreal_function_to_hub_function).city -city.climate_reference_city = climate_reference_city -city.climate_file = (tmp_folder / f'{climate_reference_city}.cli').resolve() +city_original = GeometryFactory('geojson', + path=file_path, + height_field='citygml_me', + year_of_construction_field='ANNEE_CONS', + function_field='CODE_UTILI', + function_to_hub=Dictionaries().montreal_function_to_hub_function).city +city_original.climate_reference_city = climate_reference_city +city_original.climate_file = (tmp_folder / f'{climate_reference_city}.cli').resolve() print(f'city created from {file_path}') -WeatherFactory(weather_format, city).enrich() +WeatherFactory(weather_format, city_original).enrich() print('enrich weather... done') -ConstructionFactory(construction_format, city).enrich() +ConstructionFactory(construction_format, city_original).enrich() print('enrich constructions... done') -UsageFactory(usage_format, city).enrich() +UsageFactory(usage_format, city_original).enrich() print('enrich usage... done') -for building in city.buildings: - building.energy_systems_archetype_name = 'system 1 gas pv' -EnergySystemsFactory(energy_systems_format, city).enrich() +for building in city_original.buildings: + building.energy_systems_archetype_name = 'system 1 gas' +EnergySystemsFactory(energy_systems_format, city_original).enrich() print('enrich systems... done') - print('exporting:') -sra_file = (tmp_folder / f'{city.name}_sra.xml').resolve() -SraEngine(city, sra_file, tmp_folder) +sra_file = (tmp_folder / f'{city_original.name}_sra.xml').resolve() +SraEngine(city_original, sra_file, tmp_folder) print(' sra processed...') catalog = CostCatalogFactory('montreal_custom').catalog - +investmentcosts = pd.DataFrame([]) +print(f'retrofitting 0') for retrofitting_scenario in RETROFITTING_SCENARIOS: + city = city_original.copy + total_floor_area = 0 - if retrofitting_scenario in (SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV): + if retrofitting_scenario == SYSTEM_RETROFIT_AND_PV: + print(f'retrofitting 1') + for building in city.buildings: + building.energy_systems_archetype_name = 'system 7 electricity pv' + EnergySystemsFactory(ENERGY_SYSTEM_FORMAT, city).enrich() + + if retrofitting_scenario == SKIN_RETROFIT: for building in city.buildings: building.year_of_construction = RETROFITTING_YEAR_CONSTRUCTION + building.energy_systems_archetype_name = 'system 1 gas' ConstructionFactory(CONSTRUCTION_FORMAT, city).enrich() - print('enrich retrofitted constructions... done') + print(f'retrofitting 2') - if retrofitting_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV): + if retrofitting_scenario == SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV: for building in city.buildings: - building.energy_systems_archetype_name = 'system 6 electricity pv' + building.year_of_construction = RETROFITTING_YEAR_CONSTRUCTION + building.energy_systems_archetype_name = 'system 7 electricity pv' + ConstructionFactory(CONSTRUCTION_FORMAT, city).enrich() EnergySystemsFactory(ENERGY_SYSTEM_FORMAT, city).enrich() - print('enrich systems... done') + print(f'retrofitting 3') MonthlyEnergyBalanceEngine(city, tmp_folder) print(' insel processed...') @@ -108,34 +120,54 @@ for retrofitting_scenario in RETROFITTING_SCENARIOS: energy_system.generation_system.heat_power = building.heating_peak_load[cte.YEAR][0] if cte.COOLING in energy_system.demand_types: energy_system.generation_system.cooling_power = building.cooling_peak_load[cte.YEAR][0] - print(f' heating consumption {building.heating_consumption[cte.YEAR][0]}') - print('importing results:') - results = Results(city, out_path) - results.print() - print('results printed...') - - print('[simulation end]') print(f'beginning costing scenario {retrofitting_scenario} systems... done') for building in city.buildings: - total_floor_area = 0 function = Dictionaries().hub_function_to_montreal_custom_costs_function[building.function] archetype = _search_archetype(catalog, function) - print('lcc for first building started') + print(building.heating_consumption[cte.YEAR][0]) if "gas" in building.energy_systems_archetype_name: FUEL_TYPE = 1 else: FUEL_TYPE = 0 - lcc = LifeCycleCosts(building, archetype, NUMBER_OF_YEARS, CONSUMER_PRICE_INDEX, ELECTRICITY_PEAK_INDEX, ELECTRICITY_PRICE_INDEX, GAS_PRICE_INDEX, DISCOUNT_RATE, retrofitting_scenario, FUEL_TYPE) global_capital_costs, global_capital_incomes = lcc.calculate_capital_costs() global_end_of_life_costs = lcc.calculate_end_of_life_costs() - global_operational_costs = lcc.calculate_total_operational_costs + global_operational_costs = lcc.calculate_total_operational_costs() global_maintenance_costs = lcc.calculate_total_maintenance_costs() - global_operational_incomes = lcc.calculate_total_operational_incomes(retrofitting_scenario) + global_operational_incomes = lcc.calculate_total_operational_incomes() + + total_plot_costs = global_capital_costs - global_capital_incomes + global_end_of_life_costs + \ + global_operational_costs + global_maintenance_costs - global_operational_incomes + + capital_total = global_capital_costs.sum(axis=1) + capital_income_total = global_capital_incomes.sum(axis=1) + end_of_life_total = global_end_of_life_costs.sum(axis=1) + operational_total = global_operational_costs.sum(axis=1) + maintenance_total = global_maintenance_costs.sum(axis=1) + operational_income_total = global_operational_incomes.sum(axis=1) + + lineatotal = capital_total - capital_income_total + end_of_life_total + operational_total + maintenance_total - \ + operational_income_total + + lineatotal = lineatotal.cumsum() + + print(lineatotal) + + + output_yearly_graph = pd.DataFrame({'Capital': capital_total, + 'Capital incomes' : capital_income_total, + 'End of life' : end_of_life_total, + 'Operational total': operational_total, + 'Maintenance total': maintenance_total, + 'Operational income': operational_income_total,'Common addition': lineatotal}) + + individualplot(output_yearly_graph, retrofitting_scenario) + full_path_output = Path(out_path / f'output {retrofitting_scenario} {building.name}.xlsx').resolve() + with pd.ExcelWriter(full_path_output) as writer: global_capital_costs.to_excel(writer, sheet_name='global_capital_costs') global_end_of_life_costs.to_excel(writer, sheet_name='global_end_of_life_costs') @@ -144,7 +176,6 @@ for retrofitting_scenario in RETROFITTING_SCENARIOS: global_operational_incomes.to_excel(writer, sheet_name='global_operational_incomes') global_capital_incomes.to_excel(writer, sheet_name='global_capital_incomes') - investmentcosts = pd.DataFrame([]) print('RETROFITTING SCENARIO', retrofitting_scenario) if retrofitting_scenario == 0: investmentcosts = [global_capital_costs['B2010_opaque_walls'][0], @@ -171,6 +202,8 @@ for retrofitting_scenario in RETROFITTING_SCENARIOS: investmentcosts.index = ['Opaque walls', 'Transparent walls', 'Opaque roof', 'Superstructure', 'Heat generation systems', 'Other HVAC AHU', 'Lighting and branch wiring', 'PV systems'] + investmentcosts = investmentcosts.applymap(lambda x: round(x, 2)) + df_capital_costs_skin = ( global_capital_costs['B2010_opaque_walls'] + global_capital_costs['B2020_transparent'] + global_capital_costs['B3010_opaque_roof'] + global_capital_costs['B10_superstructure'] @@ -239,9 +272,10 @@ for retrofitting_scenario in RETROFITTING_SCENARIOS: 'operational_incomes', 'capital_incomes'] - print(f'Scenario {retrofitting_scenario} {life_cycle_costs}') + life_cycle_results = life_cycle_results.applymap(lambda x: round(x, 2)) + life_cycle_costs = round(life_cycle_costs, 2) -# printing_results(investmentcosts, life_cycle_results, total_floor_area) +printing_results(investmentcosts, life_cycle_results, total_floor_area) diff --git a/costs/life_cycle_costs.py b/costs/life_cycle_costs.py index 470b242..cd93200 100644 --- a/costs/life_cycle_costs.py +++ b/costs/life_cycle_costs.py @@ -249,7 +249,7 @@ class LifeCycleCosts: def calculate_total_floor_area(self): total_floor_area = self._total_floor_area return total_floor_area - @property + def calculate_total_operational_costs(self): """ Calculate total operational costs @@ -270,8 +270,9 @@ class LifeCycleCosts: (building.heating_consumption[cte.YEAR][0] + building.domestic_hot_water_consumption[cte.YEAR][0]) / 1000 * archetype.operational_cost.fuels[1].variable[0] ) - if self._fuel_type == 0: - electricity_heating = building.heating_consumption[cte.YEAR][0] / 1000 + else: + # todo: change hardcoded 3 to include COP heating system + electricity_heating = building.heating_consumption[cte.YEAR][0] /(1000) domestic_hot_water_electricity = building.domestic_hot_water_consumption[cte.YEAR][0] / 1000 electricity_cooling = building.cooling_consumption[cte.YEAR][0] / 1000 @@ -282,14 +283,12 @@ class LifeCycleCosts: electricity_heating + electricity_cooling + electricity_lighting + domestic_hot_water_electricity + electricity_plug_loads + electricity_distribution ) - print(f'electricity consumption {total_electricity_consumption}') # todo: change when peak electricity demand is coded. Careful with factor residential peak_electricity_demand = 0.1*total_floor_area # self._peak_electricity_demand - variable_electricity_cost_year_0 = total_electricity_consumption * archetype.operational_cost.fuels[0].variable[0] peak_electricity_cost_year_0 = peak_electricity_demand * archetype.operational_cost.fuels[0].fixed_power * 12 monthly_electricity_cost_year_0 = archetype.operational_cost.fuels[0].fixed_monthly * 12 * factor_residential - + variable_electricity_cost_year_0 = total_electricity_consumption * archetype.operational_cost.fuels[0].variable[0] for year in range(1, self._number_of_years + 1): price_increase_electricity = math.pow(1 + self._electricity_price_index, year) price_increase_peak_electricity = math.pow(1 + self._electricity_peak_index, year) @@ -315,7 +314,7 @@ class LifeCycleCosts: return self._yearly_operational_costs - def calculate_total_operational_incomes(self, retrofitting_scenario): + def calculate_total_operational_incomes(self): """ Calculate total operational incomes :return: pd.DataFrame @@ -324,10 +323,7 @@ class LifeCycleCosts: if cte.YEAR not in building.onsite_electrical_production: onsite_electricity_production = 0 else: - if retrofitting_scenario == 0 or retrofitting_scenario == 1: - onsite_electricity_production = 0 - else: - onsite_electricity_production = building.onsite_electrical_production[cte.YEAR][0]/1000 + onsite_electricity_production = building.onsite_electrical_production[cte.YEAR][0]/1000 for year in range(1, self._number_of_years + 1): price_increase_electricity = math.pow(1 + self._electricity_price_index, year) diff --git a/costs/printing_results.py b/costs/printing_results.py index e7e938e..609a34b 100644 --- a/costs/printing_results.py +++ b/costs/printing_results.py @@ -55,4 +55,6 @@ def printing_results(investmentcosts, life_cycle_results,total_floor_area): fig = px.bar(df_swapped, title='Life Cycle Costs for buildings') fig.show() # Display the chart - plt.show() \ No newline at end of file + plt.show() + +