""" BuildSustain - Introduction Module This module handles the introduction page of the BuildSustain application, including application information, instructions, and project management functionality (new project, import, export). Developed by: Dr Majed Abuseif, Deakin University © 2025 """ import streamlit as st import json import base64 import io import logging from datetime import datetime from typing import Dict, Any, Optional # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def display_intro_page(): """ Display the introduction page with app information, instructions, and project management options. This is the main function called by main.py when the Intro page is selected. """ st.title("BuildSustain") # Create tabs for different sections of the intro page tab1, tab2, tab3 = st.tabs(["About", "Instructions", "Project Management"]) # About tab content with tab1: display_about_section() # Instructions tab content with tab2: display_instructions_section() # Project Management tab content with tab3: display_project_management_section() def display_about_section(): """Display information about the application, its purpose, and developers.""" st.header("About BuildSustain") st.markdown(""" ### Overview BuildSustain is a web-based tool developed by Dr. Majed Abuseif at Deakin University’s School of Architecture and Built Environment. It enables students and professionals to perform energy simulations, calculate heating and cooling loads using ASHRAE-standard methods, and analyze embodied energy and material costs for sustainable building design. ### Purpose Designed as a learning platform, BuildSustain helps users understand building physics, apply industry-standard calculations, and explore sustainable design strategies. It bridges theoretical concepts with practical applications, preparing users for careers in architecture, engineering, and sustainability. ### Key Features - **Energy Simulations**: Calculate HVAC loads using ASHRAE Transfer Function Method (TFM) and Conduction Transfer Function (CTF). - **Sustainability Analysis**: Estimate embodied carbon, renewable energy options, and material costs. - **Climate Resilience**: Model future climate scenarios with RCP projections. - **User-Friendly Interface**: Intuitive navigation for students to experiment with design parameters. ### Version Beta Version 0.4.1 (2025) For detailed guidance, refer to the [BuildSustain User Guide](BuildSustain_Student_User_Guide.markdown). """) def display_instructions_section(): """Display instructions on how to use the application.""" st.header("Instructions") st.markdown(""" ### Getting Started BuildSustain is a step-by-step tool for sustainable building design. Follow the sidebar navigation to progress through the modules in order: 1. **Start a Project**: Use the Project Management tab to create a new project or import an existing one. 2. **Enter Building Information**: Define project name, building type, dimensions, and indoor conditions. 3. **Manage Climate Data**: Upload an EPW file or select a future climate projection. 4. **Define Materials and Fenestrations**: Use or customize material and window properties. 5. **Create Constructions**: Build multi-layer assemblies for walls, roofs, and floors. 6. **Add Building Components**: Specify envelope elements like walls, windows, and skylights. 7. **Set Internal Loads**: Define occupant, lighting, and equipment heat gains with schedules. 8. **Calculate HVAC Loads**: Run simulations to analyze heating and cooling requirements. ### Navigation - Use the sidebar to access modules (e.g., Building Information, HVAC Loads). - Follow “Back” and “Continue” buttons to move sequentially. - Save progress using the Project Management tab (export as JSON). ### Learning Tips - Experiment with inputs (e.g., insulation thickness, window SHGC) to see their impact on energy loads. - Review the [BuildSustain User Guide](BuildSustain_Student_User_Guide.markdown) for detailed steps and equations. - Use the ASHRAE Handbook link in the sidebar for reference. ### Key Methods BuildSustain uses ASHRAE-approved methods: - **Conduction Transfer Function (CTF)**: For heat transfer through opaque surfaces. - **Transfer Function Method (TFM)**: For HVAC load calculations. - **Solar Heat Gain**: For dynamic fenestration analysis. - **Adaptive Comfort**: For energy-efficient indoor condition settings. """) def display_project_management_section(): """Display project management options (new, import, export).""" st.header("Project Management") col1, col2, col3 = st.columns(3) # Start New Project button with col1: if st.button("Start New Project", key="start_new_project"): start_new_project() st.success("New project initialized. Navigate to Building Information to begin.") # Import Project section with col2: uploaded_file = st.file_uploader("Import Project", type=["json"], key="import_project") if uploaded_file is not None: if load_project(uploaded_file): st.success("Project imported successfully!") else: st.error("Failed to import project. The file may be corrupted or in an incorrect format.") # Export Project button with col3: if st.button("Export Project", key="export_project"): if st.session_state.project_data.get("project_name"): export_project() else: st.warning("Please enter a project name in the Building Information section before exporting.") def start_new_project(): """Initialize a new project by resetting the project_data in session state.""" # Keep a backup of the current project data in case user wants to recover if 'project_data_backup' not in st.session_state: st.session_state.project_data_backup = {} # Only backup if there's actual project data if st.session_state.project_data.get("project_name"): backup_timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") st.session_state.project_data_backup[backup_timestamp] = st.session_state.project_data.copy() # Reset project data to default values st.session_state.project_data = { "project_name": "", "building_info": { "project_name": "", "floor_area": 100.0, "building_height": 3.0, "indoor_design_temp": 24.0, "indoor_design_rh": 50.0, "ventilation_rate": 0.1, "orientation_angle": 0.0, "operation_hours": 8, "building_type": "Office" }, "climate_data": {}, "materials": { "library": {}, "project": {} }, "fenestrations": { "library": {}, "project": {} }, "constructions": { "library": {}, "project": {} }, "components": { "walls": [], "roofs": [], "floors": [], "windows": [], "doors": [], "skylights": [] }, "internal_loads": { "people": [], "lighting": {}, "equipment": {} }, "hvac_loads": { "cooling": { "hourly": [], "peak": 0, "summary_tables": {}, "charts": {} }, "heating": { "hourly": [], "peak": 0, "summary_tables": {}, "charts": {} } }, "building_energy": { "hvac_type": "", "cop": 0.0, "energy_consumption": { "cooling": 0, "heating": 0, "lighting": 0, "equipment": 0, "total": 0 }, "charts": {} }, "renewable_energy": { "pv_system_size_kw": 0, "pv_generation_kwh": 0, "net_energy_kwh": 0, "zero_energy_status": "", "charts": {} }, "embodied_energy": { "total_embodied_carbon_kgco2e": 0, "breakdown_by_component": {}, "charts": {} }, "materials_cost": { "total_cost_usd": 0, "breakdown_by_component": {}, "charts": {} } } logger.info("New project initialized") def load_project(uploaded_file) -> bool: """ Load a project from an uploaded JSON file. Args: uploaded_file: The uploaded file object from st.file_uploader Returns: bool: True if project was loaded successfully, False otherwise """ try: # Read the uploaded file content = uploaded_file.read() project_data = json.loads(content) # Validate the project data structure if not validate_project_data(project_data): logger.error("Invalid project data structure") return False # Keep a backup of the current project data if 'project_data_backup' not in st.session_state: st.session_state.project_data_backup = {} # Only backup if there's actual project data if st.session_state.project_data.get("project_name"): backup_timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") st.session_state.project_data_backup[backup_timestamp] = st.session_state.project_data.copy() # Update session state with the loaded project data st.session_state.project_data = project_data logger.info(f"Project '{project_data.get('project_name', 'Unnamed')}' loaded successfully") return True except Exception as e: logger.error(f"Error loading project: {str(e)}") return False def validate_project_data(project_data: Dict[str, Any]) -> bool: """ Validate the structure of the project data. Args: project_data: The project data dictionary to validate Returns: bool: True if the project data structure is valid, False otherwise """ # Check for required top-level keys required_keys = [ "building_info", "climate_data", "materials", "fenestrations", "constructions", "components", "internal_loads", "hvac_loads", "building_energy", "renewable_energy", "embodied_energy", "materials_cost" ] for key in required_keys: if key not in project_data: logger.error(f"Missing required key in project data: {key}") return False # Check building_info structure building_info_keys = [ "project_name", "floor_area", "building_height", "indoor_design_temp", "indoor_design_rh", "orientation_angle", "operation_hours", "building_type" ] for key in building_info_keys: if key not in project_data["building_info"]: logger.error(f"Missing required key in building_info: {key}") return False # Check components structure component_types = ["walls", "roofs", "floors", "windows", "doors", "skylights"] for component_type in component_types: if component_type not in project_data["components"]: logger.error(f"Missing component type in components: {component_type}") return False # Check hvac_loads structure for load_type in ["cooling", "heating"]: if load_type not in project_data["hvac_loads"]: logger.error(f"Missing load type in hvac_loads: {load_type}") return False return True def export_project(): """Export the current project as a downloadable JSON file.""" try: # Convert project data to JSON project_json = json.dumps(st.session_state.project_data, indent=2) # Generate filename based on project name project_name = st.session_state.project_data.get("project_name", "unnamed_project") safe_project_name = "".join(c if c.isalnum() else "_" for c in project_name) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"{safe_project_name}_{timestamp}.json" # Create a download button for the JSON file st.download_button( label="Download Project File", data=project_json, file_name=filename, mime="application/json", key="download_project" ) logger.info(f"Project '{project_name}' exported as {filename}") except Exception as e: st.error(f"Error exporting project: {str(e)}") logger.error(f"Error exporting project: {str(e)}") # Helper function to create a download link (alternative to st.download_button) def get_download_link(data, filename, link_text): """ Generate a download link for a file. Args: data: The data to be downloaded filename: The name of the file link_text: The text to display for the download link Returns: str: HTML link for downloading the file """ b64 = base64.b64encode(data.encode()).decode() href = f'{link_text}' return href