Saeed Ranjbar
bb9454339f
A class named EnergySystemAnalysisReport is created to create and compile a latex file for reporting the output of the energy system simulation code.
207 lines
8.6 KiB
Python
207 lines
8.6 KiB
Python
import subprocess
|
|
import hub.helpers.constants as cte
|
|
import matplotlib.pyplot as plt
|
|
import random
|
|
import matplotlib.colors as mcolors
|
|
|
|
class EnergySystemAnalysisReport:
|
|
def __init__(self, file_name, city):
|
|
self.city = city
|
|
self.file_name = file_name
|
|
self.content = []
|
|
self.content.append(r'\documentclass{article}')
|
|
self.content.append(r'\usepackage[margin=2.5cm]{geometry}') # Adjust page margins
|
|
self.content.append(r'\usepackage{graphicx}')
|
|
self.content.append(r'\usepackage{tabularx}')
|
|
self.content.append(r'\begin{document}')
|
|
self.content.append(r'\title{' + 'Energy System Analysis Report' + r'}')
|
|
self.content.append(r'\author{Next-Generation Cities Institute}')
|
|
self.content.append(r'\date{\today}')
|
|
self.content.append(r'\maketitle')
|
|
|
|
def add_section(self, section_title):
|
|
self.content.append(r'\section{' + section_title + r'}')
|
|
|
|
def add_subsection(self, subsection_title):
|
|
self.content.append(r'\subsection{' + subsection_title + r'}')
|
|
|
|
def add_text(self, text):
|
|
self.content.append(text)
|
|
|
|
def add_table(self, table_data, caption=None):
|
|
num_columns = len(table_data[0])
|
|
total_width = 0.9 # Adjust the total width as needed
|
|
|
|
if caption:
|
|
self.content.append(r'\begin{table}[htbp]')
|
|
self.content.append(r'\caption{' + caption + r'}')
|
|
self.content.append(r'\centering')
|
|
|
|
self.content.append(r'\begin{tabularx}{\textwidth}{|' + '|'.join(['X'] * num_columns) + '|}')
|
|
self.content.append(r'\hline')
|
|
for row in table_data:
|
|
self.content.append(' & '.join(row) + r' \\')
|
|
self.content.append(r'\hline')
|
|
self.content.append(r'\end{tabularx}')
|
|
|
|
if caption:
|
|
self.content.append(r'\end{table}')
|
|
|
|
def add_image(self, image_path, caption=None):
|
|
if caption:
|
|
self.content.append(r'\begin{figure}[htbp]')
|
|
self.content.append(r'\centering')
|
|
self.content.append(r'\includegraphics[width=0.8\textwidth]{' + image_path + r'}')
|
|
self.content.append(r'\caption{' + caption + r'}')
|
|
self.content.append(r'\end{figure}')
|
|
else:
|
|
self.content.append(r'\begin{figure}[htbp]')
|
|
self.content.append(r'\centering')
|
|
self.content.append(r'\includegraphics[width=0.8\textwidth]{' + image_path + r'}')
|
|
self.content.append(r'\end{figure}')
|
|
|
|
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.add_table(table_data, caption='City Buildings Energy Demands')
|
|
self.add_table(intensity_table_data, caption='Energy Intensity Information')
|
|
|
|
def base_case_charts(self):
|
|
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('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(filename)
|
|
plt.close()
|
|
|
|
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')
|
|
|
|
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):
|
|
|
|
|
|
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(f'{building.name}_monthly_maximum_hvac_loads.jpg')
|
|
plt.close()
|
|
|
|
def save_report(self):
|
|
self.content.append(r'\end{document}') # Add this line to close the document
|
|
with open(self.file_name, 'w') as f:
|
|
f.write('\n'.join(self.content))
|
|
|
|
def compile_to_pdf(self):
|
|
subprocess.run(['pdflatex', self.file_name])
|