Compare commits
19 Commits
main_branc
...
simulation
Author | SHA1 | Date | |
---|---|---|---|
dee24f7cd7 | |||
c412af99c1 | |||
a32b83fc49 | |||
aca2a22dc1 | |||
3534a71040 | |||
55a15117f7 | |||
efe8f9f753 | |||
46d3c39ac9 | |||
d40965eb6c | |||
f8fa5a4ed3 | |||
d8c8eec26c | |||
a313dd8624 | |||
905fc3342b | |||
bdb13c7faf | |||
7590af1eac | |||
bb9454339f | |||
5d04d12404 | |||
e38ac5b3f6 | |||
4173b868f3 |
27
.gitignore
vendored
27
.gitignore
vendored
|
@ -1,13 +1,14 @@
|
|||
.idea
|
||||
*.idf
|
||||
*.bnd
|
||||
*.eio
|
||||
*.end
|
||||
*.err
|
||||
*.eso
|
||||
*.expidf
|
||||
*.mtr
|
||||
*.rvaudit
|
||||
*.shd
|
||||
*.csv
|
||||
*.htm
|
||||
!.gitignore
|
||||
**/venv/
|
||||
.idea/
|
||||
/development_tests/
|
||||
/data/energy_systems/heat_pumps/*.csv
|
||||
/data/energy_systems/heat_pumps/*.insel
|
||||
.DS_Store
|
||||
**/.env
|
||||
**/hub/logs/
|
||||
**/__pycache__/
|
||||
**/.idea/
|
||||
cerc_hub.egg-info
|
||||
**/out_files/
|
||||
/input_files/output_buildings.geojson
|
66
MEB_test.py
Normal file
66
MEB_test.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
from geojson_creator import process_geojson
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||
from hub.helpers.dictionaries import Dictionaries
|
||||
from hub.imports.construction_factory import ConstructionFactory
|
||||
from hub.imports.geometry_factory import GeometryFactory
|
||||
from hub.imports.weather_factory import WeatherFactory
|
||||
from hub.imports.results_factory import ResultFactory
|
||||
from hub.imports.usage_factory import UsageFactory
|
||||
from hub.exports.exports_factory import ExportsFactory
|
||||
from scripts.ep_workflow import energy_plus_workflow
|
||||
import matplotlib.pyplot as plt
|
||||
import random
|
||||
import matplotlib.colors as mcolors
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
# Process geojson
|
||||
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0001)
|
||||
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October',
|
||||
'November', 'December']
|
||||
out_path = (Path(__file__).parent / 'out_files')
|
||||
file_path = (Path(__file__).parent.parent / 'input_files' / f'{geojson_file}')
|
||||
print('[simulation start]')
|
||||
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
|
||||
print(f'city created from {file_path}')
|
||||
|
||||
# Enrich city data
|
||||
ConstructionFactory('nrcan', city).enrich()
|
||||
UsageFactory('nrcan', city).enrich()
|
||||
WeatherFactory('epw', city).enrich()
|
||||
ExportsFactory('sra', city, out_path).export()
|
||||
sra_path = (out_path / f'{city.name}_sra.xml').resolve()
|
||||
subprocess.run(['sra', str(sra_path)])
|
||||
ResultFactory('sra', city, out_path).enrich()
|
||||
EnergyBuildingsExportsFactory('insel_monthly_energy_balance', city, out_path).export_debug()
|
||||
|
||||
# Create grid of plots
|
||||
fig, axs = plt.subplots(3, 2, figsize=(12, 12))
|
||||
|
||||
# Plot monthly heating demands from Monthly Energy Balance
|
||||
for i, building in enumerate(city.buildings):
|
||||
monthly_heating_demand = [peak / 3.6e6 for peak in building.heating_peak_load[cte.MONTH]]
|
||||
ax = axs[i, 0] # Select subplot in the first column
|
||||
ax.plot(months, monthly_heating_demand)
|
||||
ax.set_title(f'Monthly Heating Demand (Building {i+1})')
|
||||
ax.set_xlabel('Month')
|
||||
ax.set_ylabel('Heating Demand')
|
||||
|
||||
# Plot monthly heating demands from EnergyPlus
|
||||
energy_plus_workflow(city)
|
||||
for i, ep in enumerate(city.buildings):
|
||||
monthly_heating_demand = [peak / 3.6e6 for peak in ep.heating_peak_load[cte.MONTH]]
|
||||
ax = axs[i, 1] # Select subplot in the second column
|
||||
ax.plot(months, monthly_heating_demand)
|
||||
ax.set_title(f'Monthly Heating Demand (Building {i+1})')
|
||||
ax.set_xlabel('Month')
|
||||
ax.set_ylabel('Heating Demand')
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
BIN
__pycache__/geojson_creator.cpython-39.pyc
Normal file
BIN
__pycache__/geojson_creator.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/report_creation.cpython-39.pyc
Normal file
BIN
__pycache__/report_creation.cpython-39.pyc
Normal file
Binary file not shown.
BIN
__pycache__/system_simulation.cpython-39.pyc
Normal file
BIN
__pycache__/system_simulation.cpython-39.pyc
Normal file
Binary file not shown.
340
energy_system_analysis_report.py
Normal file
340
energy_system_analysis_report.py
Normal file
|
@ -0,0 +1,340 @@
|
|||
import os
|
||||
import hub.helpers.constants as cte
|
||||
import matplotlib.pyplot as plt
|
||||
import random
|
||||
import matplotlib.colors as mcolors
|
||||
from matplotlib import cm
|
||||
from report_creation import LatexReport
|
||||
|
||||
class EnergySystemAnalysisReport:
|
||||
def __init__(self, city, output_path):
|
||||
self.city = city
|
||||
self.output_path = output_path
|
||||
self.content = []
|
||||
self.report = LatexReport('energy_system_analysis_report.tex')
|
||||
|
||||
def building_energy_info(self):
|
||||
|
||||
table_data = [
|
||||
["Building Name", "Year of Construction", "function", "Yearly Heating Demand (MWh)",
|
||||
"Yearly Cooling Demand (MWh)", "Yearly DHW Demand (MWh)", "Yearly Electricity Demand (MWh)"]
|
||||
]
|
||||
intensity_table_data = [["Building Name", "Total Floor Area m2", "Heating Demand Intensity kWh/m2",
|
||||
"Cooling Demand Intensity kWh/m2", "Electricity Intensity kWh/m2"]]
|
||||
|
||||
for building in self.city.buildings:
|
||||
total_floor_area = 0
|
||||
for zone in building.thermal_zones_from_internal_zones:
|
||||
total_floor_area += zone.total_floor_area
|
||||
building_data = [
|
||||
building.name,
|
||||
str(building.year_of_construction),
|
||||
building.function,
|
||||
str(format(building.heating_demand[cte.YEAR][0] / 1e6, '.2f')),
|
||||
str(format(building.cooling_demand[cte.YEAR][0] / 1e6, '.2f')),
|
||||
str(format(building.domestic_hot_water_heat_demand[cte.YEAR][0] / 1e6, '.2f')),
|
||||
str(format((building.lighting_electrical_demand[cte.YEAR][0] + building.appliances_electrical_demand[cte.YEAR][0]) / 1e6, '.2f')),
|
||||
]
|
||||
intensity_data = [
|
||||
building.name,
|
||||
str(format(total_floor_area, '.2f')),
|
||||
str(format(building.heating_demand[cte.YEAR][0] / (1e3 * total_floor_area), '.2f')),
|
||||
str(format(building.cooling_demand[cte.YEAR][0] / (1e3 * total_floor_area), '.2f')),
|
||||
str(format(
|
||||
(building.lighting_electrical_demand[cte.YEAR][0] + building.appliances_electrical_demand[cte.YEAR][0]) /
|
||||
(1e3 * total_floor_area), '.2f'))
|
||||
]
|
||||
table_data.append(building_data)
|
||||
intensity_table_data.append(intensity_data)
|
||||
|
||||
self.report.add_table(table_data, caption='City Buildings Energy Demands')
|
||||
self.report.add_table(intensity_table_data, caption='Energy Intensity Information')
|
||||
|
||||
def base_case_charts(self):
|
||||
save_directory = self.output_path
|
||||
|
||||
def autolabel(bars, ax):
|
||||
for bar in bars:
|
||||
height = bar.get_height()
|
||||
ax.annotate('{:.1f}'.format(height),
|
||||
xy=(bar.get_x() + bar.get_width() / 2, height),
|
||||
xytext=(0, 3), # 3 points vertical offset
|
||||
textcoords="offset points",
|
||||
ha='center', va='bottom')
|
||||
|
||||
def create_hvac_demand_chart(building_names, yearly_heating_demand, yearly_cooling_demand):
|
||||
fig, ax = plt.subplots()
|
||||
bar_width = 0.35
|
||||
index = range(len(building_names))
|
||||
|
||||
bars1 = ax.bar(index, yearly_heating_demand, bar_width, label='Yearly Heating Demand (MWh)')
|
||||
bars2 = ax.bar([i + bar_width for i in index], yearly_cooling_demand, bar_width,
|
||||
label='Yearly Cooling Demand (MWh)')
|
||||
|
||||
ax.set_xlabel('Building Name')
|
||||
ax.set_ylabel('Energy Demand (MWh)')
|
||||
ax.set_title('Yearly HVAC Demands')
|
||||
ax.set_xticks([i + bar_width / 2 for i in index])
|
||||
ax.set_xticklabels(building_names, rotation=45, ha='right')
|
||||
ax.legend()
|
||||
autolabel(bars1, ax)
|
||||
autolabel(bars2, ax)
|
||||
fig.tight_layout()
|
||||
plt.savefig(save_directory / 'hvac_demand_chart.jpg')
|
||||
plt.close()
|
||||
|
||||
def create_bar_chart(title, ylabel, data, filename, bar_color=None):
|
||||
fig, ax = plt.subplots()
|
||||
bar_width = 0.35
|
||||
index = range(len(building_names))
|
||||
|
||||
if bar_color is None:
|
||||
# Generate a random color
|
||||
bar_color = random.choice(list(mcolors.CSS4_COLORS.values()))
|
||||
|
||||
bars = ax.bar(index, data, bar_width, label=ylabel, color=bar_color)
|
||||
|
||||
ax.set_xlabel('Building Name')
|
||||
ax.set_ylabel('Energy Demand (MWh)')
|
||||
ax.set_title(title)
|
||||
ax.set_xticks([i + bar_width / 2 for i in index])
|
||||
ax.set_xticklabels(building_names, rotation=45, ha='right')
|
||||
ax.legend()
|
||||
autolabel(bars, ax)
|
||||
fig.tight_layout()
|
||||
plt.savefig(save_directory / filename)
|
||||
plt.close()
|
||||
|
||||
building_names = [building.name for building in self.city.buildings]
|
||||
yearly_heating_demand = [building.heating_demand[cte.YEAR][0] / 1e6 for building in self.city.buildings]
|
||||
yearly_cooling_demand = [building.cooling_demand[cte.YEAR][0] / 1e6 for building in self.city.buildings]
|
||||
yearly_dhw_demand = [building.domestic_hot_water_heat_demand[cte.YEAR][0] / 1e6 for building in
|
||||
self.city.buildings]
|
||||
yearly_electricity_demand = [(building.lighting_electrical_demand[cte.YEAR][0] +
|
||||
building.appliances_electrical_demand[cte.YEAR][0]) / 1e6 for building in
|
||||
self.city.buildings]
|
||||
|
||||
create_hvac_demand_chart(building_names, yearly_heating_demand, yearly_cooling_demand)
|
||||
create_bar_chart('Yearly DHW Demands', 'Energy Demand (MWh)', yearly_dhw_demand, 'dhw_demand_chart.jpg', )
|
||||
create_bar_chart('Yearly Electricity Demands', 'Energy Demand (MWh)', yearly_electricity_demand,
|
||||
'electricity_demand_chart.jpg')
|
||||
|
||||
def maximum_monthly_hvac_chart(self):
|
||||
save_directory = self.output_path
|
||||
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October',
|
||||
'November', 'December']
|
||||
for building in self.city.buildings:
|
||||
maximum_monthly_heating_load = []
|
||||
maximum_monthly_cooling_load = []
|
||||
fig, axs = plt.subplots(1, 2, figsize=(12, 6)) # Create a figure with 2 subplots side by side
|
||||
for demand in building.heating_peak_load[cte.MONTH]:
|
||||
maximum_monthly_heating_load.append(demand / 3.6e6)
|
||||
for demand in building.cooling_peak_load[cte.MONTH]:
|
||||
maximum_monthly_cooling_load.append(demand / 3.6e6)
|
||||
|
||||
# Plot maximum monthly heating load
|
||||
axs[0].bar(months, maximum_monthly_heating_load, color='red') # Plot on the first subplot
|
||||
axs[0].set_title('Maximum Monthly Heating Load')
|
||||
axs[0].set_xlabel('Month')
|
||||
axs[0].set_ylabel('Load (kW)')
|
||||
axs[0].tick_params(axis='x', rotation=45)
|
||||
|
||||
# Plot maximum monthly cooling load
|
||||
axs[1].bar(months, maximum_monthly_cooling_load, color='blue') # Plot on the second subplot
|
||||
axs[1].set_title('Maximum Monthly Cooling Load')
|
||||
axs[1].set_xlabel('Month')
|
||||
axs[1].set_ylabel('Load (kW)')
|
||||
axs[1].tick_params(axis='x', rotation=45)
|
||||
|
||||
plt.tight_layout() # Adjust layout to prevent overlapping
|
||||
plt.savefig(save_directory / f'{building.name}_monthly_maximum_hvac_loads.jpg')
|
||||
plt.close()
|
||||
|
||||
def load_duration_curves(self):
|
||||
save_directory = self.output_path
|
||||
for building in self.city.buildings:
|
||||
heating_demand = [demand / 1000 for demand in building.heating_demand[cte.HOUR]]
|
||||
cooling_demand = [demand / 1000 for demand in building.cooling_demand[cte.HOUR]]
|
||||
heating_demand_sorted = sorted(heating_demand, reverse=True)
|
||||
cooling_demand_sorted = sorted(cooling_demand, reverse=True)
|
||||
|
||||
plt.style.use('ggplot')
|
||||
|
||||
# Create figure and axis objects with 1 row and 2 columns
|
||||
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
|
||||
|
||||
# Plot sorted heating demand
|
||||
axs[0].plot(heating_demand_sorted, color='red', linewidth=2, label='Heating Demand')
|
||||
axs[0].set_xlabel('Hour', fontsize=14)
|
||||
axs[0].set_ylabel('Heating Demand', fontsize=14)
|
||||
axs[0].set_title('Heating Load Duration Curve', fontsize=16)
|
||||
axs[0].grid(True)
|
||||
axs[0].legend(loc='upper right', fontsize=12)
|
||||
|
||||
# Plot sorted cooling demand
|
||||
axs[1].plot(cooling_demand_sorted, color='blue', linewidth=2, label='Cooling Demand')
|
||||
axs[1].set_xlabel('Hour', fontsize=14)
|
||||
axs[1].set_ylabel('Cooling Demand', fontsize=14)
|
||||
axs[1].set_title('Cooling Load Duration Curve', fontsize=16)
|
||||
axs[1].grid(True)
|
||||
axs[1].legend(loc='upper right', fontsize=12)
|
||||
|
||||
# Adjust layout
|
||||
plt.tight_layout()
|
||||
|
||||
# Save the plot
|
||||
plt.savefig(save_directory / f'{building.name}_load_duration_curve.jpg')
|
||||
|
||||
# Close the plot to release memory
|
||||
plt.close()
|
||||
|
||||
def individual_building_info(self, building):
|
||||
table_data = [
|
||||
["Maximum Monthly HVAC Demands",
|
||||
f"\\includegraphics[width=1\\linewidth]{{{building.name}_monthly_maximum_hvac_loads.jpg}}"],
|
||||
["Load Duration Curve", f"\\includegraphics[width=1\\linewidth]{{{building.name}_load_duration_curve.jpg}}"],
|
||||
]
|
||||
|
||||
self.report.add_table(table_data, caption=f'{building.name} Information', first_column_width=1.5)
|
||||
|
||||
def building_existing_system_info(self, building):
|
||||
existing_archetype = building.energy_systems_archetype_name
|
||||
fuels = []
|
||||
system_schematic = "-"
|
||||
heating_system = "-"
|
||||
cooling_system = "-"
|
||||
dhw = "-"
|
||||
electricity = "Grid"
|
||||
hvac_ec = format((building.heating_consumption[cte.YEAR][0] + building.cooling_consumption[cte.YEAR][0])/1e6, '.2f')
|
||||
dhw_ec = format(building.domestic_hot_water_consumption[cte.YEAR][0]/1e6, '.2f')
|
||||
on_site_generation = "-"
|
||||
yearly_operational_cost = "-"
|
||||
life_cycle_cost = "-"
|
||||
for energy_system in building.energy_systems:
|
||||
if cte.HEATING and cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
|
||||
heating_system = energy_system.name
|
||||
dhw = energy_system.name
|
||||
elif cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
|
||||
dhw = energy_system.name
|
||||
elif cte.HEATING in energy_system.demand_types:
|
||||
heating_system = energy_system.name
|
||||
elif cte.COOLING in energy_system.demand_types:
|
||||
cooling_system = energy_system.name
|
||||
for generation_system in energy_system.generation_systems:
|
||||
fuels.append(generation_system.fuel_type)
|
||||
if generation_system.system_type == cte.PHOTOVOLTAIC:
|
||||
electricity = "Grid-tied PV"
|
||||
|
||||
energy_system_table_data = [
|
||||
["Detail", "Existing System", "Proposed System"],
|
||||
["Energy System Archetype", existing_archetype, "-"],
|
||||
["System Schematic", system_schematic, system_schematic],
|
||||
["Heating System", heating_system, "-"],
|
||||
["Cooling System", cooling_system, "-"],
|
||||
["DHW System", dhw, "-"],
|
||||
["Electricity", electricity, "-"],
|
||||
["Fuel(s)", str(fuels), "-"],
|
||||
["HVAC Energy Consumption (MWh)", hvac_ec, "-"],
|
||||
["DHW Energy Consumption (MWH)", dhw_ec, "-"],
|
||||
["Yearly Operational Cost (CAD)", yearly_operational_cost, "-"],
|
||||
["Life Cycle Cost (CAD)", life_cycle_cost, "-"]
|
||||
]
|
||||
self.report.add_table(energy_system_table_data, caption= f'Building {building.name} Energy System Characteristics')
|
||||
|
||||
def building_fuel_consumption_breakdown(self, building):
|
||||
save_directory = self.output_path
|
||||
# Initialize variables to store fuel consumption breakdown
|
||||
fuel_breakdown = {
|
||||
"Heating": {"Gas": 0, "Electricity": 0},
|
||||
"Domestic Hot Water": {"Gas": 0, "Electricity": 0},
|
||||
"Cooling": {"Electricity": 0},
|
||||
"Appliance": building.appliances_electrical_demand[cte.YEAR][0] / 1e6,
|
||||
"Lighting": building.lighting_electrical_demand[cte.YEAR][0] / 1e6
|
||||
}
|
||||
|
||||
# Iterate through energy systems of the building
|
||||
for energy_system in building.energy_systems:
|
||||
for demand_type in energy_system.demand_types:
|
||||
for generation_system in energy_system.generation_systems:
|
||||
consumption = 0
|
||||
if demand_type == cte.HEATING:
|
||||
consumption = building.heating_consumption[cte.YEAR][0] / 1e6
|
||||
elif demand_type == cte.DOMESTIC_HOT_WATER:
|
||||
consumption = building.domestic_hot_water_consumption[cte.YEAR][0] / 1e6
|
||||
elif demand_type == cte.COOLING:
|
||||
consumption = building.cooling_consumption[cte.YEAR][0] / 1e6
|
||||
|
||||
if generation_system.fuel_type == cte.ELECTRICITY:
|
||||
fuel_breakdown[demand_type]["Electricity"] += consumption
|
||||
else:
|
||||
fuel_breakdown[demand_type]["Gas"] += consumption
|
||||
|
||||
electricity_labels = ['Appliance', 'Lighting']
|
||||
electricity_sizes = [fuel_breakdown['Appliance'], fuel_breakdown['Lighting']]
|
||||
if fuel_breakdown['Heating']['Electricity'] > 0:
|
||||
electricity_labels.append('Heating')
|
||||
electricity_sizes.append(fuel_breakdown['Heating']['Electricity'])
|
||||
if fuel_breakdown['Cooling']['Electricity'] > 0:
|
||||
electricity_labels.append('Cooling')
|
||||
electricity_sizes.append(fuel_breakdown['Cooling']['Electricity'])
|
||||
if fuel_breakdown['Domestic Hot Water']['Electricity'] > 0:
|
||||
electricity_labels.append('Domestic Hot Water')
|
||||
electricity_sizes.append(fuel_breakdown['Domestic Hot Water']['Electricity'])
|
||||
|
||||
# Data for bar chart
|
||||
gas_labels = ['Heating', 'Domestic Hot Water']
|
||||
gas_sizes = [fuel_breakdown['Heating']['Gas'], fuel_breakdown['Domestic Hot Water']['Gas']]
|
||||
|
||||
# Set the style
|
||||
plt.style.use('ggplot')
|
||||
|
||||
# Create plot grid
|
||||
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
|
||||
|
||||
# Plot pie chart for electricity consumption breakdown
|
||||
colors = cm.get_cmap('tab20c', len(electricity_labels))
|
||||
axs[0].pie(electricity_sizes, labels=electricity_labels,
|
||||
autopct=lambda pct: f"{pct:.1f}%\n({pct / 100 * sum(electricity_sizes):.2f})",
|
||||
startangle=90, colors=[colors(i) for i in range(len(electricity_labels))])
|
||||
axs[0].set_title('Electricity Consumption Breakdown')
|
||||
|
||||
# Plot bar chart for natural gas consumption breakdown
|
||||
colors = cm.get_cmap('Paired', len(gas_labels))
|
||||
axs[1].bar(gas_labels, gas_sizes, color=[colors(i) for i in range(len(gas_labels))])
|
||||
axs[1].set_ylabel('Consumption (MWh)')
|
||||
axs[1].set_title('Natural Gas Consumption Breakdown')
|
||||
|
||||
# Add grid to bar chart
|
||||
axs[1].grid(axis='y', linestyle='--', alpha=0.7)
|
||||
|
||||
# Add a title to the entire figure
|
||||
plt.suptitle('Building Energy Consumption Breakdown', fontsize=16, fontweight='bold')
|
||||
|
||||
# Adjust layout
|
||||
plt.tight_layout()
|
||||
|
||||
# Save the plot as a high-quality image
|
||||
plt.savefig(save_directory / f'{building.name}_energy_consumption_breakdown.png', dpi=300)
|
||||
plt.close()
|
||||
|
||||
def create_report(self):
|
||||
os.chdir(self.output_path)
|
||||
self.report.add_section('Current Status')
|
||||
self.building_energy_info()
|
||||
self.base_case_charts()
|
||||
self.report.add_image('hvac_demand_chart.jpg', caption='Yearly HVAC Demands')
|
||||
self.report.add_image('dhw_demand_chart.jpg', caption='Yearly DHW Demands')
|
||||
self.report.add_image('electricity_demand_chart.jpg', caption='Yearly Electricity Demands')
|
||||
self.maximum_monthly_hvac_chart()
|
||||
self.load_duration_curves()
|
||||
for building in self.city.buildings:
|
||||
self.individual_building_info(building)
|
||||
self.building_existing_system_info(building)
|
||||
self.building_fuel_consumption_breakdown(building)
|
||||
self.report.add_image(f'{building.name}_energy_consumption_breakdown.png',
|
||||
caption=f'Building {building.name} Consumption by source and sector breakdown')
|
||||
self.report.save_report()
|
||||
self.report.compile_to_pdf()
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
hub/catalog_factories/cost/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
hub/catalog_factories/cost/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
Binary file not shown.
196
hub/catalog_factories/cost/montreal_complete_cost_catalog.py
Normal file
196
hub/catalog_factories/cost/montreal_complete_cost_catalog.py
Normal file
|
@ -0,0 +1,196 @@
|
|||
"""
|
||||
Cost catalog
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
import xmltodict
|
||||
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
|
||||
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
|
||||
from hub.catalog_factories.data_models.cost.chapter import Chapter
|
||||
from hub.catalog_factories.data_models.cost.item_description import ItemDescription
|
||||
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
|
||||
|
||||
|
||||
class MontrealNewCatalog(Catalog):
|
||||
"""
|
||||
Montreal custom catalog class
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
path = (path / 'montreal_costs_completed.xml').resolve()
|
||||
with open(path, 'r', encoding='utf-8') as xml:
|
||||
self._archetypes = xmltodict.parse(xml.read(), force_list='archetype')
|
||||
|
||||
# store the full catalog data model in self._content
|
||||
self._content = Content(self._load_archetypes())
|
||||
|
||||
def _load_archetypes(self):
|
||||
_catalog_archetypes = []
|
||||
archetypes = self._archetypes['archetypes']['archetype']
|
||||
for archetype in archetypes:
|
||||
lod = float(archetype['@lod'])
|
||||
function = archetype['@function']
|
||||
municipality = archetype['@municipality']
|
||||
country = archetype['@country']
|
||||
currency = archetype['currency']
|
||||
capital_cost = self.load_capital_costs(archetype)
|
||||
operational_cost = self._get_operational_costs(archetype['operational_cost'])
|
||||
end_of_life_cost = float(archetype['end_of_life_cost']['#text'])
|
||||
construction = float(archetype['incomes']['subsidies']['construction']['#text'])
|
||||
hvac = float(archetype['incomes']['subsidies']['hvac']['#text'])
|
||||
photovoltaic_system = float(archetype['incomes']['subsidies']['photovoltaic']['#text'])
|
||||
electricity_exports = float(archetype['incomes']['electricity_export']['#text']) / 1000 / 3600
|
||||
reduction_tax = float(archetype['incomes']['tax_reduction']['#text']) / 100
|
||||
income = Income(construction_subsidy=construction,
|
||||
hvac_subsidy=hvac,
|
||||
photovoltaic_subsidy=photovoltaic_system,
|
||||
electricity_export=electricity_exports,
|
||||
reductions_tax=reduction_tax)
|
||||
_catalog_archetypes.append(Archetype(lod,
|
||||
function,
|
||||
municipality,
|
||||
country,
|
||||
currency,
|
||||
capital_cost,
|
||||
operational_cost,
|
||||
end_of_life_cost,
|
||||
income))
|
||||
return _catalog_archetypes
|
||||
|
||||
@staticmethod
|
||||
def item_description(item_type, item):
|
||||
if 'refurbishment_cost' in item.keys():
|
||||
_refurbishment = float(item['refurbishment_cost']['#text'])
|
||||
_refurbishment_unit = item['refurbishment_cost']['@cost_unit']
|
||||
_item_description = ItemDescription(item_type,
|
||||
initial_investment=None,
|
||||
initial_investment_unit=None,
|
||||
refurbishment=_refurbishment,
|
||||
refurbishment_unit=_refurbishment_unit,
|
||||
reposition=None,
|
||||
reposition_unit=None,
|
||||
lifetime=None)
|
||||
else:
|
||||
_reposition = float(item['reposition']['#text'])
|
||||
_reposition_unit = item['reposition']['@cost_unit']
|
||||
_investment = float(item['investment_cost']['#text'])
|
||||
_investment_unit = item['investment_cost']['@cost_unit']
|
||||
_lifetime = float(item['lifetime_equipment']['#text'])
|
||||
_item_description = ItemDescription(item_type,
|
||||
initial_investment=_investment,
|
||||
initial_investment_unit=_investment_unit,
|
||||
refurbishment=None,
|
||||
refurbishment_unit=None,
|
||||
reposition=_reposition,
|
||||
reposition_unit=_reposition_unit,
|
||||
lifetime=_lifetime)
|
||||
|
||||
return _item_description
|
||||
|
||||
def load_capital_costs(self, archetype):
|
||||
archetype_capital_costs = archetype['capital_cost']
|
||||
design_allowance = float(
|
||||
archetype_capital_costs['Z_allowances_overhead_profit']['Z10_design_allowance']['#text']) / 100
|
||||
overhead_and_profit = float(
|
||||
archetype_capital_costs['Z_allowances_overhead_profit']['Z20_overhead_profit']['#text']) / 100
|
||||
general_chapters = []
|
||||
shell_items = []
|
||||
service_items = []
|
||||
for category in archetype_capital_costs:
|
||||
if category == 'B_shell':
|
||||
items = archetype_capital_costs[category]
|
||||
for item in items:
|
||||
components = items[item]
|
||||
for component in components:
|
||||
building_item = components[component]
|
||||
shell_items.append(self.item_description(component, building_item))
|
||||
general_chapters.append(Chapter(chapter_type=category, items=shell_items))
|
||||
elif category == 'D_services':
|
||||
services = archetype_capital_costs[category]
|
||||
for service in services:
|
||||
components = services[service]
|
||||
if len(components.keys()) == 1:
|
||||
for component in components:
|
||||
service_item = components[component]
|
||||
service_items.append(self.item_description(component, service_item))
|
||||
else:
|
||||
for component in components:
|
||||
items = components[component]
|
||||
if 'investment_cost' in items.keys():
|
||||
service_item = components[component]
|
||||
service_items.append(self.item_description(component, service_item))
|
||||
else:
|
||||
for item in items:
|
||||
service_item = items[item]
|
||||
service_items.append(self.item_description(item, service_item))
|
||||
|
||||
general_chapters.append(Chapter(chapter_type=category, items=service_items))
|
||||
capital_costs = CapitalCost(general_chapters=general_chapters,
|
||||
design_allowance=design_allowance,
|
||||
overhead_and_profit=overhead_and_profit)
|
||||
|
||||
return capital_costs
|
||||
|
||||
@staticmethod
|
||||
def _get_operational_costs(entry):
|
||||
fuels = []
|
||||
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_fixed_monthly = None
|
||||
fuel_fixed_peak = None
|
||||
if fuel_type == 'electricity':
|
||||
fuel_fixed_monthly = float(item['fixed_monthly']['#text'])
|
||||
fuel_fixed_peak = float(item['fixed_power']['#text']) / 1000
|
||||
elif fuel_type == 'gas':
|
||||
fuel_fixed_monthly = float(item['fixed_monthly']['#text'])
|
||||
fuel = Fuel(fuel_type,
|
||||
fixed_monthly=fuel_fixed_monthly,
|
||||
fixed_power=fuel_fixed_peak,
|
||||
variable=fuel_variable,
|
||||
variable_units=fuel_variable_units)
|
||||
fuels.append(fuel)
|
||||
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000
|
||||
cooling_equipment_maintenance = float(entry['maintenance']['cooling_equipment']['#text']) / 1000
|
||||
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,
|
||||
photovoltaic_system_maintenance,
|
||||
co2_emissions)
|
||||
return _operational_cost
|
||||
|
||||
def names(self, category=None):
|
||||
"""
|
||||
Get the catalog elements names
|
||||
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
|
||||
"""
|
||||
_names = {'archetypes': []}
|
||||
for archetype in self._content.archetypes:
|
||||
_names['archetypes'].append(archetype.name)
|
||||
return _names
|
||||
|
||||
def entries(self, category=None):
|
||||
"""
|
||||
Get the catalog elements
|
||||
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
|
||||
"""
|
||||
return self._content
|
||||
|
||||
def get_entry(self, name):
|
||||
"""
|
||||
Get one catalog element by names
|
||||
:parm: entry name
|
||||
"""
|
||||
for entry in self._content.archetypes:
|
||||
if entry.name.lower() == name.lower():
|
||||
return entry
|
||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -9,6 +9,7 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
|||
from pathlib import Path
|
||||
from typing import TypeVar
|
||||
from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCatalog
|
||||
from hub.catalog_factories.cost.montreal_complete_cost_catalog import MontrealNewCatalog
|
||||
|
||||
Catalog = TypeVar('Catalog')
|
||||
|
||||
|
@ -30,6 +31,14 @@ class CostsCatalogFactory:
|
|||
"""
|
||||
return MontrealCustomCatalog(self._path)
|
||||
|
||||
@property
|
||||
def _montreal_new(self):
|
||||
"""
|
||||
Retrieve Montreal Custom catalog
|
||||
"""
|
||||
return MontrealNewCatalog(self._path)
|
||||
|
||||
|
||||
@property
|
||||
def catalog(self) -> Catalog:
|
||||
"""
|
||||
|
@ -37,3 +46,7 @@ class CostsCatalogFactory:
|
|||
:return: CostCatalog
|
||||
"""
|
||||
return getattr(self, self._catalog_type, lambda: None)
|
||||
|
||||
@property
|
||||
def catalog_debug(self):
|
||||
return MontrealNewCatalog(self._path)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user