|
|
""" |
|
|
Main HVAC Calculator Script with Streamlit Interface |
|
|
|
|
|
Developed by: Dr Majed Abuseif, Deakin University |
|
|
© 2025 |
|
|
""" |
|
|
|
|
|
import streamlit as st |
|
|
import pandas as pd |
|
|
import plotly.graph_objects as go |
|
|
import logging |
|
|
from enum import Enum |
|
|
from typing import Dict, List |
|
|
from data.material_library import GlazingMaterial |
|
|
from data.calculation import TFMCalculations |
|
|
from utils.solar import SolarCalculations |
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
class ComponentType(Enum): |
|
|
WALL = "Wall" |
|
|
ROOF = "Roof" |
|
|
FLOOR = "Floor" |
|
|
WINDOW = "Window" |
|
|
DOOR = "Door" |
|
|
SKYLIGHT = "Skylight" |
|
|
|
|
|
class HVACCalculatorApp: |
|
|
def __init__(self): |
|
|
self.tfm = TFMCalculations() |
|
|
|
|
|
if 'window_action' not in st.session_state: |
|
|
st.session_state.glazing_action = {"action": None, "id": None} |
|
|
if 'components' not in st.session_state: |
|
|
st.session_state.components = { |
|
|
"windows": [ |
|
|
GlazingMaterial( |
|
|
id="window_1", |
|
|
name="Single Clear 6mm", |
|
|
component_type=ComponentType.WINDOW, |
|
|
area=10.0, |
|
|
u_value=5.8, |
|
|
shgc=0.7, |
|
|
facade="A" |
|
|
) |
|
|
], |
|
|
"skylights": [], |
|
|
"walls": [], |
|
|
"roofs": [], |
|
|
"floors": [], |
|
|
"doors": [], |
|
|
"_building_info": { |
|
|
"A": {"azimuth": 0.0, "tilt_angle": 0.0} |
|
|
} |
|
|
} |
|
|
if 'climate_data' not in st.session_state: |
|
|
st.session_state.climate_data = { |
|
|
"hourly_data": [ |
|
|
{ |
|
|
"month": 7, |
|
|
"day": 1, |
|
|
"hour": h, |
|
|
"dry_bulb": 30.0, |
|
|
"global_horizontal_radiation": 800.0 if 8 <= h <= 16 else 0.0, |
|
|
"direct_normal_radiation": 560.0 if 8 <= h <= 16 else 0.0, |
|
|
"diffuse_horizontal_radiation": 240.0 if 8 <= h <= 16 else 0.0 |
|
|
} for h in range(24) |
|
|
], |
|
|
"typical_extreme_periods": { |
|
|
"summer_extreme": {"start": {"month": 7, "day": 1}, "end": {"month": 7, "day": 7}}, |
|
|
"summer_typical": {"start": {"month": 7, "day": 1}, "end": {"month": 7, "day": 7}}, |
|
|
"winter_extreme": {"start": {"month": 1, "day": 1}, "end": {"month": 1, "day": 7}}, |
|
|
"winter_typical": {"start": {"month": 1, "day": 1}, "end": {"month": 1, "day": 7}} |
|
|
} |
|
|
} |
|
|
if 'building_info' not in st.session_state: |
|
|
st.session_state.building_info = { |
|
|
"latitude": 37.8, |
|
|
"longitude": -122.4, |
|
|
"timezone": -8.0, |
|
|
"ground_reflectivity": 0.2, |
|
|
"floor_area": 100.0, |
|
|
"indoor_design_temp": 24.0, |
|
|
"indoor_design_rh": 50.0 |
|
|
} |
|
|
if 'internal_loads' not in st.session_state: |
|
|
st.session_state.internal_loads = { |
|
|
"people": [{"num_people": 10, "activity_data": {"sensible_min_w": 70, "sensible_max_w": 100, "latent_min_w": 40, "latent_max_w": 60}, "diversity_factor": 1.0}], |
|
|
"lighting": [{"lpd": 10.0, "operating_hours": 10}], |
|
|
"equipment": {"total_power_density": 5.0}, |
|
|
"ventilation": {"space_rate": 0.3, "people_rate": 2.5}, |
|
|
"infiltration": {"method": "ACH", "settings": {"rate": 0.5}} |
|
|
} |
|
|
if 'calculation_results' not in st.session_state: |
|
|
st.session_state.calculation_results = {"cooling": [], "heating": []} |
|
|
|
|
|
def display_calculation_results(self): |
|
|
st.title("Calculation Results") |
|
|
st.write("Configure simulation settings and view cooling and heating load calculations based on ASHRAE CTF/TFM methods.") |
|
|
|
|
|
if not st.session_state.get("climate_data"): |
|
|
st.error("Please upload climate data in the Climate Data section.") |
|
|
st.button("Go to Climate Data", key="results_to_climate", |
|
|
on_click=lambda: setattr(st.session_state, "page", "Climate Data and Design Requirements")) |
|
|
return |
|
|
|
|
|
if not any(st.session_state.components.values()): |
|
|
st.error("Please define building components in the Building Components section.") |
|
|
st.button("Go to Building Components", key="results_to_components", |
|
|
on_click=lambda: setattr(st.session_state, "page", "Building Components")) |
|
|
return |
|
|
|
|
|
|
|
|
st.subheader("Debugging Solar Calculations") |
|
|
debug_hours = [8, 9, 10, 11] |
|
|
debug_data = [d for d in st.session_state.climate_data["hourly_data"] if d["month"] == 7 and d["day"] == 1 and d["hour"] in debug_hours] |
|
|
if not debug_data: |
|
|
st.warning("No climate data for debug hours (July 1, 8 AM–12 PM).") |
|
|
else: |
|
|
logger.info("Debugging SolarCalculations Inputs:") |
|
|
logger.info(f"Components (windows): {[{'id': c.id, 'area': c.area, 'shgc': c.shgc, 'facade': c.facade} for c in st.session_state.components.get('windows', [])]}") |
|
|
logger.info(f"Components (skylights): {[{'id': c.id, 'area': c.area, 'shgc': c.shgc, 'facade': c.facade} for c in st.session_state.components.get('skylights', [])]}") |
|
|
logger.info(f"Hourly Data: {[{'month': d['month'], 'day': d['day'], 'hour': d['hour'], 'GHI': d['global_horizontal_radiation'], 'DNI': d.get('direct_normal_radiation', 0), 'DHI': d.get('diffuse_horizontal_radiation', 0), 'dry_bulb': d['dry_bulb']} for d in debug_data]}") |
|
|
logger.info(f"Building Info: {{'latitude': {st.session_state.building_info.get('latitude', 0.0)}, 'longitude': {st.session_state.building_info.get('longitude', 0.0)}, 'timezone': {st.session_state.building_info.get('timezone', 0.0)}, 'ground_reflectivity': {st.session_state.building_info.get('ground_reflectivity', 0.2)}}}") |
|
|
|
|
|
try: |
|
|
solar_results = SolarCalculations.calculate_solar_parameters( |
|
|
hourly_data=debug_data, |
|
|
latitude=st.session_state.building_info.get("latitude", 0.0), |
|
|
longitude=st.session_state.building_info.get("longitude", 0.0), |
|
|
timezone=st.session_state.building_info.get("timezone", 0.0), |
|
|
ground_reflectivity=st.session_state.building_info.get("ground_reflectivity", 0.2), |
|
|
components=st.session_state.components |
|
|
) |
|
|
st.write("Solar Calculations Debug Output:") |
|
|
for result in solar_results: |
|
|
month, day, hour = result["month"], result["day"], result["hour"] |
|
|
logger.info(f"Solar Results for {month}/{day}/{hour}:") |
|
|
logger.info(f" Solar Altitude: {result['altitude']:.2f}°, Azimuth: {result['azimuth']:.2f}°") |
|
|
for comp_result in result["component_results"]: |
|
|
if "solar_heat_gain" in comp_result: |
|
|
logger.info(f" Component {comp_result['component_id']}: Solar Heat Gain = {comp_result['solar_heat_gain']:.2f} kW") |
|
|
st.write(f"Month {month}, Day {day}, Hour {hour}, Component {comp_result['component_id']}: Solar Heat Gain = {comp_result['solar_heat_gain']:.2f} kW") |
|
|
else: |
|
|
logger.info(f" Component {comp_result['component_id']}: No solar heat gain (not a window/skylight)") |
|
|
if not any("solar_heat_gain" in cr for cr in result["component_results"]): |
|
|
st.write(f"Month {month}, Day {day}, Hour {hour}: No solar heat gains calculated.") |
|
|
except Exception as e: |
|
|
logger.error(f"Error in SolarCalculations: {str(e)}") |
|
|
st.error(f"Error in Solar Calculations: {str(e)}") |
|
|
|
|
|
|
|
|
if 'sim_period' not in st.session_state: |
|
|
st.session_state.sim_period = {"type": "Full Year"} |
|
|
if 'indoor_conditions' not in st.session_state: |
|
|
st.session_state.indoor_conditions = { |
|
|
"type": "Fixed", |
|
|
"cooling_setpoint": { |
|
|
"temperature": st.session_state.building_info["indoor_design_temp"], |
|
|
"rh": st.session_state.building_info["indoor_design_rh"] |
|
|
}, |
|
|
"heating_setpoint": { |
|
|
"temperature": st.session_state.building_info["indoor_design_temp"] - 2.0, |
|
|
"rh": st.session_state.building_info["indoor_design_rh"] |
|
|
} |
|
|
} |
|
|
if 'hvac_settings' not in st.session_state: |
|
|
st.session_state.hvac_settings = { |
|
|
"cop": 3.5, |
|
|
"operating_hours": [{"start": 8, "end": 18}] |
|
|
} |
|
|
|
|
|
|
|
|
st.subheader("Simulation Period") |
|
|
typical_extreme_periods = st.session_state.climate_data.get("typical_extreme_periods", {}) |
|
|
sim_type_options = [ |
|
|
"Full Year", |
|
|
"From Date to Date", |
|
|
"Heating Only", |
|
|
"Cooling Only", |
|
|
"Summer Extreme", |
|
|
"Summer Typical", |
|
|
"Winter Extreme", |
|
|
"Winter Typical" |
|
|
] |
|
|
sim_type = st.selectbox( |
|
|
"Simulation Type", |
|
|
sim_type_options, |
|
|
index=sim_type_options.index(st.session_state.sim_period["type"]) |
|
|
if st.session_state.sim_period["type"] in sim_type_options else 0, |
|
|
key="sim_type" |
|
|
) |
|
|
sim_period = {"type": sim_type} |
|
|
if sim_type == "From Date to Date": |
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
start_date = st.date_input("Start Date", value=pd.to_datetime("2025-01-01"), key="start_date") |
|
|
with col2: |
|
|
end_date = st.date_input("End Date", value=pd.to_datetime("2025-12-31"), key="end_date") |
|
|
sim_period["start_date"] = start_date |
|
|
sim_period["end_date"] = end_date |
|
|
elif sim_type in ["Summer Extreme", "Summer Typical", "Winter Extreme", "Winter Typical"]: |
|
|
period_key = sim_type.lower().replace(" ", "_") |
|
|
if period_key in typical_extreme_periods: |
|
|
period = typical_extreme_periods[period_key] |
|
|
start_date = pd.to_datetime(f"2025-{period['start']['month']}-{period['start']['day']}") |
|
|
end_date = pd.to_datetime(f"2025-{period['end']['month']}-{period['end']['day']}") |
|
|
st.write(f"Period: {start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')}") |
|
|
sim_period["start_date"] = start_date |
|
|
sim_period["end_date"] = end_date |
|
|
else: |
|
|
st.warning(f"No data available for {sim_type}. Please check climate data.") |
|
|
sim_period["start_date"] = pd.to_datetime("2025-01-01") |
|
|
sim_period["end_date"] = pd.to_datetime("2025-12-31") |
|
|
|
|
|
|
|
|
st.subheader("Indoor Conditions") |
|
|
indoor_type = st.selectbox( |
|
|
"Indoor Conditions Type", |
|
|
["Fixed", "Time-varying", "Adaptive"], |
|
|
index=["Fixed", "Time-varying", "Adaptive"].index(st.session_state.indoor_conditions["type"]) |
|
|
if st.session_state.indoor_conditions["type"] in ["Fixed", "Time-varying", "Adaptive"] else 0, |
|
|
key="indoor_type" |
|
|
) |
|
|
indoor_conditions = {"type": indoor_type} |
|
|
if indoor_type == "Fixed": |
|
|
st.write("Cooling Setpoint") |
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
cooling_temp = st.number_input( |
|
|
"Cooling Indoor Temperature (°C)", |
|
|
min_value=15.0, |
|
|
max_value=30.0, |
|
|
value=st.session_state.indoor_conditions.get("cooling_setpoint", {}).get("temperature", 24.0), |
|
|
key="cooling_fixed_temp" |
|
|
) |
|
|
with col2: |
|
|
cooling_rh = st.number_input( |
|
|
"Cooling Indoor Relative Humidity (%)", |
|
|
min_value=0.0, |
|
|
max_value=100.0, |
|
|
value=st.session_state.indoor_conditions.get("cooling_setpoint", {}).get("rh", 50.0), |
|
|
key="cooling_fixed_rh" |
|
|
) |
|
|
st.write("Heating Setpoint") |
|
|
col3, col4 = st.columns(2) |
|
|
with col3: |
|
|
heating_temp = st.number_input( |
|
|
"Heating Indoor Temperature (°C)", |
|
|
min_value=15.0, |
|
|
max_value=30.0, |
|
|
value=st.session_state.indoor_conditions.get("heating_setpoint", {}).get("temperature", 22.0), |
|
|
key="heating_fixed_temp" |
|
|
) |
|
|
with col4: |
|
|
heating_rh = st.number_input( |
|
|
"Heating Indoor Relative Humidity (%)", |
|
|
min_value=0.0, |
|
|
max_value=100.0, |
|
|
value=st.session_state.indoor_conditions.get("heating_setpoint", {}).get("rh", 50.0), |
|
|
key="heating_fixed_rh" |
|
|
) |
|
|
indoor_conditions["cooling_setpoint"] = {"temperature": cooling_temp, "rh": cooling_rh} |
|
|
indoor_conditions["heating_setpoint"] = {"temperature": heating_temp, "rh": heating_rh} |
|
|
elif indoor_type == "Time-varying": |
|
|
st.write("Define hourly schedule (0-23 hours) for Cooling and Heating Setpoints") |
|
|
cooling_schedule = [] |
|
|
heating_schedule = [] |
|
|
for hour in range(24): |
|
|
with st.expander(f"Hour {hour}", expanded=False): |
|
|
st.write("Cooling Setpoint") |
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
cooling_temp = st.number_input( |
|
|
f"Cooling Temperature (°C) at Hour {hour}", |
|
|
min_value=15.0, |
|
|
max_value=30.0, |
|
|
value=24.0, |
|
|
key=f"cooling_schedule_temp_{hour}" |
|
|
) |
|
|
with col2: |
|
|
cooling_rh = st.number_input( |
|
|
f"Cooling RH (%) at Hour {hour}", |
|
|
min_value=0.0, |
|
|
max_value=100.0, |
|
|
value=50.0, |
|
|
key=f"cooling_schedule_rh_{hour}" |
|
|
) |
|
|
st.write("Heating Setpoint") |
|
|
col3, col4 = st.columns(2) |
|
|
with col3: |
|
|
heating_temp = st.number_input( |
|
|
f"Heating Temperature (°C) at Hour {hour}", |
|
|
min_value=15.0, |
|
|
max_value=30.0, |
|
|
value=22.0, |
|
|
key=f"heating_schedule_temp_{hour}" |
|
|
) |
|
|
with col4: |
|
|
heating_rh = st.number_input( |
|
|
f"Heating RH (%) at Hour {hour}", |
|
|
min_value=0.0, |
|
|
max_value=100.0, |
|
|
value=50.0, |
|
|
key=f"heating_schedule_rh_{hour}" |
|
|
) |
|
|
cooling_schedule.append({"hour": hour, "temperature": cooling_temp, "rh": cooling_rh}) |
|
|
heating_schedule.append({"hour": hour, "temperature": heating_temp, "rh": heating_rh}) |
|
|
indoor_conditions["cooling_schedule"] = cooling_schedule |
|
|
indoor_conditions["heating_schedule"] = heating_schedule |
|
|
else: |
|
|
st.write("Adaptive comfort model (ASHRAE 55) will be used, adjusting temperature based on outdoor conditions.") |
|
|
indoor_conditions["rh"] = 50.0 |
|
|
|
|
|
|
|
|
st.subheader("HVAC System Settings") |
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
cop = st.number_input( |
|
|
"Coefficient of Performance (COP)", |
|
|
min_value=1.0, |
|
|
max_value=6.0, |
|
|
value=st.session_state.hvac_settings.get("cop", 3.5), |
|
|
step=0.1, |
|
|
key="hvac_cop" |
|
|
) |
|
|
with col2: |
|
|
num_periods = st.number_input( |
|
|
"Number of Operating Periods", |
|
|
min_value=1, |
|
|
max_value=5, |
|
|
value=len(st.session_state.hvac_settings.get("operating_hours", [{"start": 8, "end": 18}])), |
|
|
step=1, |
|
|
key="num_operating_periods" |
|
|
) |
|
|
operating_hours = [] |
|
|
for i in range(int(num_periods)): |
|
|
st.write(f"Operating Period {i+1}") |
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
start_hour = st.slider( |
|
|
f"Start Hour (Period {i+1})", |
|
|
min_value=0, |
|
|
max_value=23, |
|
|
value=st.session_state.hvac_settings["operating_hours"][i]["start"] if i < len(st.session_state.hvac_settings["operating_hours"]) else 8, |
|
|
key=f"start_hour_{i}" |
|
|
) |
|
|
with col2: |
|
|
end_hour = st.slider( |
|
|
f"End Hour (Period {i+1})", |
|
|
min_value=start_hour, |
|
|
max_value=23, |
|
|
value=st.session_state.hvac_settings["operating_hours"][i]["end"] if i < len(st.session_state.hvac_settings["operating_hours"]) else 18, |
|
|
key=f"end_hour_{i}" |
|
|
) |
|
|
operating_hours.append({"start": start_hour, "end": end_hour}) |
|
|
|
|
|
|
|
|
st.session_state.sim_period = sim_period |
|
|
st.session_state.indoor_conditions = indoor_conditions |
|
|
st.session_state.hvac_settings = { |
|
|
"cop": cop, |
|
|
"operating_hours": operating_hours |
|
|
} |
|
|
|
|
|
|
|
|
if st.button("Run Simulation", key="run_simulation"): |
|
|
climate_data = st.session_state.climate_data.get("hourly_data", []) |
|
|
if not climate_data: |
|
|
st.error("No valid climate data available.") |
|
|
return |
|
|
with st.spinner("Running simulation..."): |
|
|
loads = self.tfm.calculate_tfm_loads( |
|
|
st.session_state.components, |
|
|
climate_data, |
|
|
st.session_state.indoor_conditions, |
|
|
st.session_state.internal_loads, |
|
|
st.session_state.building_info, |
|
|
st.session_state.sim_period, |
|
|
st.session_state.hvac_settings |
|
|
) |
|
|
st.session_state.calculation_results["cooling"] = loads |
|
|
st.session_state.calculation_results["heating"] = loads |
|
|
|
|
|
st.write("TFMCalculations Solar Load Debug Output:") |
|
|
for load in loads: |
|
|
if load["month"] == 7 and load["day"] == 1 and load["hour"] in debug_hours: |
|
|
logger.info(f"TFM Solar Load for {load['month']}/{load['day']}/{load['hour']}: {load['solar']:.2f} kW") |
|
|
st.write(f"Month {load['month']}, Day {load['day']}, Hour {load['hour']}: Solar Load = {load['solar']:.2f} kW") |
|
|
st.success("Simulation completed!") |
|
|
|
|
|
|
|
|
if st.session_state.calculation_results.get("cooling") and st.session_state.calculation_results.get("heating"): |
|
|
df = pd.DataFrame(st.session_state.calculation_results["cooling"]) |
|
|
if df.empty: |
|
|
st.error("No load calculations available.") |
|
|
return |
|
|
|
|
|
|
|
|
st.subheader("Equipment Sizing") |
|
|
peak_cooling_load = df["total_cooling"].max() if "total_cooling" in df else 0.0 |
|
|
peak_heating_load = df["total_heating"].max() if "total_heating" in df else 0.0 |
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
st.metric("Cooling Equipment Size", f"{peak_cooling_load:.2f} kW", help="Peak hourly cooling load") |
|
|
with col2: |
|
|
st.metric("Heating Equipment Size", f"{peak_heating_load:.2f} kW", help="Peak hourly heating load") |
|
|
|
|
|
|
|
|
st.subheader("Load Breakdown") |
|
|
cooling_totals = { |
|
|
"Conduction": df["conduction_cooling"].sum(), |
|
|
"Solar": df["solar"].sum(), |
|
|
"Internal": df["internal"].sum(), |
|
|
"Ventilation": df["ventilation_cooling"].sum(), |
|
|
"Infiltration": df["infiltration_cooling"].sum() |
|
|
} |
|
|
heating_totals = { |
|
|
"Conduction": df["conduction_heating"].sum(), |
|
|
"Ventilation": df["ventilation_heating"].sum(), |
|
|
"Infiltration": df["infiltration_heating"].sum() |
|
|
} |
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
fig_cooling = go.Figure(data=[ |
|
|
go.Pie(labels=list(cooling_totals.keys()), values=list(cooling_totals.values())) |
|
|
]) |
|
|
fig_cooling.update_layout(title="Cooling Load Breakdown (kWh)", width=400, height=400) |
|
|
st.plotly_chart(fig_cooling, use_container_width=True) |
|
|
with col2: |
|
|
fig_heating = go.Figure(data=[ |
|
|
go.Pie(labels=list(heating_totals.keys()), values=list(heating_totals.values())) |
|
|
]) |
|
|
fig_heating.update_layout(title="Heating Load Breakdown (kWh)", width=400, height=400) |
|
|
st.plotly_chart(fig_heating, use_container_width=True) |
|
|
|
|
|
|
|
|
st.subheader("Monthly Heating and Cooling Loads") |
|
|
df["month_name"] = df["month"].map({ |
|
|
1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "May", 6: "Jun", |
|
|
7: "Jul", 8: "Aug", 9: "Sep", 10: "Oct", 11: "Nov", 12: "Dec" |
|
|
}) |
|
|
monthly_loads = df.groupby("month_name")[["total_cooling", "total_heating"]].sum().reindex( |
|
|
["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] |
|
|
) |
|
|
fig_monthly = go.Figure(data=[ |
|
|
go.Bar(name="Cooling Load (kWh)", x=monthly_loads.index, y=monthly_loads["total_cooling"]), |
|
|
go.Bar(name="Heating Load (kWh)", x=monthly_loads.index, y=monthly_loads["total_heating"]) |
|
|
]) |
|
|
fig_monthly.update_layout( |
|
|
title="Monthly Heating and Cooling Loads", |
|
|
xaxis_title="Month", |
|
|
yaxis_title="Load (kWh)", |
|
|
barmode="group", |
|
|
width=800, |
|
|
height=400 |
|
|
) |
|
|
st.plotly_chart(fig_monthly, use_container_width=True) |
|
|
|
|
|
|
|
|
st.subheader("Load Summary") |
|
|
summary_row = { |
|
|
"hour": "Total", |
|
|
"month_name": "", |
|
|
"conduction_cooling": df["conduction_cooling"].sum(), |
|
|
"conduction_heating": df["conduction_heating"].sum(), |
|
|
"solar": df["solar"].sum(), |
|
|
"internal": df["internal"].sum(), |
|
|
"ventilation_cooling": df["ventilation_cooling"].sum(), |
|
|
"ventilation_heating": df["ventilation_heating"].sum(), |
|
|
"infiltration_cooling": df["infiltration_cooling"].sum(), |
|
|
"infiltration_heating": df["infiltration_heating"].sum(), |
|
|
"total_cooling": df["total_cooling"].sum(), |
|
|
"total_heating": df["total_heating"].sum() |
|
|
} |
|
|
display_df = df[["hour", "month_name", "conduction_cooling", "conduction_heating", "solar", |
|
|
"internal", "ventilation_cooling", "ventilation_heating", |
|
|
"infiltration_cooling", "infiltration_heating", "total_cooling", "total_heating"]] |
|
|
display_df = pd.concat([display_df, pd.DataFrame([summary_row])], ignore_index=True) |
|
|
st.dataframe(display_df.rename(columns={"month_name": "Month"}), use_container_width=True) |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
st.button("Back to Internal Loads", key="results_back_to_internal", |
|
|
on_click=lambda: setattr(st.session_state, "page", "Internal Loads")) |
|
|
with col2: |
|
|
st.button("Continue to Export Data", key="results_to_export", |
|
|
on_click=lambda: setattr(st.session_state, "page", "Export Data")) |
|
|
|
|
|
def main(): |
|
|
app = HVACCalculatorApp() |
|
|
app.display_calculation_results() |
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |