Spaces:
Sleeping
Sleeping
| """ | |
| Results display module for HVAC Load Calculator. | |
| This module provides the UI components for displaying calculation results. | |
| """ | |
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| from typing import Dict, List, Any, Optional, Tuple | |
| import json | |
| import os | |
| import plotly.graph_objects as go | |
| import plotly.express as px | |
| from datetime import datetime | |
| # Import visualization modules | |
| from utils.component_visualization import ComponentVisualization | |
| from utils.scenario_comparison import ScenarioComparisonVisualization | |
| from utils.psychrometric_visualization import PsychrometricVisualization | |
| from utils.time_based_visualization import TimeBasedVisualization | |
| class ResultsDisplay: | |
| """Class for results display interface.""" | |
| def __init__(self): | |
| """Initialize results display interface.""" | |
| self.component_visualization = ComponentVisualization() | |
| self.scenario_comparison = ScenarioComparisonVisualization() | |
| self.psychrometric_visualization = PsychrometricVisualization() | |
| self.time_based_visualization = TimeBasedVisualization() | |
| def display_results(self, session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display calculation results in Streamlit. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.header("Calculation Results") | |
| # Check if calculations have been performed | |
| if "calculation_results" not in session_state or not session_state["calculation_results"]: | |
| st.warning("No calculation results available. Please run calculations first.") | |
| return | |
| # Create tabs for different result views | |
| tab1, tab2, tab3, tab4, tab5 = st.tabs([ | |
| "Summary", | |
| "Component Breakdown", | |
| "Psychrometric Analysis", | |
| "Time Analysis", | |
| "Scenario Comparison" | |
| ]) | |
| with tab1: | |
| self._display_summary_results(session_state) | |
| with tab2: | |
| self._display_component_breakdown(session_state) | |
| with tab3: | |
| self._display_psychrometric_analysis(session_state) | |
| with tab4: | |
| self._display_time_analysis(session_state) | |
| with tab5: | |
| self._display_scenario_comparison(session_state) | |
| def _display_summary_results(self, session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display summary of calculation results. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("Summary Results") | |
| results = session_state["calculation_results"] | |
| # Display project information | |
| if "building_info" in session_state: | |
| st.write(f"**Project:** {session_state['building_info']['project_name']}") | |
| st.write(f"**Building:** {session_state['building_info']['building_name']}") | |
| location = f"{session_state['building_info']['city']}, {session_state['building_info']['country']}" | |
| st.write(f"**Location:** {location}") | |
| st.write(f"**Climate Zone:** {session_state['building_info'].get('climate_zone', 'N/A')}") | |
| st.write(f"**Floor Area:** {session_state['building_info']['floor_area']} m²") | |
| # Create columns for cooling and heating loads | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.write("### Cooling Load Results") | |
| # Check if cooling results are available | |
| if not results.get("cooling") or "total_load" not in results["cooling"]: | |
| st.warning("Cooling load results are not available. Please check calculation inputs and try again.") | |
| else: | |
| # Display cooling load metrics | |
| cooling_metrics = [ | |
| {"name": "Total Cooling Load", "value": results["cooling"]["total_load"], "unit": "kW"}, | |
| {"name": "Sensible Cooling Load", "value": results["cooling"]["sensible_load"], "unit": "kW"}, | |
| {"name": "Latent Cooling Load", "value": results["cooling"]["latent_load"], "unit": "kW"}, | |
| {"name": "Cooling Load per Area", "value": results["cooling"]["load_per_area"], "unit": "W/m²"} | |
| ] | |
| for metric in cooling_metrics: | |
| st.metric( | |
| label=metric["name"], | |
| value=f"{metric['value']:.2f} {metric['unit']}" | |
| ) | |
| # Display cooling load pie chart | |
| cooling_breakdown = { | |
| "Walls": results["cooling"]["component_loads"]["walls"], | |
| "Roof": results["cooling"]["component_loads"]["roof"], | |
| "Windows": results["cooling"]["component_loads"]["windows"], | |
| "Doors": results["cooling"]["component_loads"]["doors"], | |
| "People": results["cooling"]["component_loads"]["people"], | |
| "Lighting": results["cooling"]["component_loads"]["lighting"], | |
| "Equipment": results["cooling"]["component_loads"]["equipment"], | |
| "Infiltration": results["cooling"]["component_loads"]["infiltration"], | |
| "Ventilation": results["cooling"]["component_loads"]["ventilation"] | |
| } | |
| fig = px.pie( | |
| values=list(cooling_breakdown.values()), | |
| names=list(cooling_breakdown.keys()), | |
| title="Cooling Load Breakdown", | |
| color_discrete_sequence=px.colors.qualitative.Pastel | |
| ) | |
| fig.update_traces(textposition='inside', textinfo='percent+label') | |
| fig.update_layout(uniformtext_minsize=12, uniformtext_mode='hide') | |
| st.plotly_chart(fig, use_container_width=True) | |
| with col2: | |
| st.write("### Heating Load Results") | |
| # Check if heating results are available | |
| if not results.get("heating") or "total_load" not in results["heating"]: | |
| st.warning("Heating load results are not available. Please check calculation inputs and try again.") | |
| else: | |
| # Display heating load metrics | |
| heating_metrics = [ | |
| {"name": "Total Heating Load", "value": results["heating"]["total_load"], "unit": "kW"}, | |
| {"name": "Heating Load per Area", "value": results["heating"]["load_per_area"], "unit": "W/m²"}, | |
| {"name": "Design Heat Loss", "value": results["heating"]["design_heat_loss"], "unit": "kW"}, | |
| {"name": "Safety Factor", "value": results["heating"]["safety_factor"], "unit": "%"} | |
| ] | |
| for metric in heating_metrics: | |
| st.metric( | |
| label=metric["name"], | |
| value=f"{metric['value']:.2f} {metric['unit']}" | |
| ) | |
| # Display heating load pie chart | |
| heating_breakdown = { | |
| "Walls": results["heating"]["component_loads"]["walls"], | |
| "Roof": results["heating"]["component_loads"]["roof"], | |
| "Floor": results["heating"]["component_loads"]["floor"], | |
| "Windows": results["heating"]["component_loads"]["windows"], | |
| "Doors": results["heating"]["component_loads"]["doors"], | |
| "Infiltration": results["heating"]["component_loads"]["infiltration"], | |
| "Ventilation": results["heating"]["component_loads"]["ventilation"] | |
| } | |
| fig = px.pie( | |
| values=list(heating_breakdown.values()), | |
| names=list(heating_breakdown.keys()), | |
| title="Heating Load Breakdown", | |
| color_discrete_sequence=px.colors.qualitative.Pastel | |
| ) | |
| fig.update_traces(textposition='inside', textinfo='percent+label') | |
| fig.update_layout(uniformtext_minsize=12, uniformtext_mode='hide') | |
| st.plotly_chart(fig, use_container_width=True) | |
| # Display tabular results | |
| st.subheader("Detailed Results") | |
| # Create tabs for cooling and heating tables | |
| tab1, tab2 = st.tabs(["Cooling Load Details", "Heating Load Details"]) | |
| with tab1: | |
| if not results.get("cooling") or "detailed_loads" not in results["cooling"]: | |
| st.warning("Cooling load details are not available.") | |
| else: | |
| # Create cooling load details table | |
| cooling_details = [] | |
| # Add envelope components | |
| for wall in results["cooling"]["detailed_loads"]["walls"]: | |
| cooling_details.append({ | |
| "Component Type": "Wall", | |
| "Name": wall["name"], | |
| "Orientation": wall["orientation"], | |
| "Area (m²)": wall["area"], | |
| "U-Value (W/m²·K)": wall["u_value"], | |
| "CLTD (°C)": wall["cltd"], | |
| "Load (kW)": wall["load"] | |
| }) | |
| for roof in results["cooling"]["detailed_loads"]["roofs"]: | |
| cooling_details.append({ | |
| "Component Type": "Roof", | |
| "Name": roof["name"], | |
| "Orientation": roof["orientation"], | |
| "Area (m²)": roof["area"], | |
| "U-Value (W/m²·K)": roof["u_value"], | |
| "CLTD (°C)": roof["cltd"], | |
| "Load (kW)": roof["load"] | |
| }) | |
| for window in results["cooling"]["detailed_loads"]["windows"]: | |
| cooling_details.append({ | |
| "Component Type": "Window", | |
| "Name": window["name"], | |
| "Orientation": window["orientation"], | |
| "Area (m²)": window["area"], | |
| "U-Value (W/m²·K)": window["u_value"], | |
| "SHGC": window["shgc"], | |
| "SCL (W/m²)": window["scl"], | |
| "Load (kW)": window["load"] | |
| }) | |
| for door in results["cooling"]["detailed_loads"]["doors"]: | |
| cooling_details.append({ | |
| "Component Type": "Door", | |
| "Name": door["name"], | |
| "Orientation": door["orientation"], | |
| "Area (m²)": door["area"], | |
| "U-Value (W/m²·K)": door["u_value"], | |
| "CLTD (°C)": door["cltd"], | |
| "Load (kW)": door["load"] | |
| }) | |
| # Add internal loads | |
| for internal_load in results["cooling"]["detailed_loads"]["internal"]: | |
| cooling_details.append({ | |
| "Component Type": internal_load["type"], | |
| "Name": internal_load["name"], | |
| "Quantity": internal_load["quantity"], | |
| "Heat Gain (W)": internal_load["heat_gain"], | |
| "CLF": internal_load["clf"], | |
| "Load (kW)": internal_load["load"] | |
| }) | |
| # Add infiltration and ventilation | |
| cooling_details.append({ | |
| "Component Type": "Infiltration", | |
| "Name": "Air Infiltration", | |
| "Air Flow (m³/s)": results["cooling"]["detailed_loads"]["infiltration"]["air_flow"], | |
| "Sensible Load (kW)": results["cooling"]["detailed_loads"]["infiltration"]["sensible_load"], | |
| "Latent Load (kW)": results["cooling"]["detailed_loads"]["infiltration"]["latent_load"], | |
| "Load (kW)": results["cooling"]["detailed_loads"]["infiltration"]["total_load"] | |
| }) | |
| cooling_details.append({ | |
| "Component Type": "Ventilation", | |
| "Name": "Fresh Air", | |
| "Air Flow (m³/s)": results["cooling"]["detailed_loads"]["ventilation"]["air_flow"], | |
| "Sensible Load (kW)": results["cooling"]["detailed_loads"]["ventilation"]["sensible_load"], | |
| "Latent Load (kW)": results["cooling"]["detailed_loads"]["ventilation"]["latent_load"], | |
| "Load (kW)": results["cooling"]["detailed_loads"]["ventilation"]["total_load"] | |
| }) | |
| # Display cooling details table | |
| cooling_df = pd.DataFrame(cooling_details) | |
| st.dataframe(cooling_df, use_container_width=True) | |
| with tab2: | |
| if not results.get("heating") or "detailed_loads" not in results["heating"]: | |
| st.warning("Heating load details are not available.") | |
| else: | |
| # Create heating load details table | |
| heating_details = [] | |
| # Add envelope components | |
| for wall in results["heating"]["detailed_loads"]["walls"]: | |
| heating_details.append({ | |
| "Component Type": "Wall", | |
| "Name": wall["name"], | |
| "Orientation": wall["orientation"], | |
| "Area (m²)": wall["area"], | |
| "U-Value (W/m²·K)": wall["u_value"], | |
| "Temperature Difference (°C)": wall["delta_t"], | |
| "Load (kW)": wall["load"] | |
| }) | |
| for roof in results["heating"]["detailed_loads"]["roofs"]: | |
| heating_details.append({ | |
| "Component Type": "Roof", | |
| "Name": roof["name"], | |
| "Orientation": roof["orientation"], | |
| "Area (m²)": roof["area"], | |
| "U-Value (W/m²·K)": wall["u_value"], | |
| "Temperature Difference (°C)": roof["delta_t"], | |
| "Load (kW)": roof["load"] | |
| }) | |
| for floor in results["heating"]["detailed_loads"]["floors"]: | |
| heating_details.append({ | |
| "Component Type": "Floor", | |
| "Name": floor["name"], | |
| "Area (m²)": floor["area"], | |
| "U-Value (W/m²·K)": floor["u_value"], | |
| "Temperature Difference (°C)": floor["delta_t"], | |
| "Load (kW)": floor["load"] | |
| }) | |
| for window in results["heating"]["detailed_loads"]["windows"]: | |
| heating_details.append({ | |
| "Component Type": "Window", | |
| "Name": window["name"], | |
| "Orientation": window["orientation"], | |
| "Area (m²)": window["area"], | |
| "U-Value (W/m²·K)": window["u_value"], | |
| "Temperature Difference (°C)": window["delta_t"], | |
| "Load (kW)": window["load"] | |
| }) | |
| for door in results["heating"]["detailed_loads"]["doors"]: | |
| heating_details.append({ | |
| "Component Type": "Door", | |
| "Name": door["name"], | |
| "Orientation": door["orientation"], | |
| "Area (m²)": door["area"], | |
| "U-Value (W/m²·K)": door["u_value"], | |
| "Temperature Difference (°C)": door["delta_t"], | |
| "Load (kW)": door["load"] | |
| }) | |
| # Add infiltration and ventilation | |
| heating_details.append({ | |
| "Component Type": "Infiltration", | |
| "Name": "Air Infiltration", | |
| "Air Flow (m³/s)": results["heating"]["detailed_loads"]["infiltration"]["air_flow"], | |
| "Temperature Difference (°C)": results["heating"]["detailed_loads"]["infiltration"]["delta_t"], | |
| "Load (kW)": results["heating"]["detailed_loads"]["infiltration"]["load"] | |
| }) | |
| heating_details.append({ | |
| "Component Type": "Ventilation", | |
| "Name": "Fresh Air", | |
| "Air Flow (m³/s)": results["heating"]["detailed_loads"]["ventilation"]["air_flow"], | |
| "Temperature Difference (°C)": results["heating"]["detailed_loads"]["ventilation"]["delta_t"], | |
| "Load (kW)": results["heating"]["detailed_loads"]["ventilation"]["load"] | |
| }) | |
| # Display heating details table | |
| heating_df = pd.DataFrame(heating_details) | |
| st.dataframe(heating_df, use_container_width=True) | |
| # Add download buttons for results | |
| st.subheader("Download Results") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if results.get("cooling") and "detailed_loads" in results["cooling"]: | |
| if st.button("Download Cooling Load Results (CSV)"): | |
| cooling_csv = cooling_df.to_csv(index=False) | |
| st.download_button( | |
| label="Download CSV", | |
| data=cooling_csv, | |
| file_name=f"cooling_load_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv", | |
| mime="text/csv" | |
| ) | |
| with col2: | |
| if results.get("heating") and "detailed_loads" in results["heating"]: | |
| if st.button("Download Heating Load Results (CSV)"): | |
| heating_csv = heating_df.to_csv(index=False) | |
| st.download_button( | |
| label="Download CSV", | |
| data=heating_csv, | |
| file_name=f"heating_load_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv", | |
| mime="text/csv" | |
| ) | |
| # Add button to download full report | |
| if st.button("Generate Full Report (Excel)"): | |
| st.info("Excel report generation will be implemented in the Export module.") | |
| def _display_component_breakdown(self, session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display component breakdown visualization. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("Component Breakdown") | |
| if not session_state["calculation_results"].get("cooling") and not session_state["calculation_results"].get("heating"): | |
| st.warning("No component breakdown data available.") | |
| return | |
| # Try to use component visualization module | |
| try: | |
| self.component_visualization.display_component_breakdown( | |
| session_state["calculation_results"], | |
| session_state["components"] | |
| ) | |
| except AttributeError: | |
| # Fallback visualization if display_component_breakdown is not available | |
| st.info("Component visualization module not fully implemented. Displaying default breakdown.") | |
| results = session_state["calculation_results"] | |
| # Cooling load bar chart | |
| if results.get("cooling"): | |
| cooling_breakdown = { | |
| "Walls": results["cooling"]["component_loads"]["walls"], | |
| "Roof": results["cooling"]["component_loads"]["roof"], | |
| "Windows": results["cooling"]["component_loads"]["windows"], | |
| "Doors": results["cooling"]["component_loads"]["doors"], | |
| "People": results["cooling"]["component_loads"]["people"], | |
| "Lighting": results["cooling"]["component_loads"]["lighting"], | |
| "Equipment": results["cooling"]["component_loads"]["equipment"], | |
| "Infiltration": results["cooling"]["component_loads"]["infiltration"], | |
| "Ventilation": results["cooling"]["component_loads"]["ventilation"] | |
| } | |
| fig_cooling = px.bar( | |
| x=list(cooling_breakdown.keys()), | |
| y=list(cooling_breakdown.values()), | |
| title="Cooling Load by Component", | |
| labels={"x": "Component", "y": "Load (kW)"}, | |
| color_discrete_sequence=px.colors.qualitative.Pastel | |
| ) | |
| fig_cooling.update_layout(showlegend=False) | |
| st.plotly_chart(fig_cooling, use_container_width=True) | |
| # Heating load bar chart | |
| if results.get("heating"): | |
| heating_breakdown = { | |
| "Walls": results["heating"]["component_loads"]["walls"], | |
| "Roof": results["heating"]["component_loads"]["roof"], | |
| "Floor": results["heating"]["component_loads"]["floor"], | |
| "Windows": results["heating"]["component_loads"]["windows"], | |
| "Doors": results["heating"]["component_loads"]["doors"], | |
| "Infiltration": results["heating"]["component_loads"]["infiltration"], | |
| "Ventilation": results["heating"]["component_loads"]["ventilation"] | |
| } | |
| fig_heating = px.bar( | |
| x=list(heating_breakdown.keys()), | |
| y=list(heating_breakdown.values()), | |
| title="Heating Load by Component", | |
| labels={"x": "Component", "y": "Load (kW)"}, | |
| color_discrete_sequence=px.colors.qualitative.Pastel | |
| ) | |
| fig_heating.update_layout(showlegend=False) | |
| st.plotly_chart(fig_heating, use_container_width=True) | |
| def _display_psychrometric_analysis(self, session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display psychrometric analysis visualization. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("Psychrometric Analysis") | |
| if not session_state["calculation_results"].get("cooling"): | |
| st.warning("Psychrometric analysis requires cooling load results.") | |
| return | |
| # Use psychrometric visualization module | |
| self.psychrometric_visualization.display_psychrometric_chart( | |
| session_state["calculation_results"], | |
| session_state["building_info"] | |
| ) | |
| def _display_time_analysis(self, session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display time-based analysis visualization. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("Time Analysis") | |
| if not session_state["calculation_results"].get("cooling"): | |
| st.warning("Time analysis requires cooling load results.") | |
| return | |
| # Use time-based visualization module | |
| self.time_based_visualization.display_time_analysis( | |
| session_state["calculation_results"] | |
| ) | |
| def _display_scenario_comparison(self, session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display scenario comparison visualization. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("Scenario Comparison") | |
| # Check if there are saved scenarios | |
| if "saved_scenarios" not in session_state or not session_state["saved_scenarios"]: | |
| st.info("No saved scenarios available for comparison. Save the current results as a scenario to enable comparison.") | |
| # Add button to save current results as a scenario | |
| scenario_name = st.text_input("Scenario Name", value="Baseline") | |
| if st.button("Save Current Results as Scenario"): | |
| if "saved_scenarios" not in session_state: | |
| session_state["saved_scenarios"] = {} | |
| # Save current results as a scenario | |
| session_state["saved_scenarios"][scenario_name] = { | |
| "results": session_state["calculation_results"], | |
| "building_info": session_state["building_info"], | |
| "components": session_state["components"], | |
| "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| } | |
| st.success(f"Scenario '{scenario_name}' saved successfully!") | |
| st.rerun() | |
| else: | |
| # Use scenario comparison module | |
| self.scenario_comparison.display_scenario_comparison( | |
| session_state["calculation_results"], | |
| session_state["saved_scenarios"] | |
| ) | |
| # Add button to save current results as a new scenario | |
| st.write("### Save Current Results as New Scenario") | |
| scenario_name = st.text_input("Scenario Name", value="Scenario " + str(len(session_state["saved_scenarios"]) + 1)) | |
| if st.button("Save Current Results as Scenario"): | |
| # Save current results as a scenario | |
| session_state["saved_scenarios"][scenario_name] = { | |
| "results": session_state["calculation_results"], | |
| "building_info": session_state["building_info"], | |
| "components": session_state["components"], | |
| "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| } | |
| st.success(f"Scenario '{scenario_name}' saved successfully!") | |
| st.rerun() | |
| # Add button to delete a scenario | |
| st.write("### Delete Scenario") | |
| scenario_to_delete = st.selectbox( | |
| "Select Scenario to Delete", | |
| options=list(session_state["saved_scenarios"].keys()) | |
| ) | |
| if st.button("Delete Selected Scenario"): | |
| # Delete selected scenario | |
| del session_state["saved_scenarios"][scenario_to_delete] | |
| st.success(f"Scenario '{scenario_to_delete}' deleted successfully!") | |
| st.rerun() | |
| # Create a singleton instance | |
| results_display = ResultsDisplay() | |
| # Example usage | |
| if __name__ == "__main__": | |
| import streamlit as st | |
| # Initialize session state with dummy data for testing | |
| if "calculation_results" not in st.session_state: | |
| st.session_state["calculation_results"] = { | |
| "cooling": { | |
| "total_load": 25.5, | |
| "sensible_load": 20.0, | |
| "latent_load": 5.5, | |
| "load_per_area": 85.0, | |
| "component_loads": { | |
| "walls": 5.0, | |
| "roof": 3.0, | |
| "windows": 8.0, | |
| "doors": 1.0, | |
| "people": 2.5, | |
| "lighting": 2.0, | |
| "equipment": 1.5, | |
| "infiltration": 1.0, | |
| "ventilation": 1.5 | |
| }, | |
| "detailed_loads": { | |
| "walls": [ | |
| {"name": "North Wall", "orientation": "NORTH", "area": 20.0, "u_value": 0.5, "cltd": 10.0, "load": 1.0} | |
| ], | |
| "roofs": [ | |
| {"name": "Main Roof", "orientation": "HORIZONTAL", "area": 100.0, "u_value": 0.3, "cltd": 15.0, "load": 3.0} | |
| ], | |
| "windows": [ | |
| {"name": "South Window", "orientation": "SOUTH", "area": 10.0, "u_value": 2.8, "shgc": 0.7, "scl": 800.0, "load": 8.0} | |
| ], | |
| "doors": [ | |
| {"name": "Main Door", "orientation": "NORTH", "area": 2.0, "u_value": 2.0, "cltd": 10.0, "load": 1.0} | |
| ], | |
| "internal": [ | |
| {"type": "People", "name": "Occupants", "quantity": 10, "heat_gain": 250, "clf": 1.0, "load": 2.5}, | |
| {"type": "Lighting", "name": "General Lighting", "quantity": 1000, "heat_gain": 2000, "clf": 1.0, "load": 2.0}, | |
| {"type": "Equipment", "name": "Office Equipment", "quantity": 5, "heat_gain": 300, "clf": 1.0, "load": 1.5} | |
| ], | |
| "infiltration": { | |
| "air_flow": 0.05, | |
| "sensible_load": 0.8, | |
| "latent_load": 0.2, | |
| "total_load": 1.0 | |
| }, | |
| "ventilation": { | |
| "air_flow": 0.1, | |
| "sensible_load": 1.0, | |
| "latent_load": 0.5, | |
| "total_load": 1.5 | |
| } | |
| } | |
| }, | |
| "heating": { | |
| "total_load": 30.0, | |
| "load_per_area": 100.0, | |
| "design_heat_loss": 27.0, | |
| "safety_factor": 10.0, | |
| "component_loads": { | |
| "walls": 8.0, | |
| "roof": 5.0, | |
| "floor": 4.0, | |
| "windows": 7.0, | |
| "doors": 1.0, | |
| "infiltration": 2.0, | |
| "ventilation": 3.0 | |
| }, | |
| "detailed_loads": { | |
| "walls": [ | |
| {"name": "North Wall", "orientation": "NORTH", "area": 20.0, "u_value": 0.5, "delta_t": 25.0, "load": 8.0} | |
| ], | |
| "roofs": [ | |
| {"name": "Main Roof", "orientation": "HORIZONTAL", "area": 100.0, "u_value": 0.3, "delta_t": 25.0, "load": 5.0} | |
| ], | |
| "floors": [ | |
| {"name": "Ground Floor", "area": 100.0, "u_value": 0.4, "delta_t": 10.0, "load": 4.0} | |
| ], | |
| "windows": [ | |
| {"name": "South Window", "orientation": "SOUTH", "area": 10.0, "u_value": 2.8, "delta_t": 25.0, "load": 7.0} | |
| ], | |
| "doors": [ | |
| {"name": "Main Door", "orientation": "NORTH", "area": 2.0, "u_value": 2.0, "delta_t": 25.0, "load": 1.0} | |
| ], | |
| "infiltration": { | |
| "air_flow": 0.05, | |
| "delta_t": 25.0, | |
| "load": 2.0 | |
| }, | |
| "ventilation": { | |
| "air_flow": 0.1, | |
| "delta_t": 25.0, | |
| "load": 3.0 | |
| } | |
| } | |
| } | |
| } | |
| # Display results | |
| results_display.display_results(st.session_state) |