Spaces:
Sleeping
Sleeping
| """ | |
| BuildSustain - Building Information Module | |
| This module handles the building information input page of the BuildSustain application, | |
| allowing users to define basic building parameters such as project name, floor area, building height, | |
| indoor design conditions for winter and summer, orientation, and building type. | |
| Developed by: Dr Majed Abuseif, Deakin University | |
| © 2025 | |
| """ | |
| import streamlit as st | |
| import logging | |
| import math | |
| from typing import Dict, Any, Optional, List, Tuple | |
| from app.i_l_data import DEFAULT_BUILDING_INTERNALS | |
| # Define BUILDING_TYPES as the list of keys from DEFAULT_BUILDING_INTERNALS | |
| BUILDING_TYPES = list(DEFAULT_BUILDING_INTERNALS.keys()) | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
| logger = logging.getLogger(__name__) | |
| def display_building_info_page(): | |
| """ | |
| Display the building information input page. | |
| This is the main function called by main.py when the Building Information page is selected. | |
| """ | |
| st.title("Building Information") | |
| # Display help information in an expandable section | |
| with st.expander("Help & Information"): | |
| display_building_info_help() | |
| # Create the main form for building information input | |
| with st.form("building_info_form"): | |
| # Get current values from session state or use defaults | |
| current_values = st.session_state.project_data["building_info"] | |
| # Project Name and other fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| project_name = st.text_input( | |
| "Project Name", | |
| value=current_values["project_name"], | |
| help="Enter a unique identifier for your project." | |
| ) | |
| # Building Type | |
| building_type = st.selectbox( | |
| "Building Type", | |
| options=BUILDING_TYPES, | |
| index=BUILDING_TYPES.index(current_values["building_type"]) if current_values["building_type"] in BUILDING_TYPES else 0, | |
| help="Primary use of the building, which affects default internal loads." | |
| ) | |
| # Floor Area | |
| floor_area = st.number_input( | |
| "Floor Area (square meters)", | |
| min_value=1.0, | |
| max_value=100000.0, | |
| value=float(current_values["floor_area"]), | |
| step=10.0, | |
| format="%.1f", | |
| help="Total conditioned floor area of the building in square meters." | |
| ) | |
| # Building Height | |
| building_height = st.number_input( | |
| "Building Height (meters)", | |
| min_value=2.0, | |
| max_value=100.0, | |
| value=float(current_values["building_height"]), | |
| step=0.1, | |
| format="%.1f", | |
| help="Average ceiling height of the building in meters." | |
| ) | |
| with col2: | |
| # Summer Indoor Design Temperature | |
| summer_indoor_design_temp = st.number_input( | |
| "Summer Indoor Design Temperature (°C)", | |
| min_value=15.0, | |
| max_value=30.0, | |
| value=float(current_values.get("summer_indoor_design_temp", current_values.get("indoor_design_temp", 24.0))), | |
| step=0.5, | |
| format="%.1f", | |
| help="Target indoor temperature for summer season comfort (15–30°C)." | |
| ) | |
| # Winter Indoor Design Temperature | |
| winter_indoor_design_temp = st.number_input( | |
| "Winter Indoor Design Temperature (°C)", | |
| min_value=15.0, | |
| max_value=30.0, | |
| value=float(current_values.get("winter_indoor_design_temp", current_values.get("indoor_design_temp", 20.0))), | |
| step=0.5, | |
| format="%.1f", | |
| help="Target indoor temperature for winter season comfort (15–30°C)." | |
| ) | |
| # Summer Indoor Design Relative Humidity | |
| summer_indoor_design_rh = st.number_input( | |
| "Summer Indoor Design Relative Humidity (%)", | |
| min_value=20.0, | |
| max_value=80.0, | |
| value=float(current_values.get("summer_indoor_design_rh", current_values.get("indoor_design_rh", 50.0))), | |
| step=5.0, | |
| format="%.1f", | |
| help="Target indoor relative humidity for summer season comfort (20–80%)." | |
| ) | |
| # Winter Indoor Design Relative Humidity | |
| winter_indoor_design_rh = st.number_input( | |
| "Winter Indoor Design Relative Humidity (%)", | |
| min_value=20.0, | |
| max_value=80.0, | |
| value=float(current_values.get("winter_indoor_design_rh", current_values.get("indoor_design_rh", 50.0))), | |
| step=5.0, | |
| format="%.1f", | |
| help="Target indoor relative humidity for winter season comfort (20–80%)." | |
| ) | |
| # Building Orientation | |
| st.subheader("Building Orientation") | |
| # Display orientation images | |
| display_orientation_diagram() | |
| orientation_angle = st.slider( | |
| "Orientation Angle (°)", | |
| min_value=-180, | |
| max_value=180, | |
| value=int(current_values["orientation_angle"]), | |
| step=5, | |
| help="Sets the building's rotation angle relative to north (0°). Component orientations are defined as A (North), B (South), C (East), D (West) at 0°. Adjusting this angle rotates all component orientations accordingly." | |
| ) | |
| # Form submission button | |
| submit_button = st.form_submit_button("Save Building Information") | |
| if submit_button: | |
| # Validate inputs | |
| validation_errors = validate_building_info( | |
| project_name, floor_area, building_height, building_type, | |
| winter_indoor_design_temp, winter_indoor_design_rh, | |
| summer_indoor_design_temp, summer_indoor_design_rh, | |
| orientation_angle | |
| ) | |
| if validation_errors: | |
| # Display validation errors | |
| for error in validation_errors: | |
| st.error(error) | |
| else: | |
| # Update session state with validated inputs | |
| st.session_state.project_data["project_name"] = project_name | |
| st.session_state.project_data["building_info"].update({ | |
| "project_name": project_name, | |
| "floor_area": floor_area, | |
| "building_height": building_height, | |
| "building_type": building_type, | |
| "winter_indoor_design_temp": winter_indoor_design_temp, | |
| "winter_indoor_design_rh": winter_indoor_design_rh, | |
| "summer_indoor_design_temp": summer_indoor_design_temp, | |
| "summer_indoor_design_rh": summer_indoor_design_rh, | |
| "orientation_angle": float(orientation_angle) | |
| }) | |
| # Log the update | |
| logger.info(f"Building information updated for project: {project_name}") | |
| # Show success message | |
| st.success("Building information saved successfully!") | |
| # Navigation buttons | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("Back to Intro", key="back_to_intro"): | |
| st.session_state.current_page = "Intro" | |
| st.rerun() | |
| with col2: | |
| if st.button("Continue to Climate Data", key="continue_to_climate"): | |
| # Check if required fields are filled before proceeding | |
| if not st.session_state.project_data["building_info"]["project_name"]: | |
| st.error("Please enter a project name before continuing.") | |
| else: | |
| st.session_state.current_page = "Climate Data" | |
| st.rerun() | |
| def validate_building_info( | |
| project_name: str, | |
| floor_area: float, | |
| building_height: float, | |
| building_type: str, | |
| winter_indoor_design_temp: float, | |
| winter_indoor_design_rh: float, | |
| summer_indoor_design_temp: float, | |
| summer_indoor_design_rh: float, | |
| orientation_angle: int | |
| ) -> List[str]: | |
| """ | |
| Validate building information inputs. | |
| Args: | |
| project_name: Project name | |
| floor_area: Floor area in square meters | |
| building_height: Building height in meters | |
| building_type: Building type | |
| winter_indoor_design_temp: Winter indoor design temperature in °C | |
| winter_indoor_design_rh: Winter indoor design relative humidity in % | |
| summer_indoor_design_temp: Summer indoor design temperature in °C | |
| summer_indoor_design_rh: Summer indoor design relative humidity in % | |
| orientation_angle: Building orientation angle in degrees | |
| Returns: | |
| List of validation error messages, empty if all inputs are valid | |
| """ | |
| errors = [] | |
| # Validate project name | |
| if not project_name or project_name.strip() == "": | |
| errors.append("Project name is required.") | |
| # Validate floor area | |
| if floor_area <= 0: | |
| errors.append("Floor area must be greater than zero.") | |
| elif floor_area > 100000: | |
| errors.append("Floor area exceeds maximum value (100,000 m²).") | |
| # Validate building height | |
| if building_height < 2.0: | |
| errors.append("Building height must be at least 2.0 meters.") | |
| elif building_height > 100.0: | |
| errors.append("Building height exceeds maximum value (100 meters).") | |
| # Validate building type | |
| if building_type not in BUILDING_TYPES: | |
| errors.append("Please select a valid building type.") | |
| # Validate winter indoor design temperature | |
| if winter_indoor_design_temp < 15.0 or winter_indoor_design_temp > 30.0: | |
| errors.append("Winter indoor design temperature must be between 15°C and 30°C.") | |
| # Validate winter indoor design relative humidity | |
| if winter_indoor_design_rh < 20.0 or winter_indoor_design_rh > 80.0: | |
| errors.append("Winter indoor design relative humidity must be between 20% and 80%.") | |
| # Validate summer indoor design temperature | |
| if summer_indoor_design_temp < 15.0 or summer_indoor_design_temp > 30.0: | |
| errors.append("Summer indoor design temperature must be between 15°C and 30°C.") | |
| # Validate summer indoor design relative humidity | |
| if summer_indoor_design_rh < 20.0 or summer_indoor_design_rh > 80.0: | |
| errors.append("Summer indoor design relative humidity must be between 20% and 80%.") | |
| # Validate orientation angle | |
| if orientation_angle < -180 or orientation_angle > 180: | |
| errors.append("Orientation angle must be between -180° and 180°.") | |
| return errors | |
| def display_building_info_help(): | |
| """Display help information for the building information page.""" | |
| st.markdown(""" | |
| ### Building Information Help | |
| This section collects basic information about your building project. The inputs provided here will be used throughout the calculation process. | |
| **Key Parameters:** | |
| * **Project Name**: A unique identifier for your project. | |
| * **Floor Area**: The total conditioned floor area of the building in square meters. | |
| * **Building Height**: The average ceiling height of the building in meters. | |
| * **Building Type**: The primary use of the building, which affects default internal loads. | |
| * **Winter Indoor Design Temperature**: The target indoor temperature for winter season comfort (typically 20-24°C). | |
| * **Winter Indoor Design Relative Humidity**: The target indoor relative humidity for winter season comfort (typically 30-50%). | |
| * **Summer Indoor Design Temperature**: The target indoor temperature for summer season comfort (typically 22-26°C). | |
| * **Summer Indoor Design Relative Humidity**: The target indoor relative humidity for summer season comfort (typically 40-60%). | |
| * **Orientation Angle**: The building's rotation angle relative to north (0°). | |
| **Building Orientation:** | |
| The orientation angle rotates the entire building relative to true north. At 0°, the building facades are aligned with the cardinal directions: | |
| * Facade A: North (0°) | |
| * Facade B: South (180°) | |
| * Facade C: East (90°) | |
| * Facade D: West (270°) | |
| Adjusting the orientation angle will rotate all facades accordingly. | |
| """) | |
| def display_orientation_diagram(): | |
| """Display orientation images showing building orientation.""" | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown( | |
| '<div style="display: flex; justify-content: center; align-items: center; width: 100%; text-align: center; margin: 0 auto;">', | |
| unsafe_allow_html=True | |
| ) | |
| st.image("images/orientation1.jpg", caption="Building Orientation Angle = 0", width=300, use_column_width=False, output_format="auto") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| with col2: | |
| st.markdown( | |
| '<div style="display: flex; justify-content: center; align-items: center; width: 100%; text-align: center; margin: 0 auto;">', | |
| unsafe_allow_html=True | |
| ) | |
| st.image("images/orientation2.jpg", caption="Building Orientation Angle = 45", width=300, use_column_width=False, output_format="auto") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| def calculate_volume(floor_area: float, height: float) -> float: | |
| """ | |
| Calculate the building volume. | |
| Args: | |
| floor_area: Floor area in square meters | |
| height: Building height in meters | |
| Returns: | |
| Building volume in cubic meters | |
| """ | |
| return floor_area * height |