|
|
""" |
|
|
Export utilities for HVAC Load Calculator |
|
|
|
|
|
This module provides functions for exporting data from the HVAC Load Calculator. |
|
|
""" |
|
|
|
|
|
import json |
|
|
import csv |
|
|
import io |
|
|
import pandas as pd |
|
|
from datetime import datetime |
|
|
|
|
|
|
|
|
def export_data(form_data, results, format='json'): |
|
|
""" |
|
|
Export form data and calculation results. |
|
|
|
|
|
Args: |
|
|
form_data (dict): Form input data |
|
|
results (dict): Calculation results |
|
|
format (str): Export format ('json' or 'csv') |
|
|
|
|
|
Returns: |
|
|
str: Exported data as string |
|
|
""" |
|
|
if format == 'json': |
|
|
return export_as_json(form_data, results) |
|
|
elif format == 'csv': |
|
|
return export_as_csv(form_data, results) |
|
|
else: |
|
|
raise ValueError(f"Unsupported export format: {format}") |
|
|
|
|
|
|
|
|
def export_as_json(form_data, results): |
|
|
""" |
|
|
Export data as JSON. |
|
|
|
|
|
Args: |
|
|
form_data (dict): Form input data |
|
|
results (dict): Calculation results |
|
|
|
|
|
Returns: |
|
|
str: JSON string |
|
|
""" |
|
|
|
|
|
export_data = { |
|
|
'form_data': form_data, |
|
|
'results': results, |
|
|
'export_timestamp': datetime.now().isoformat() |
|
|
} |
|
|
|
|
|
|
|
|
return json.dumps(export_data, indent=2) |
|
|
|
|
|
|
|
|
def export_as_csv(form_data, results): |
|
|
""" |
|
|
Export data as CSV. |
|
|
|
|
|
Args: |
|
|
form_data (dict): Form input data |
|
|
results (dict): Calculation results |
|
|
|
|
|
Returns: |
|
|
str: CSV string |
|
|
""" |
|
|
|
|
|
output = io.StringIO() |
|
|
writer = csv.writer(output) |
|
|
|
|
|
|
|
|
writer.writerow(['HVAC Load Calculator Results', datetime.now().isoformat()]) |
|
|
writer.writerow([]) |
|
|
|
|
|
|
|
|
writer.writerow(['Building Information']) |
|
|
building_info = form_data.get('building_info', {}) |
|
|
for key, value in building_info.items(): |
|
|
writer.writerow([key, value]) |
|
|
writer.writerow([]) |
|
|
|
|
|
|
|
|
writer.writerow(['Calculation Results']) |
|
|
for key, value in results.items(): |
|
|
if key not in ['building_info', 'timestamp'] and not isinstance(value, dict): |
|
|
writer.writerow([key, value]) |
|
|
writer.writerow([]) |
|
|
|
|
|
|
|
|
writer.writerow(['Load Components']) |
|
|
writer.writerow(['Component', 'Load (W)', 'Percentage (%)']) |
|
|
|
|
|
|
|
|
sensible_load = results.get('sensible_load', 1) |
|
|
|
|
|
components = { |
|
|
'Conduction (Opaque Surfaces)': results.get('conduction_gain', 0), |
|
|
'Conduction (Windows)': results.get('window_conduction_gain', 0), |
|
|
'Solar Radiation (Windows)': results.get('window_solar_gain', 0), |
|
|
'Infiltration & Ventilation': results.get('infiltration_gain', 0), |
|
|
'Internal Gains': results.get('internal_gain', 0) |
|
|
} |
|
|
|
|
|
for component, load in components.items(): |
|
|
percentage = (load / sensible_load) * 100 if sensible_load > 0 else 0 |
|
|
writer.writerow([component, f"{load:.2f}", f"{percentage:.2f}"]) |
|
|
|
|
|
|
|
|
return output.getvalue() |
|
|
|
|
|
|
|
|
def generate_report(form_data, results, calculation_type='cooling'): |
|
|
""" |
|
|
Generate a formatted report of calculation results. |
|
|
|
|
|
Args: |
|
|
form_data (dict): Form input data |
|
|
results (dict): Calculation results |
|
|
calculation_type (str): Type of calculation ('cooling' or 'heating') |
|
|
|
|
|
Returns: |
|
|
str: Formatted report as HTML |
|
|
""" |
|
|
|
|
|
report_data = [] |
|
|
|
|
|
|
|
|
building_info = form_data.get('building_info', {}) |
|
|
report_data.append({ |
|
|
'Section': 'Building Information', |
|
|
'Item': 'Building Name', |
|
|
'Value': building_info.get('building_name', 'N/A') |
|
|
}) |
|
|
report_data.append({ |
|
|
'Section': 'Building Information', |
|
|
'Item': 'Location', |
|
|
'Value': building_info.get('location_name', 'N/A') |
|
|
}) |
|
|
report_data.append({ |
|
|
'Section': 'Building Information', |
|
|
'Item': 'Floor Area', |
|
|
'Value': f"{building_info.get('floor_area', 0):.2f} m²" |
|
|
}) |
|
|
report_data.append({ |
|
|
'Section': 'Building Information', |
|
|
'Item': 'Volume', |
|
|
'Value': f"{building_info.get('volume', 0):.2f} m³" |
|
|
}) |
|
|
|
|
|
|
|
|
if calculation_type == 'cooling': |
|
|
report_data.append({ |
|
|
'Section': 'Results', |
|
|
'Item': 'Sensible Cooling Load', |
|
|
'Value': f"{results.get('sensible_load', 0):.2f} W" |
|
|
}) |
|
|
report_data.append({ |
|
|
'Section': 'Results', |
|
|
'Item': 'Latent Cooling Load', |
|
|
'Value': f"{results.get('latent_load', 0):.2f} W" |
|
|
}) |
|
|
report_data.append({ |
|
|
'Section': 'Results', |
|
|
'Item': 'Total Cooling Load', |
|
|
'Value': f"{results.get('total_load', 0):.2f} W" |
|
|
}) |
|
|
report_data.append({ |
|
|
'Section': 'Results', |
|
|
'Item': 'Cooling Load per Area', |
|
|
'Value': f"{results.get('total_load', 0) / building_info.get('floor_area', 1):.2f} W/m²" |
|
|
}) |
|
|
else: |
|
|
report_data.append({ |
|
|
'Section': 'Results', |
|
|
'Item': 'Total Heating Load', |
|
|
'Value': f"{results.get('total_load', 0):.2f} W" |
|
|
}) |
|
|
report_data.append({ |
|
|
'Section': 'Results', |
|
|
'Item': 'Heating Load per Area', |
|
|
'Value': f"{results.get('total_load', 0) / building_info.get('floor_area', 1):.2f} W/m²" |
|
|
}) |
|
|
if 'annual_energy_kwh' in results: |
|
|
report_data.append({ |
|
|
'Section': 'Results', |
|
|
'Item': 'Annual Heating Energy', |
|
|
'Value': f"{results.get('annual_energy_kwh', 0):.2f} kWh" |
|
|
}) |
|
|
|
|
|
|
|
|
df = pd.DataFrame(report_data) |
|
|
|
|
|
|
|
|
html = df.to_html(index=False) |
|
|
|
|
|
return html |
|
|
|