Spaces:
Sleeping
Sleeping
| """ | |
| Building information input form for HVAC Load Calculator. | |
| This module provides the UI components for entering building information. | |
| Author: Dr Majed Abuseif | |
| Date: March 2025 | |
| Version: 1.0.0 | |
| """ | |
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import pycountry | |
| from typing import Dict, List, Any, Optional, Tuple | |
| import os | |
| # Import data models | |
| from data.building_components import Orientation, ComponentType | |
| class BuildingInfoForm: | |
| """Class for building information input form.""" | |
| def __init__(self): | |
| """Initialize the building information form.""" | |
| self.countries = sorted([country.name for country in pycountry.countries]) | |
| def display(self): | |
| """Display the building information form.""" | |
| self.display_building_info_form(st.session_state) | |
| def display_building_info_form(self, session_state: Dict[str, Any]) -> None: | |
| """Display building information input form in Streamlit.""" | |
| st.header("Building Information") | |
| if "building_info" not in session_state: | |
| session_state["building_info"] = { | |
| "project_name": "", | |
| "building_name": "", | |
| "country": "", | |
| "city": "", | |
| "building_type": "", | |
| "floor_area": 0.0, | |
| "width": 0.0, | |
| "depth": 0.0, | |
| "building_height": 3.0, | |
| "orientation": "NORTH", | |
| "operating_hours": "8:00-18:00" | |
| } | |
| default_values = { | |
| "project_name": "", | |
| "building_name": "", | |
| "country": "", | |
| "city": "", | |
| "building_type": "", | |
| "floor_area": 0.0, | |
| "width": 0.0, | |
| "depth": 0.0, | |
| "building_height": 3.0, | |
| "orientation": "NORTH", | |
| "operating_hours": "8:00-18:00" | |
| } | |
| for key, default_value in default_values.items(): | |
| if key not in session_state["building_info"]: | |
| session_state["building_info"][key] = default_value | |
| if "data_saved" not in session_state: | |
| session_state["data_saved"] = False | |
| with st.form(key="building_info_form"): | |
| st.subheader("Project Information") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| session_state["building_info"]["project_name"] = st.text_input( | |
| "Project Name", | |
| value=session_state["building_info"]["project_name"], | |
| help="Enter the project's identification name" | |
| ) | |
| session_state["building_info"]["building_name"] = st.text_input( | |
| "Building Name", | |
| value=session_state["building_info"]["building_name"], | |
| help="Enter the building's identification name" | |
| ) | |
| with col2: | |
| session_state["building_info"]["country"] = st.selectbox( | |
| "Country", | |
| options=[""] + self.countries, | |
| index=0 if not session_state["building_info"]["country"] else | |
| self.countries.index(session_state["building_info"]["country"]) + 1, | |
| help="Select the building's country location" | |
| ) | |
| session_state["building_info"]["city"] = st.text_input( | |
| "City", | |
| value=session_state["building_info"]["city"], | |
| help="Enter the building's city location" | |
| ) | |
| st.subheader("Building Characteristics") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| session_state["building_info"]["building_type"] = st.selectbox( | |
| "Building Type", | |
| ["Residential", "Office", "Retail", "Educational", "Healthcare", "Industrial", "Other"], | |
| index=1 if session_state["building_info"]["building_type"] == "" else | |
| ["Residential", "Office", "Retail", "Educational", "Healthcare", "Industrial", "Other"].index(session_state["building_info"]["building_type"]), | |
| help="Select the building's purpose or usage type" | |
| ) | |
| with col2: | |
| session_state["building_info"]["building_height"] = st.number_input( | |
| "Building Height (m)", | |
| min_value=2.0, | |
| max_value=1000.0, | |
| value=float(session_state["building_info"]["building_height"]), | |
| step=0.1, | |
| help="Enter the total height of the building in meters" | |
| ) | |
| st.subheader("Building Dimensions") | |
| session_state["building_info"]["floor_area"] = st.number_input( | |
| "Total Floor Area (m²)", | |
| min_value=0.0, | |
| value=float(session_state["building_info"]["floor_area"]), | |
| step=10.0, | |
| help="Enter the total floor area of the building in square meters (optional if width and depth provided)" | |
| ) | |
| # Center the OR using columns | |
| col1, col2, col3 = st.columns([2, 1, 2]) | |
| with col2: | |
| st.markdown("Enter the total floor area above OR the building width and depth below") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| session_state["building_info"]["width"] = st.number_input( | |
| "Width (m)", | |
| min_value=0.0, | |
| value=float(session_state["building_info"]["width"]), | |
| step=1.0, | |
| help="Enter the building's width in meters (optional if area provided)" | |
| ) | |
| with col2: | |
| session_state["building_info"]["depth"] = st.number_input( | |
| "Depth (m)", | |
| min_value=0.0, | |
| value=float(session_state["building_info"]["depth"]), | |
| step=1.0, | |
| help="Enter the building's depth in meters (optional if area provided)" | |
| ) | |
| st.subheader("Building Orientation") | |
| session_state["building_info"]["orientation"] = st.selectbox( | |
| "Building Orientation", | |
| ["NORTH", "NORTHEAST", "EAST", "SOUTHEAST", "SOUTH", "SOUTHWEST", "WEST", "NORTHWEST"], | |
| index=["NORTH", "NORTHEAST", "EAST", "SOUTHEAST", "SOUTH", "SOUTHWEST", "WEST", "NORTHWEST"].index(session_state["building_info"]["orientation"]), | |
| help="Select the direction of the building's main facade" | |
| ) | |
| st.subheader("Operating Hours") | |
| session_state["building_info"]["operating_hours"] = st.text_input( | |
| "Operating Hours", | |
| value=session_state["building_info"]["operating_hours"], | |
| help="Enter the building's daily operating hours (e.g., 8:00-18:00)" | |
| ) | |
| submitted = st.form_submit_button("Save Building Information") | |
| if submitted: | |
| valid, errors = self.validate_building_info(session_state["building_info"]) | |
| if not valid: | |
| for error in errors: | |
| st.error(error) | |
| else: | |
| if session_state["building_info"]["width"] > 0 and session_state["building_info"]["depth"] > 0: | |
| calculated_area = session_state["building_info"]["width"] * session_state["building_info"]["depth"] | |
| if session_state["building_info"]["floor_area"] == 0: | |
| session_state["building_info"]["floor_area"] = calculated_area | |
| total_volume = session_state["building_info"]["floor_area"] * session_state["building_info"]["building_height"] | |
| session_state["save_results"] = { | |
| "success": "Building information saved successfully!", | |
| "area": f"Total Floor Area: {session_state['building_info']['floor_area']:.1f} m²", | |
| "volume": f"Total Building Volume: {total_volume:.1f} m³" | |
| } | |
| session_state["data_saved"] = True | |
| # Display results if they exist | |
| if "save_results" in session_state and session_state["data_saved"]: | |
| st.success(session_state["save_results"]["success"]) | |
| st.info(session_state["save_results"]["area"]) | |
| st.info(session_state["save_results"]["volume"]) | |
| # Proceed button with immediate navigation | |
| if session_state["data_saved"]: | |
| if st.button("Proceed to Climate Data"): | |
| session_state["page"] = "Climate Data" | |
| session_state["data_saved"] = False | |
| if "save_results" in session_state: | |
| del session_state["save_results"] | |
| def validate_building_info(building_info: Dict[str, Any]) -> Tuple[bool, List[str]]: | |
| """Validate building information.""" | |
| valid = True | |
| errors = [] | |
| required_fields = ["project_name", "building_name", "country", "city", "building_type"] | |
| for field in required_fields: | |
| if field not in building_info or not building_info[field]: | |
| valid = False | |
| errors.append(f"Missing required field: {field}") | |
| if building_info.get("floor_area", 0) <= 0 and (building_info.get("width", 0) <= 0 or building_info.get("depth", 0) <= 0): | |
| valid = False | |
| errors.append("Must provide either floor area or both width and depth dimensions") | |
| if building_info.get("building_height", 0) <= 0: | |
| valid = False | |
| errors.append("Building height must be greater than zero") | |
| return valid, errors | |
| if __name__ == "__main__": | |
| form = BuildingInfoForm() | |
| form.display() |