| """ |
| Building information input form for HVAC Load Calculator. |
| This module provides the UI components for entering building information. |
| """ |
|
|
| import streamlit as st |
| import pandas as pd |
| import numpy as np |
| from typing import Dict, List, Any, Optional, Tuple |
| import json |
| import os |
|
|
| |
| from data.building_components import Orientation, ComponentType |
|
|
|
|
| class BuildingInfoForm: |
| """Class for building information input form.""" |
| |
| def __init__(self): |
| """Initialize the building information form.""" |
| pass |
| |
| def display(self): |
| """ |
| Display the building information form. |
| This method is called from main.py. |
| """ |
| self.display_building_info_form(st.session_state) |
| |
| @staticmethod |
| def display_building_info_form(session_state: Dict[str, Any]) -> None: |
| """ |
| Display building information input form in Streamlit. |
| |
| Args: |
| session_state: Streamlit session state for storing form data |
| """ |
| st.header("Building Information") |
| |
| |
| if "building_info" not in session_state: |
| session_state["building_info"] = { |
| "project_name": "", |
| "building_name": "", |
| "location": "", |
| "climate_zone": "", |
| "building_type": "", |
| "floor_area": 0.0, |
| "num_floors": 1, |
| "floor_height": 3.0, |
| "orientation": "NORTH", |
| "occupancy": 0, |
| "operating_hours": "8:00-18:00", |
| "design_conditions": { |
| "summer_outdoor_db": 35.0, |
| "summer_outdoor_wb": 25.0, |
| "summer_indoor_db": 24.0, |
| "summer_indoor_rh": 50.0, |
| "winter_outdoor_db": -5.0, |
| "winter_outdoor_rh": 80.0, |
| "winter_indoor_db": 21.0, |
| "winter_indoor_rh": 40.0 |
| } |
| } |
| |
| elif "design_conditions" not in session_state["building_info"]: |
| session_state["building_info"]["design_conditions"] = { |
| "summer_outdoor_db": 35.0, |
| "summer_outdoor_wb": 25.0, |
| "summer_indoor_db": 24.0, |
| "summer_indoor_rh": 50.0, |
| "winter_outdoor_db": -5.0, |
| "winter_outdoor_rh": 80.0, |
| "winter_indoor_db": 21.0, |
| "winter_indoor_rh": 40.0 |
| } |
| |
| |
| default_values = { |
| "project_name": "", |
| "building_name": "", |
| "location": "", |
| "climate_zone": "", |
| "building_type": "", |
| "floor_area": 0.0, |
| "num_floors": 1, |
| "floor_height": 3.0, |
| "orientation": "NORTH", |
| "occupancy": 0, |
| "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 |
| |
| |
| with st.form("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 name of the project" |
| ) |
| |
| session_state["building_info"]["building_name"] = st.text_input( |
| "Building Name", |
| value=session_state["building_info"]["building_name"], |
| help="Enter the name of the building" |
| ) |
| |
| with col2: |
| session_state["building_info"]["location"] = st.text_input( |
| "Location", |
| value=session_state["building_info"]["location"], |
| help="Enter the location of the building (city, country)" |
| ) |
| |
| session_state["building_info"]["climate_zone"] = st.selectbox( |
| "Climate Zone", |
| ["1A", "1B", "2A", "2B", "3A", "3B", "3C", "4A", "4B", "4C", "5A", "5B", "5C", "6A", "6B", "7", "8"], |
| index=4 if session_state["building_info"]["climate_zone"] == "" else |
| ["1A", "1B", "2A", "2B", "3A", "3B", "3C", "4A", "4B", "4C", "5A", "5B", "5C", "6A", "6B", "7", "8"].index(session_state["building_info"]["climate_zone"]), |
| help="Select the ASHRAE climate zone for the building location" |
| ) |
| |
| st.subheader("Building Characteristics") |
| |
| col1, col2, col3 = st.columns(3) |
| |
| 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 type of building" |
| ) |
| |
| with col2: |
| session_state["building_info"]["floor_area"] = st.number_input( |
| "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" |
| ) |
| |
| with col3: |
| session_state["building_info"]["num_floors"] = st.number_input( |
| "Number of Floors", |
| min_value=1, |
| value=int(session_state["building_info"]["num_floors"]), |
| step=1, |
| help="Enter the number of floors in the building" |
| ) |
| |
| col1, col2, col3 = st.columns(3) |
| |
| with col1: |
| session_state["building_info"]["floor_height"] = st.number_input( |
| "Floor Height (m)", |
| min_value=2.0, |
| max_value=10.0, |
| value=float(session_state["building_info"]["floor_height"]), |
| step=0.1, |
| help="Enter the floor-to-floor height in meters" |
| ) |
| |
| with col2: |
| 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 orientation of the building's main facade" |
| ) |
| |
| with col3: |
| session_state["building_info"]["occupancy"] = st.number_input( |
| "Occupancy (people)", |
| min_value=0, |
| value=int(session_state["building_info"]["occupancy"]), |
| step=1, |
| help="Enter the total number of occupants" |
| ) |
| |
| session_state["building_info"]["operating_hours"] = st.text_input( |
| "Operating Hours", |
| value=session_state["building_info"]["operating_hours"], |
| help="Enter the operating hours of the building (e.g., 8:00-18:00)" |
| ) |
| |
| st.subheader("Design Conditions") |
| |
| st.write("Summer Design Conditions") |
| col1, col2, col3, col4 = st.columns(4) |
| |
| with col1: |
| session_state["building_info"]["design_conditions"]["summer_outdoor_db"] = st.number_input( |
| "Outdoor Dry-Bulb (°C)", |
| min_value=-10.0, |
| max_value=50.0, |
| value=float(session_state["building_info"]["design_conditions"]["summer_outdoor_db"]), |
| step=0.5, |
| key="summer_outdoor_db", |
| help="Enter the summer outdoor design dry-bulb temperature" |
| ) |
| |
| with col2: |
| session_state["building_info"]["design_conditions"]["summer_outdoor_wb"] = st.number_input( |
| "Outdoor Wet-Bulb (°C)", |
| min_value=-10.0, |
| max_value=40.0, |
| value=float(session_state["building_info"]["design_conditions"]["summer_outdoor_wb"]), |
| step=0.5, |
| key="summer_outdoor_wb", |
| help="Enter the summer outdoor design wet-bulb temperature" |
| ) |
| |
| with col3: |
| session_state["building_info"]["design_conditions"]["summer_indoor_db"] = st.number_input( |
| "Indoor Dry-Bulb (°C)", |
| min_value=18.0, |
| max_value=30.0, |
| value=float(session_state["building_info"]["design_conditions"]["summer_indoor_db"]), |
| step=0.5, |
| key="summer_indoor_db", |
| help="Enter the summer indoor design dry-bulb temperature" |
| ) |
| |
| with col4: |
| session_state["building_info"]["design_conditions"]["summer_indoor_rh"] = st.number_input( |
| "Indoor RH (%)", |
| min_value=30.0, |
| max_value=70.0, |
| value=float(session_state["building_info"]["design_conditions"]["summer_indoor_rh"]), |
| step=5.0, |
| key="summer_indoor_rh", |
| help="Enter the summer indoor design relative humidity" |
| ) |
| |
| st.write("Winter Design Conditions") |
| col1, col2, col3, col4 = st.columns(4) |
| |
| with col1: |
| session_state["building_info"]["design_conditions"]["winter_outdoor_db"] = st.number_input( |
| "Outdoor Dry-Bulb (°C)", |
| min_value=-40.0, |
| max_value=20.0, |
| value=float(session_state["building_info"]["design_conditions"]["winter_outdoor_db"]), |
| step=0.5, |
| key="winter_outdoor_db", |
| help="Enter the winter outdoor design dry-bulb temperature" |
| ) |
| |
| with col2: |
| session_state["building_info"]["design_conditions"]["winter_outdoor_rh"] = st.number_input( |
| "Outdoor RH (%)", |
| min_value=0.0, |
| max_value=100.0, |
| value=float(session_state["building_info"]["design_conditions"]["winter_outdoor_rh"]), |
| step=5.0, |
| key="winter_outdoor_rh", |
| help="Enter the winter outdoor design relative humidity" |
| ) |
| |
| with col3: |
| session_state["building_info"]["design_conditions"]["winter_indoor_db"] = st.number_input( |
| "Indoor Dry-Bulb (°C)", |
| min_value=18.0, |
| max_value=25.0, |
| value=float(session_state["building_info"]["design_conditions"]["winter_indoor_db"]), |
| step=0.5, |
| key="winter_indoor_db", |
| help="Enter the winter indoor design dry-bulb temperature" |
| ) |
| |
| with col4: |
| session_state["building_info"]["design_conditions"]["winter_indoor_rh"] = st.number_input( |
| "Indoor RH (%)", |
| min_value=20.0, |
| max_value=60.0, |
| value=float(session_state["building_info"]["design_conditions"]["winter_indoor_rh"]), |
| step=5.0, |
| key="winter_indoor_rh", |
| help="Enter the winter indoor design relative humidity" |
| ) |
| |
| |
| submitted = st.form_submit_button("Save Building Information") |
| |
| if submitted: |
| st.success("Building information saved successfully!") |
| |
| |
| total_height = session_state["building_info"]["floor_height"] * session_state["building_info"]["num_floors"] |
| total_volume = session_state["building_info"]["floor_area"] * total_height |
| |
| |
| st.info(f"Total Building Height: {total_height:.1f} m") |
| st.info(f"Total Building Volume: {total_volume:.1f} m³") |
| |
| |
| if "page" in session_state and session_state["page"] == "building_info": |
| session_state["page"] = "climate_data" |
| |
| @staticmethod |
| def validate_building_info(building_info: Dict[str, Any]) -> Tuple[bool, List[str]]: |
| """ |
| Validate building information. |
| |
| Args: |
| building_info: Dictionary with building information |
| |
| Returns: |
| Tuple with validation result (True if valid) and list of error messages |
| """ |
| valid = True |
| errors = [] |
| |
| |
| required_fields = ["project_name", "building_name", "location", "climate_zone", "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: |
| valid = False |
| errors.append("Floor area must be greater than zero") |
| |
| if building_info.get("num_floors", 0) <= 0: |
| valid = False |
| errors.append("Number of floors must be greater than zero") |
| |
| if building_info.get("floor_height", 0) <= 0: |
| valid = False |
| errors.append("Floor height must be greater than zero") |
| |
| |
| design_conditions = building_info.get("design_conditions", {}) |
| |
| if design_conditions.get("summer_indoor_db", 0) >= design_conditions.get("summer_outdoor_db", 0): |
| valid = False |
| errors.append("Summer indoor dry-bulb temperature must be less than outdoor dry-bulb temperature") |
| |
| if design_conditions.get("winter_indoor_db", 0) <= design_conditions.get("winter_outdoor_db", 0): |
| valid = False |
| errors.append("Winter indoor dry-bulb temperature must be greater than outdoor dry-bulb temperature") |
| |
| return valid, errors |
|
|