mabuseif commited on
Commit
9bf0764
·
verified ·
1 Parent(s): 61cf626

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +544 -0
main.py ADDED
@@ -0,0 +1,544 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ HVAC Load Calculator - Main Module
3
+
4
+ This is the main module for the HVAC Load Calculator application. It serves as the central
5
+ orchestrator for the application, handling navigation between different modules and managing
6
+ the overall application flow.
7
+
8
+ Developed by: Dr Majed Abuseif, Deakin University
9
+ © 2025
10
+ """
11
+
12
+ import streamlit as st
13
+ import logging
14
+ import os
15
+ import sys
16
+ from typing import Dict, List, Any, Optional, Tuple
17
+
18
+ # Configure logging
19
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
20
+ logger = logging.getLogger(__name__)
21
+
22
+ # Add the current directory to the path so we can import our modules
23
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
24
+
25
+ # Import modules as they are developed
26
+ from intro import display_intro_page
27
+ from building_information import display_building_info_page
28
+ from climate_data import display_climate_page
29
+ from materials_library import display_materials_page
30
+ from construction import display_construction_page
31
+ from components import display_components_page
32
+ from data.internal_loads import display_internal_loads_page
33
+ from hvac_loads import display_hvac_loads_page
34
+ from building_energy import display_building_energy_page
35
+ from renewable_energy import display_renewable_energy_page
36
+ from embodied_energy import display_embodied_energy_page
37
+ from materials_cost import display_materials_cost_page
38
+
39
+ class HVACApp:
40
+ """
41
+ Main class for the HVAC Load Calculator application.
42
+ Handles navigation, session state initialization, and module integration.
43
+ """
44
+
45
+ def __init__(self):
46
+ """
47
+ Initialize the HVAC Load Calculator application.
48
+ Sets up the page configuration and initializes session state if needed.
49
+ """
50
+ # Configure the Streamlit page
51
+ st.set_page_config(
52
+ page_title="HVAC Load Calculator",
53
+ page_icon="🌡️",
54
+ layout="wide",
55
+ initial_sidebar_state="expanded"
56
+ )
57
+
58
+ # Initialize session state if it doesn't exist
59
+ self._initialize_session_state()
60
+
61
+ # Set up the application layout
62
+ self.setup_layout()
63
+
64
+ def _initialize_session_state(self):
65
+ """
66
+ Initialize the session state structure if it doesn't exist.
67
+ This creates the basic structure for storing all application data.
68
+ """
69
+ # Initialize current page if not set
70
+ if 'current_page' not in st.session_state:
71
+ st.session_state.current_page = "Intro"
72
+
73
+ # Initialize project data structure if not set
74
+ if 'project_data' not in st.session_state:
75
+ st.session_state.project_data = {
76
+ "project_name": "",
77
+ "building_info": {
78
+ "project_name": "",
79
+ "floor_area": 100.0,
80
+ "building_height": 3.0,
81
+ "indoor_design_temp": 24.0,
82
+ "indoor_design_rh": 50.0,
83
+ "ventilation_rate": 0.1,
84
+ "orientation_angle": 0.0,
85
+ "operation_hours": 8,
86
+ "building_type": "Office"
87
+ },
88
+ "climate_data": {},
89
+ "materials": {
90
+ "library": {},
91
+ "project": {}
92
+ },
93
+ "fenestrations": {
94
+ "library": {},
95
+ "project": {}
96
+ },
97
+ "constructions": {
98
+ "library": {},
99
+ "project": {}
100
+ },
101
+ "components": {
102
+ "walls": [],
103
+ "roofs": [],
104
+ "floors": [],
105
+ "windows": [],
106
+ "doors": [],
107
+ "skylights": []
108
+ },
109
+ "internal_loads": {
110
+ "people": [],
111
+ "lighting": {},
112
+ "equipment": {}
113
+ },
114
+ "hvac_loads": {
115
+ "cooling": {
116
+ "hourly": [],
117
+ "peak": 0,
118
+ "summary_tables": {},
119
+ "charts": {}
120
+ },
121
+ "heating": {
122
+ "hourly": [],
123
+ "peak": 0,
124
+ "summary_tables": {},
125
+ "charts": {}
126
+ }
127
+ },
128
+ "building_energy": {
129
+ "hvac_type": "",
130
+ "cop": 0.0,
131
+ "energy_consumption": {
132
+ "cooling": 0,
133
+ "heating": 0,
134
+ "lighting": 0,
135
+ "equipment": 0,
136
+ "total": 0
137
+ },
138
+ "charts": {}
139
+ },
140
+ "renewable_energy": {
141
+ "pv_system_size_kw": 0,
142
+ "pv_generation_kwh": 0,
143
+ "net_energy_kwh": 0,
144
+ "zero_energy_status": "",
145
+ "charts": {}
146
+ },
147
+ "embodied_energy": {
148
+ "total_embodied_carbon_kgco2e": 0,
149
+ "breakdown_by_component": {},
150
+ "charts": {}
151
+ },
152
+ "materials_cost": {
153
+ "total_cost_usd": 0,
154
+ "breakdown_by_component": {},
155
+ "charts": {}
156
+ }
157
+ }
158
+
159
+ # Initialize UI state variables
160
+ if 'debug_mode' not in st.session_state:
161
+ st.session_state.debug_mode = False
162
+
163
+ if 'rerun_pending' not in st.session_state:
164
+ st.session_state.rerun_pending = False
165
+
166
+ def setup_layout(self):
167
+ """
168
+ Set up the main application layout with sidebar navigation and main content area.
169
+ """
170
+ # Create the sidebar
171
+ st.sidebar.title("HVAC Load Calculator")
172
+ st.sidebar.markdown("---")
173
+
174
+ # Navigation section in sidebar
175
+ st.sidebar.subheader("Navigation")
176
+
177
+ # Define all available pages
178
+ pages = [
179
+ "Intro",
180
+ "Building Information",
181
+ "Climate Data",
182
+ "Material Library",
183
+ "Construction",
184
+ "Building Components",
185
+ "Internal Loads",
186
+ "HVAC Loads",
187
+ "Building Energy",
188
+ "Renewable Energy",
189
+ "Embodied Energy",
190
+ "Materials Cost"
191
+ ]
192
+
193
+ # Create the navigation radio buttons
194
+ selected_page = st.sidebar.radio(
195
+ "Go to",
196
+ pages,
197
+ index=pages.index(st.session_state.current_page)
198
+ )
199
+
200
+ # Update the current page if changed
201
+ if selected_page != st.session_state.current_page:
202
+ st.session_state.current_page = selected_page
203
+ # Clear any temporary form states when changing pages
204
+ for key in list(st.session_state.keys()):
205
+ if key.endswith("_form_state") or key.endswith("_editor"):
206
+ st.session_state.pop(key, None)
207
+
208
+ # Add application info to sidebar
209
+ st.sidebar.markdown("---")
210
+ st.sidebar.info(
211
+ "HVAC Load Calculator v3.0.0\n\n"
212
+ "Based on ASHRAE CTF/TFM methods\n\n"
213
+ "Developed by: Dr Majed Abuseif\n\n"
214
+ "School of Architecture and Built Environment\n\n"
215
+ "Deakin University\n\n"
216
+ "© 2025"
217
+ )
218
+
219
+ # Add help section to sidebar
220
+ st.sidebar.markdown("### Help")
221
+ st.sidebar.write("Learn about CTF/TFM methods:")
222
+ st.sidebar.markdown("[ASHRAE Handbook](https://www.ashrae.org/technical-resources/bookstore/handbook)")
223
+
224
+ # Debug mode toggle (for development)
225
+ if st.sidebar.checkbox("Debug Mode", value=st.session_state.debug_mode):
226
+ st.session_state.debug_mode = True
227
+ else:
228
+ st.session_state.debug_mode = False
229
+
230
+ # Display the selected page content
231
+ self.display_page(st.session_state.current_page)
232
+
233
+ # Handle any pending reruns (for form submissions that need to refresh)
234
+ if st.session_state.rerun_pending:
235
+ st.session_state.rerun_pending = False
236
+ st.rerun()
237
+
238
+ def display_page(self, page: str):
239
+ """
240
+ Display the content for the selected page by calling the appropriate module function.
241
+
242
+ Args:
243
+ page: The name of the page to display
244
+ """
245
+ if page == "Intro":
246
+ # Call the implemented intro module
247
+ display_intro_page()
248
+ elif page == "Building Information":
249
+ # Call the implemented building information module
250
+ display_building_info_page()
251
+ elif page == "Climate Data":
252
+ # Call the implemented climate data module
253
+ display_climate_page()
254
+ elif page == "Material Library":
255
+ # Call the implemented material library module
256
+ display_materials_page()
257
+ elif page == "Construction":
258
+ # Call the implemented construction module
259
+ display_construction_page()
260
+ elif page == "Building Components":
261
+ # Call the implemented components module
262
+ display_components_page()
263
+ elif page == "Internal Loads":
264
+ # Call the implemented internal loads module
265
+ display_internal_loads_page()
266
+ elif page == "HVAC Loads":
267
+ # Call the implemented HVAC loads module
268
+ display_hvac_loads_page()
269
+ elif page == "Building Energy":
270
+ # Call the implemented building energy module
271
+ display_building_energy_page()
272
+ elif page == "Renewable Energy":
273
+ # Call the implemented renewable energy module
274
+ display_renewable_energy_page()
275
+ elif page == "Embodied Energy":
276
+ # Call the implemented embodied energy module
277
+ display_embodied_energy_page()
278
+ elif page == "Materials Cost":
279
+ # Call the implemented materials cost module
280
+ display_materials_cost_page()
281
+ else:
282
+ st.error(f"Unknown page: {page}")
283
+
284
+ # Placeholder display methods until actual modules are implemented
285
+ def _display_intro_placeholder(self):
286
+ st.info("This is a placeholder for the Intro module. The actual module will be implemented in Stage 2.")
287
+ st.markdown("""
288
+ ### About
289
+ The HVAC Load Calculator is a tool for calculating heating and cooling loads for buildings.
290
+
291
+ ### Features
292
+ - Building information input
293
+ - Climate data selection
294
+ - Material and construction library
295
+ - Component definition
296
+ - Internal loads calculation
297
+ - HVAC load calculation using CTF/TFM methods
298
+ - Building energy consumption estimation
299
+ - Renewable energy sizing
300
+ - Embodied energy calculation
301
+ - Materials cost estimation
302
+
303
+ ### Project Management
304
+ """)
305
+
306
+ col1, col2, col3 = st.columns(3)
307
+ with col1:
308
+ st.button("Start New Project")
309
+ with col2:
310
+ st.file_uploader("Import Project", type=["json"])
311
+ with col3:
312
+ st.button("Export Project")
313
+
314
+ def _display_building_info_placeholder(self):
315
+ st.info("This is a placeholder for the Building Information module. The actual module will be implemented in Stage 3.")
316
+
317
+ with st.form("building_info_form_placeholder"):
318
+ st.text_input("Project Name", value=st.session_state.project_data["building_info"]["project_name"])
319
+ st.number_input("Floor Area (square meters)", value=st.session_state.project_data["building_info"]["floor_area"])
320
+ st.number_input("Building Height (meters)", value=st.session_state.project_data["building_info"]["building_height"])
321
+ st.number_input("Indoor Design Temperature (°C)", value=st.session_state.project_data["building_info"]["indoor_design_temp"])
322
+ st.number_input("Indoor Design Relative Humidity (%)", value=st.session_state.project_data["building_info"]["indoor_design_rh"])
323
+ st.slider("Orientation Angle (°)", min_value=-180, max_value=180, value=int(st.session_state.project_data["building_info"]["orientation_angle"]))
324
+ st.slider("Operation Hours (hours/day)", min_value=0, max_value=24, value=st.session_state.project_data["building_info"]["operation_hours"])
325
+ st.selectbox("Building Type", ["Office", "Classroom", "Retail", "Restaurant", "Hotel", "Hospital", "Residential"])
326
+
327
+ st.form_submit_button("Save")
328
+
329
+ st.button("Continue to Climate Data")
330
+
331
+ def _display_climate_data_placeholder(self):
332
+ st.info("This is a placeholder for the Climate Data module. The actual module will be implemented in Stage 4.")
333
+
334
+ st.file_uploader("Upload EPW File", type=["epw"])
335
+
336
+ st.markdown("### Climate Data Summary")
337
+ st.markdown("Location: Not selected")
338
+ st.markdown("Climate Zone: Not available")
339
+ st.markdown("Design Temperatures: Not available")
340
+
341
+ col1, col2 = st.columns(2)
342
+ with col1:
343
+ st.button("Back to Building Information")
344
+ with col2:
345
+ st.button("Continue to Material Library")
346
+
347
+ def _display_material_library_placeholder(self):
348
+ st.info("This is a placeholder for the Material Library module. The actual module will be implemented in Stage 5.")
349
+
350
+ tab1, tab2 = st.tabs(["Materials", "Fenestrations"])
351
+
352
+ with tab1:
353
+ st.markdown("### Library Materials")
354
+ st.markdown("Material list will appear here")
355
+
356
+ st.markdown("### Project Materials")
357
+ st.markdown("User-defined materials will appear here")
358
+
359
+ st.markdown("### Material Editor")
360
+ st.text_input("Material Name")
361
+ st.selectbox("Category", ["Finishing Materials", "Structural Materials", "Sub-Structural Materials", "Insulation"])
362
+ st.number_input("Thermal Conductivity (W/m·K)", min_value=0.01, value=0.1)
363
+ st.button("Save Material")
364
+
365
+ with tab2:
366
+ st.markdown("### Library Fenestrations")
367
+ st.markdown("Fenestration list will appear here")
368
+
369
+ st.markdown("### Project Fenestrations")
370
+ st.markdown("User-defined fenestrations will appear here")
371
+
372
+ st.markdown("### Fenestration Editor")
373
+ st.text_input("Fenestration Name")
374
+ st.number_input("U-Value (W/m²·K)", min_value=0.1, value=2.8)
375
+ st.number_input("SHGC", min_value=0.0, max_value=1.0, value=0.7)
376
+ st.button("Save Fenestration")
377
+
378
+ col1, col2 = st.columns(2)
379
+ with col1:
380
+ st.button("Back to Climate Data")
381
+ with col2:
382
+ st.button("Continue to Construction")
383
+
384
+ def _display_construction_placeholder(self):
385
+ st.info("This is a placeholder for the Construction module. The actual module will be implemented in Stage 6.")
386
+
387
+ st.markdown("### Library Constructions")
388
+ st.markdown("Construction list will appear here")
389
+
390
+ st.markdown("### Project Constructions")
391
+ st.markdown("User-defined constructions will appear here")
392
+
393
+ st.markdown("### Construction Editor")
394
+ st.text_input("Construction Name")
395
+ st.selectbox("Component Type", ["Wall", "Roof", "Floor"])
396
+ st.markdown("Layer editor will appear here")
397
+ st.button("Save Construction")
398
+
399
+ col1, col2 = st.columns(2)
400
+ with col1:
401
+ st.button("Back to Material Library")
402
+ with col2:
403
+ st.button("Continue to Building Components")
404
+
405
+ def _display_components_placeholder(self):
406
+ st.info("This is a placeholder for the Building Components module. The actual module will be implemented in Stage 7.")
407
+
408
+ tabs = st.tabs(["Walls", "Roofs", "Floors", "Windows", "Doors", "Skylights"])
409
+
410
+ for i, tab in enumerate(tabs):
411
+ with tab:
412
+ st.markdown(f"### {['Walls', 'Roofs', 'Floors', 'Windows', 'Doors', 'Skylights'][i]}")
413
+ st.markdown("Component list will appear here")
414
+ st.button(f"Add New {['Wall', 'Roof', 'Floor', 'Window', 'Door', 'Skylight'][i]}")
415
+
416
+ col1, col2 = st.columns(2)
417
+ with col1:
418
+ st.button("Back to Construction")
419
+ with col2:
420
+ st.button("Continue to Internal Loads")
421
+
422
+ def _display_internal_loads_placeholder(self):
423
+ st.info("This is a placeholder for the Internal Loads module. The actual module will be implemented in Stage 8.")
424
+
425
+ tabs = st.tabs(["People", "Lighting", "Equipment"])
426
+
427
+ with tabs[0]:
428
+ st.number_input("Number of People", min_value=1, value=10)
429
+ st.selectbox("Activity Level", ["Seated, at Rest", "Light Office Work", "Standing, Light Work"])
430
+
431
+ with tabs[1]:
432
+ st.number_input("Lighting Power Density (W/m²)", min_value=0.0, value=10.0)
433
+ st.selectbox("Fixture Type", ["LED", "Fluorescent", "Incandescent"])
434
+
435
+ with tabs[2]:
436
+ st.number_input("Equipment Power Density (W/m²)", min_value=0.0, value=15.0)
437
+
438
+ col1, col2 = st.columns(2)
439
+ with col1:
440
+ st.button("Back to Building Components")
441
+ with col2:
442
+ st.button("Continue to HVAC Loads")
443
+
444
+ def _display_hvac_loads_placeholder(self):
445
+ st.info("This is a placeholder for the HVAC Loads module. The actual module will be implemented in Stage 9.")
446
+
447
+ st.button("Calculate HVAC Loads")
448
+
449
+ st.markdown("### Results")
450
+ st.markdown("Peak Cooling Load: Not calculated")
451
+ st.markdown("Peak Heating Load: Not calculated")
452
+
453
+ st.markdown("### Load Breakdown")
454
+ st.markdown("Charts will appear here")
455
+
456
+ col1, col2 = st.columns(2)
457
+ with col1:
458
+ st.button("Back to Internal Loads")
459
+ with col2:
460
+ st.button("Continue to Building Energy")
461
+
462
+ def _display_building_energy_placeholder(self):
463
+ st.info("This is a placeholder for the Building Energy module. The actual module will be implemented in Stage 10.")
464
+
465
+ st.selectbox("HVAC System Type", ["Heat Pump", "Boiler + Chiller", "VRF", "Other"])
466
+ st.number_input("COP/Efficiency", min_value=0.1, value=3.5)
467
+ st.button("Calculate Energy Consumption")
468
+
469
+ st.markdown("### Results")
470
+ st.markdown("Total Annual Energy Consumption: Not calculated")
471
+
472
+ st.markdown("### Energy Breakdown")
473
+ st.markdown("Charts will appear here")
474
+
475
+ col1, col2 = st.columns(2)
476
+ with col1:
477
+ st.button("Back to HVAC Loads")
478
+ with col2:
479
+ st.button("Continue to Renewable Energy")
480
+
481
+ def _display_renewable_energy_placeholder(self):
482
+ st.info("This is a placeholder for the Renewable Energy module. The actual module will be implemented in Stage 11.")
483
+
484
+ st.markdown("### PV System Sizing")
485
+ st.markdown("Required PV System Size for Net-Zero: Not calculated")
486
+ st.number_input("Custom PV System Size (kWp)", min_value=0.0, value=10.0)
487
+ st.button("Calculate PV Generation")
488
+
489
+ st.markdown("### Results")
490
+ st.markdown("Annual PV Generation: Not calculated")
491
+ st.markdown("Net Energy Consumption: Not calculated")
492
+ st.markdown("Zero Energy Status: Not calculated")
493
+
494
+ st.markdown("### Energy Balance")
495
+ st.markdown("Charts will appear here")
496
+
497
+ col1, col2 = st.columns(2)
498
+ with col1:
499
+ st.button("Back to Building Energy")
500
+ with col2:
501
+ st.button("Continue to Embodied Energy")
502
+
503
+ def _display_embodied_energy_placeholder(self):
504
+ st.info("This is a placeholder for the Embodied Energy module. The actual module will be implemented in Stage 12.")
505
+
506
+ st.button("Calculate Embodied Carbon")
507
+
508
+ st.markdown("### Results")
509
+ st.markdown("Total Embodied Carbon: Not calculated")
510
+
511
+ st.markdown("### Carbon Breakdown")
512
+ st.markdown("Charts will appear here")
513
+
514
+ col1, col2 = st.columns(2)
515
+ with col1:
516
+ st.button("Back to Renewable Energy")
517
+ with col2:
518
+ st.button("Continue to Materials Cost")
519
+
520
+ def _display_materials_cost_placeholder(self):
521
+ st.info("This is a placeholder for the Materials Cost module. The actual module will be implemented in Stage 13.")
522
+
523
+ st.button("Calculate Material Cost")
524
+
525
+ st.markdown("### Results")
526
+ st.markdown("Total Material Cost: Not calculated")
527
+
528
+ st.markdown("### Cost Breakdown")
529
+ st.markdown("Charts will appear here")
530
+
531
+ st.button("Back to Embodied Energy")
532
+
533
+
534
+ # Main entry point
535
+ if __name__ == "__main__":
536
+ try:
537
+ app = HVACApp()
538
+ except Exception as e:
539
+ st.error(f"An error occurred: {str(e)}")
540
+ logger.exception("Application error")
541
+
542
+
543
+ sys.path.append(os.path.join(os.path.dirname(__file__), 'data'))
544
+