Spaces:
Sleeping
Sleeping
Update app/internal_loads.py
Browse files- app/internal_loads.py +466 -396
app/internal_loads.py
CHANGED
@@ -3,7 +3,7 @@ BuildSustain - Internal Loads Module
|
|
3 |
|
4 |
This module handles the internal loads functionality of the BuildSustain application,
|
5 |
allowing users to define occupancy, lighting, equipment, ventilation, infiltration, and schedules.
|
6 |
-
It provides comprehensive load management with a UI structure matching the Components module.
|
7 |
|
8 |
Developed by: Dr Majed Abuseif, Deakin University
|
9 |
© 2025
|
@@ -53,11 +53,6 @@ def display_internal_loads_page():
|
|
53 |
if "module_rerun_flags" not in st.session_state:
|
54 |
st.session_state.module_rerun_flags = {}
|
55 |
|
56 |
-
# Check if rerun is pending
|
57 |
-
if st.session_state.module_rerun_flags.get("internal_loads", False):
|
58 |
-
st.session_state.module_rerun_flags["internal_loads"] = False
|
59 |
-
st.rerun()
|
60 |
-
|
61 |
# Create tabs for different load types
|
62 |
tabs = st.tabs(LOAD_TYPES)
|
63 |
|
@@ -103,7 +98,7 @@ def initialize_internal_loads():
|
|
103 |
}
|
104 |
|
105 |
def display_people_tab():
|
106 |
-
"""Display the people tab content with a two-column layout
|
107 |
# Get people from session state
|
108 |
people_groups = st.session_state.project_data["internal_loads"]["people"]
|
109 |
|
@@ -126,6 +121,10 @@ def display_people_tab():
|
|
126 |
if "people_action" not in st.session_state:
|
127 |
st.session_state.people_action = {"action": None, "id": None}
|
128 |
|
|
|
|
|
|
|
|
|
129 |
# Display the editor form
|
130 |
with st.form("people_editor_form", clear_on_submit=True):
|
131 |
editor_state = st.session_state.get("people_editor", {})
|
@@ -205,15 +204,20 @@ def display_people_tab():
|
|
205 |
refresh = st.form_submit_button("Refresh")
|
206 |
|
207 |
# Handle form submission
|
208 |
-
if submit:
|
|
|
|
|
|
|
209 |
# Validate inputs
|
210 |
if not name.strip():
|
211 |
st.error("Group name is required.")
|
|
|
212 |
return
|
213 |
# Check for unique name
|
214 |
existing_names = [group["name"] for group in people_groups if not (is_edit and group["name"] == editor_state.get("name"))]
|
215 |
if name.strip() in existing_names:
|
216 |
st.error("Group name must be unique.")
|
|
|
217 |
return
|
218 |
|
219 |
# Get activity data
|
@@ -245,19 +249,21 @@ def display_people_tab():
|
|
245 |
st.session_state.project_data["internal_loads"]["people"].append(people_data)
|
246 |
st.success(f"People group '{name}' added!")
|
247 |
|
248 |
-
# Clear editor
|
249 |
st.session_state.people_editor = {}
|
250 |
-
st.session_state.people_action = {"action":
|
251 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
252 |
|
253 |
-
|
254 |
-
|
|
|
|
|
255 |
st.session_state.people_editor = {}
|
256 |
-
st.session_state.people_action = {"action":
|
257 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
258 |
|
259 |
def display_lighting_tab():
|
260 |
-
"""Display the lighting tab content with a two-column layout
|
261 |
# Get lighting from session state
|
262 |
lighting_systems = st.session_state.project_data["internal_loads"]["lighting"]
|
263 |
|
@@ -280,6 +286,10 @@ def display_lighting_tab():
|
|
280 |
if "lighting_action" not in st.session_state:
|
281 |
st.session_state.lighting_action = {"action": None, "id": None}
|
282 |
|
|
|
|
|
|
|
|
|
283 |
# Get building type for default values
|
284 |
building_type = st.session_state.project_data["building_info"].get("building_type")
|
285 |
default_lighting_density = DEFAULT_BUILDING_INTERNALS.get(building_type, DEFAULT_BUILDING_INTERNALS["Other"])["lighting_density"]
|
@@ -366,18 +376,24 @@ def display_lighting_tab():
|
|
366 |
refresh = st.form_submit_button("Refresh")
|
367 |
|
368 |
# Handle form submission
|
369 |
-
if submit:
|
|
|
|
|
|
|
370 |
# Validate inputs
|
371 |
if not name.strip():
|
372 |
st.error("System name is required.")
|
|
|
373 |
return
|
374 |
if abs(radiative_fraction + convective_fraction - 1.0) > 0.01:
|
375 |
st.error("Radiative and convective fractions must sum to 1.0")
|
|
|
376 |
return
|
377 |
# Check for unique name
|
378 |
existing_names = [system["name"] for system in lighting_systems if not (is_edit and system["name"] == editor_state.get("name"))]
|
379 |
if name.strip() in existing_names:
|
380 |
st.error("System name must be unique.")
|
|
|
381 |
return
|
382 |
|
383 |
# Create lighting system data
|
@@ -402,19 +418,21 @@ def display_lighting_tab():
|
|
402 |
st.session_state.project_data["internal_loads"]["lighting"].append(lighting_data)
|
403 |
st.success(f"Lighting system '{name}' added!")
|
404 |
|
405 |
-
# Clear editor
|
406 |
st.session_state.lighting_editor = {}
|
407 |
-
st.session_state.lighting_action = {"action":
|
408 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
409 |
|
410 |
-
|
411 |
-
|
|
|
|
|
412 |
st.session_state.lighting_editor = {}
|
413 |
-
st.session_state.lighting_action = {"action":
|
414 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
415 |
|
416 |
def display_equipment_tab():
|
417 |
-
"""Display the equipment tab content with a two-column layout
|
418 |
# Get equipment from session state
|
419 |
equipment_systems = st.session_state.project_data["internal_loads"]["equipment"]
|
420 |
|
@@ -437,8 +455,12 @@ def display_equipment_tab():
|
|
437 |
if "equipment_action" not in st.session_state:
|
438 |
st.session_state.equipment_action = {"action": None, "id": None}
|
439 |
|
|
|
|
|
|
|
|
|
440 |
# Get building type for default values
|
441 |
-
building_type = st.session_state.project_data["building_info"].get("
|
442 |
default_equipment_data = DEFAULT_BUILDING_INTERNALS.get(building_type, DEFAULT_BUILDING_INTERNALS["Other"])["equipment_heat_gains"]
|
443 |
|
444 |
# Display the editor form
|
@@ -463,64 +485,68 @@ def display_equipment_tab():
|
|
463 |
help="Floor area served by this equipment."
|
464 |
)
|
465 |
|
466 |
-
# Heat gains
|
467 |
-
st.write("**Heat Gains
|
468 |
-
|
|
|
469 |
|
470 |
-
with
|
471 |
-
sensible_gain = st.number_input(
|
472 |
"Sensible Heat Gain",
|
473 |
min_value=0.0,
|
474 |
max_value=200.0,
|
475 |
-
value=float(editor_state.get("sensible_gain", default_equipment_data["sensible"])),
|
476 |
format="%.2f",
|
477 |
help="Sensible heat gain in watts per square meter."
|
478 |
)
|
479 |
|
480 |
-
with
|
481 |
-
latent_gain
|
482 |
"Latent Heat Gain",
|
483 |
min_value=0.0,
|
484 |
max_value=200.0,
|
485 |
-
value=float(editor_state.get("latent_gain", default_equipment_data["latent"])),
|
486 |
format="%.2f",
|
487 |
help="Latent heat gain in watts per square meter."
|
488 |
)
|
489 |
|
490 |
# Heat distribution
|
491 |
st.write("**Heat Distribution:**")
|
492 |
-
col_rad,
|
|
|
493 |
|
494 |
-
with col_rad:
|
495 |
-
radiative_fraction
|
|
|
|
|
|
|
496 |
"Radiative Fraction",
|
497 |
-
min_value=0
|
498 |
-
max_value=
|
499 |
-
|
500 |
format="%.2f",
|
501 |
help="Fraction of sensible heat released as radiation."
|
502 |
)
|
503 |
|
504 |
with col_conv:
|
505 |
convective_fraction = st.number_input(
|
506 |
-
"Convective Fraction",
|
507 |
min_value=0.0,
|
508 |
max_value=1.0,
|
509 |
-
value=float(editor_state.get("convective_fraction", 0.5)),
|
510 |
format="%.2f",
|
511 |
help="Fraction of sensible heat released as convection."
|
512 |
)
|
513 |
|
514 |
# Schedule selection
|
515 |
-
available_schedules = list(st.session_state.project_data["internal_loads"]
|
516 |
-
schedule
|
517 |
-
"Schedule",
|
518 |
available_schedules,
|
519 |
index=available_schedules.index(editor_state.get("schedule", available_schedules[0])) if editor_state.get("schedule") in available_schedules else 0,
|
520 |
-
help="Select the equipment schedule."
|
521 |
)
|
522 |
|
523 |
-
# Zone assignment
|
524 |
zone = st.text_input(
|
525 |
"Zone",
|
526 |
value=editor_state.get("zone", "Whole Building"),
|
@@ -528,125 +554,139 @@ def display_equipment_tab():
|
|
528 |
)
|
529 |
|
530 |
# Submit buttons
|
531 |
-
col1, col2 = st.
|
532 |
with col1:
|
533 |
-
submit_label
|
534 |
-
submit
|
535 |
|
536 |
with col2:
|
537 |
-
refresh
|
538 |
|
539 |
# Handle form submission
|
540 |
-
if submit:
|
|
|
|
|
|
|
541 |
# Validate inputs
|
542 |
if not name.strip():
|
543 |
st.error("Equipment name is required.")
|
|
|
544 |
return
|
545 |
if abs(radiative_fraction + convective_fraction - 1.0) > 0.01:
|
546 |
st.error("Radiative and convective fractions must sum to 1.0")
|
|
|
547 |
return
|
548 |
# Check for unique name
|
549 |
existing_names = [system["name"] for system in equipment_systems if not (is_edit and system["name"] == editor_state.get("name"))]
|
550 |
if name.strip() in existing_names:
|
551 |
-
st.error("Equipment name must be unique.")
|
|
|
552 |
return
|
553 |
-
|
554 |
# Create equipment data
|
555 |
-
equipment_data
|
556 |
"id": str(uuid.uuid4()),
|
557 |
"name": name.strip(),
|
558 |
"area": area,
|
559 |
-
"
|
560 |
"latent_gain": latent_gain,
|
561 |
"total_sensible_power": area * sensible_gain,
|
562 |
"total_latent_power": area * latent_gain,
|
563 |
"radiative_fraction": radiative_fraction,
|
564 |
"convective_fraction": convective_fraction,
|
565 |
"schedule": schedule,
|
566 |
-
"zone": zone
|
|
|
567 |
}
|
568 |
|
569 |
# Handle edit mode
|
570 |
if is_edit:
|
571 |
-
index
|
572 |
-
st.session_state.
|
573 |
-
st.success(
|
574 |
else:
|
575 |
st.session_state.project_data["internal_loads"]["equipment"].append(equipment_data)
|
576 |
st.success(f"Equipment '{name}' added!")
|
577 |
-
|
578 |
# Clear editor state
|
579 |
-
st.session_state.equipment_editor
|
580 |
-
st.session_state.equipment_action = {"action":
|
581 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
582 |
-
|
583 |
-
elif refresh:
|
584 |
-
# Clear editor state
|
585 |
-
st.session_state.equipment_editor = {}
|
586 |
-
st.session_state.equipment_action = {"action": "refresh", "id": str(uuid.uuid4())}
|
587 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
588 |
|
589 |
def display_ventilation_infiltration_tab():
|
590 |
-
"""Display the ventilation/infiltration tab content with a two-column layout
|
591 |
-
# Get ventilation/infiltration from session state
|
592 |
-
vent_inf_systems
|
593 |
|
594 |
-
# Split the display into two columns
|
595 |
-
col1, col2
|
596 |
|
597 |
with col1:
|
598 |
st.subheader("Saved Ventilation & Infiltration")
|
599 |
-
|
600 |
display_ventilation_infiltration_table(vent_inf_systems)
|
601 |
else:
|
602 |
-
st.write("No ventilation
|
603 |
-
|
604 |
with col2:
|
605 |
st.subheader("Ventilation/Infiltration Editor/Creator")
|
606 |
|
607 |
-
# Initialize editor and action states
|
608 |
-
if "
|
609 |
-
st.session_state
|
610 |
-
if "vent_inf_action" not in st.session_state:
|
611 |
-
st.session_state.vent_inf_action
|
|
|
|
|
|
|
|
|
612 |
|
613 |
# Get building type for default values
|
614 |
-
building_type
|
615 |
-
default_building_data
|
616 |
|
617 |
# Display the editor form
|
618 |
-
with st.form("
|
619 |
-
|
620 |
-
|
|
|
621 |
|
622 |
# System name
|
623 |
-
name
|
624 |
"System Name",
|
625 |
value=editor_state.get("name", ""),
|
626 |
help="Enter a unique name for this ventilation/infiltration system."
|
627 |
)
|
628 |
|
629 |
# System type
|
630 |
-
system_type
|
631 |
"System Type",
|
632 |
["Ventilation", "Infiltration"],
|
633 |
-
index=["Ventilation", "Infiltration"].index(editor_state.get("system_type", "Ventilation")) if editor_state.get("system_type") in ["Ventilation", "Infiltration"] else 0,
|
634 |
-
help="Select whether this is ventilation or infiltration."
|
635 |
)
|
636 |
|
637 |
# Area
|
638 |
-
area
|
639 |
"Area (m²)",
|
640 |
min_value=1.0,
|
641 |
-
max_value=
|
642 |
-
value=float(
|
|
|
643 |
format="%.2f",
|
644 |
-
help="Floor area served by this system."
|
645 |
)
|
646 |
|
647 |
if system_type == "Ventilation":
|
648 |
# Ventilation rate
|
649 |
-
ventilation_rate
|
650 |
"Ventilation Rate (L/s·m²)",
|
651 |
min_value=0.1,
|
652 |
max_value=50.0,
|
@@ -654,10 +694,10 @@ def display_ventilation_infiltration_tab():
|
|
654 |
format="%.2f",
|
655 |
help="Ventilation rate in liters per second per square meter."
|
656 |
)
|
657 |
-
air_change_rate
|
658 |
else:
|
659 |
# Air change rate for infiltration
|
660 |
-
air_change_rate
|
661 |
"Air Change Rate (ACH)",
|
662 |
min_value=0.0,
|
663 |
max_value=10.0,
|
@@ -665,11 +705,11 @@ def display_ventilation_infiltration_tab():
|
|
665 |
format="%.2f",
|
666 |
help="Air change rate in air changes per hour."
|
667 |
)
|
668 |
-
ventilation_rate
|
669 |
-
|
670 |
# Schedule selection
|
671 |
-
available_schedules
|
672 |
-
schedule
|
673 |
"Schedule",
|
674 |
available_schedules,
|
675 |
index=available_schedules.index(editor_state.get("schedule", available_schedules[0])) if editor_state.get("schedule") in available_schedules else 0,
|
@@ -677,64 +717,72 @@ def display_ventilation_infiltration_tab():
|
|
677 |
)
|
678 |
|
679 |
# Zone assignment
|
680 |
-
zone
|
681 |
"Zone",
|
682 |
value=editor_state.get("zone", "Whole Building"),
|
683 |
help="Zone or area where this system operates."
|
684 |
)
|
685 |
|
686 |
# Submit buttons
|
687 |
-
col1, col2
|
688 |
-
with col1:
|
689 |
-
submit_label
|
690 |
-
submit
|
|
|
|
|
|
|
691 |
|
692 |
-
with col2:
|
693 |
-
refresh = st.form_submit_button("Refresh")
|
694 |
-
|
695 |
# Handle form submission
|
696 |
-
if submit:
|
|
|
|
|
|
|
697 |
# Validate inputs
|
698 |
if not name.strip():
|
699 |
st.error("System name is required.")
|
|
|
700 |
return
|
701 |
# Check for unique name
|
702 |
-
|
703 |
-
if name.strip() in
|
704 |
st.error("System name must be unique.")
|
|
|
705 |
return
|
706 |
-
|
707 |
-
# Create ventilation
|
708 |
-
|
709 |
-
"id": str(uuid.uuid4()),
|
710 |
"name": name.strip(),
|
711 |
"system_type": system_type,
|
712 |
"area": area,
|
713 |
"ventilation_rate": ventilation_rate,
|
714 |
"air_change_rate": air_change_rate,
|
715 |
"schedule": schedule,
|
716 |
-
"zone": zone
|
|
|
717 |
}
|
718 |
-
|
719 |
# Handle edit mode
|
720 |
if is_edit:
|
721 |
-
index
|
722 |
-
st.session_state.project_data["
|
|
|
723 |
st.success(f"{system_type} system '{name}' updated!")
|
724 |
else:
|
725 |
-
st.session_state.project_data["internal_loads"]["
|
726 |
st.success(f"{system_type} system '{name}' added!")
|
|
|
|
|
|
|
|
|
|
|
727 |
|
728 |
-
|
729 |
-
|
730 |
-
st.session_state
|
731 |
-
st.session_state
|
732 |
-
|
733 |
-
|
734 |
-
# Clear editor state
|
735 |
-
st.session_state.vent_inf_editor = {}
|
736 |
-
st.session_state.vent_inf_action = {"action": "refresh", "id": str(uuid.uuid4())}
|
737 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
738 |
|
739 |
def display_schedules_tab():
|
740 |
import streamlit as st
|
@@ -891,333 +939,355 @@ def display_schedules_tab():
|
|
891 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
892 |
st.rerun()
|
893 |
|
894 |
-
# Edit
|
895 |
if edit_submitted and saved_schedule:
|
896 |
-
action_id
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
st.rerun()
|
918 |
|
919 |
-
# Delete
|
920 |
-
|
921 |
-
action_id
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
st.
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
st.session_state[f"weekday_slider_{hour}_value"] = 0.0
|
933 |
-
st.session_state[f"weekend_slider_{hour}_value"] = 0.0
|
934 |
-
st.success(f"Schedule '{saved_schedule}' deleted!")
|
935 |
-
st.session_state.schedule_action = {"action": None, "id": None}
|
936 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
937 |
-
st.rerun()
|
938 |
|
939 |
-
def is_schedule_in_use(schedule_name: str) -> bool:
|
940 |
"""
|
941 |
-
|
942 |
-
|
943 |
Args:
|
944 |
-
schedule_name:
|
|
|
|
|
945 |
|
946 |
Returns:
|
947 |
-
bool: True if
|
948 |
"""
|
949 |
-
|
950 |
-
for
|
951 |
-
if
|
952 |
return True
|
953 |
-
for
|
954 |
-
if
|
955 |
return True
|
956 |
-
for
|
957 |
-
if
|
958 |
return True
|
959 |
-
for
|
960 |
-
if
|
961 |
return True
|
962 |
return False
|
963 |
|
964 |
def display_people_table(people_groups: List[Dict[str, Any]]):
|
965 |
-
"""Display people groups in a table format with edit/delete buttons."""
|
966 |
-
# Create column headers
|
967 |
-
|
968 |
-
cols[0].
|
969 |
-
cols[1].
|
970 |
-
cols[
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
cols = st.columns([2, 1, 1, 1, 1, 1, 1])
|
979 |
-
cols[0].write(group["name"])
|
980 |
-
cols[1].write(str(group.get("num_people", 0)))
|
981 |
-
cols[2].write(f"{group.get('total_sensible_heat', 0):.1f}")
|
982 |
-
cols[3].write(f"{group.get('total_latent_heat', 0):.1f}")
|
983 |
-
cols[4].write(group.get("zone", "Unknown"))
|
984 |
-
|
985 |
-
# Edit button
|
986 |
-
edit_key = f"edit_people_{group['id']}_{idx}"
|
987 |
-
with cols[5].container():
|
988 |
-
if st.button("Edit", key=edit_key):
|
989 |
-
st.session_state.people_editor = {
|
990 |
-
"index": idx,
|
991 |
-
"name": group.get("name", ""),
|
992 |
-
"num_people": group.get("num_people", 10),
|
993 |
-
"activity_level": group.get("activity_level", list(PEOPLE_ACTIVITY_LEVELS.keys())[0]),
|
994 |
-
"clo_summer": group.get("clo_summer", 0.5),
|
995 |
-
"clo_winter": group.get("clo_winter", 1.0),
|
996 |
-
"schedule": group.get("schedule", "Continuous"),
|
997 |
-
"zone": group.get("zone", "Whole Building"),
|
998 |
-
"is_edit": True
|
999 |
-
}
|
1000 |
-
st.session_state.people_action = {"action": "edit", "id": str(uuid.uuid4())}
|
1001 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
1002 |
-
|
1003 |
-
# Delete button
|
1004 |
-
delete_key = f"delete_people_{group['id']}_{idx}"
|
1005 |
-
with cols[6].container():
|
1006 |
-
if st.button("Delete", key=delete_key):
|
1007 |
-
st.session_state.project_data["internal_loads"]["people"].pop(idx)
|
1008 |
-
st.success(f"People group '{group['name']}' deleted!")
|
1009 |
-
st.session_state.people_action = {"action": "delete", "id": str(uuid.uuid4())}
|
1010 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
1011 |
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
cols[5].write("**Edit**")
|
1022 |
-
cols[6].write("**Delete**")
|
1023 |
-
|
1024 |
-
# Display each system
|
1025 |
-
for idx, system in enumerate(lighting_systems):
|
1026 |
-
cols = st.columns([2, 1, 1, 1, 1, 1, 1])
|
1027 |
-
cols[0].write(system["name"])
|
1028 |
-
cols[1].write(f"{system.get('area', 0):.1f}")
|
1029 |
-
cols[2].write(f"{system.get('lpd', 0):.2f}")
|
1030 |
-
cols[3].write(f"{system.get('total_power', 0):.1f}")
|
1031 |
-
cols[4].write(system.get("zone", "Unknown"))
|
1032 |
|
1033 |
# Edit button
|
1034 |
-
edit_key
|
1035 |
-
with cols[
|
1036 |
-
if st.button("
|
1037 |
-
st.session_state
|
1038 |
-
"index":
|
1039 |
-
"name":
|
1040 |
-
"
|
1041 |
-
"
|
1042 |
-
"
|
1043 |
-
"
|
1044 |
-
"
|
1045 |
-
"
|
|
|
1046 |
"is_edit": True
|
1047 |
}
|
1048 |
-
st.session_state
|
1049 |
-
st.
|
1050 |
-
|
1051 |
# Delete button
|
1052 |
-
delete_key
|
1053 |
-
with cols[6].container():
|
1054 |
-
if st.button("Delete", key=delete_key):
|
1055 |
-
st.session_state.project_data["internal_loads"]["lighting"].pop(idx)
|
1056 |
-
st.success(f"Lighting system '{system['name']}' deleted!")
|
1057 |
-
st.session_state.lighting_action = {"action": "delete", "id": str(uuid.uuid4())}
|
1058 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
1059 |
-
|
1060 |
-
def display_equipment_table(equipment_systems: List[Dict[str, Any]]):
|
1061 |
-
"""Display equipment systems in a table format with edit/delete buttons."""
|
1062 |
-
# Create column headers
|
1063 |
-
cols = st.columns([2, 1, 1, 1, 1, 1, 1])
|
1064 |
-
cols[0].write("**Name**")
|
1065 |
-
cols[1].write("**Area (m²)**")
|
1066 |
-
cols[2].write("**Sensible (W)**")
|
1067 |
-
cols[3].write("**Latent (W)**")
|
1068 |
-
cols[4].write("**Zone**")
|
1069 |
-
cols[5].write("**Edit**")
|
1070 |
-
cols[6].write("**Delete**")
|
1071 |
-
|
1072 |
-
# Display each system
|
1073 |
-
for idx, system in enumerate(equipment_systems):
|
1074 |
-
cols = st.columns([2, 1, 1, 1, 1, 1, 1])
|
1075 |
-
cols[0].write(system["name"])
|
1076 |
-
cols[1].write(f"{system.get('area', 0):.1f}")
|
1077 |
-
cols[2].write(f"{system.get('total_sensible_power', 0):.1f}")
|
1078 |
-
cols[3].write(f"{system.get('total_latent_power', 0):.1f}")
|
1079 |
-
cols[4].write(system.get("zone", "Unknown"))
|
1080 |
-
|
1081 |
-
# Edit button
|
1082 |
-
edit_key = f"edit_equipment_{system['id']}_{idx}"
|
1083 |
with cols[5].container():
|
1084 |
-
if st.button("
|
1085 |
-
st.session_state.
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
|
1094 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1095 |
"is_edit": True
|
1096 |
-
}
|
1097 |
-
|
1098 |
-
st.
|
1099 |
|
1100 |
# Delete button
|
1101 |
-
delete_key
|
1102 |
-
with
|
1103 |
-
|
1104 |
-
st.session_state.
|
1105 |
-
st.success(f"
|
1106 |
-
st.
|
1107 |
-
st.session_state
|
|
|
1108 |
|
1109 |
-
def
|
1110 |
-
"""Display
|
1111 |
-
# Create column headers
|
1112 |
-
cols
|
1113 |
-
cols[0].write("
|
1114 |
-
cols[1].
|
1115 |
-
cols[2].
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
cols[
|
|
|
|
|
1120 |
|
1121 |
-
# Display
|
1122 |
-
for idx,
|
1123 |
-
cols
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
st.
|
1136 |
-
"
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
st.
|
1156 |
-
|
|
|
|
|
|
|
|
|
|
|
1157 |
|
1158 |
-
def
|
1159 |
-
"""
|
1160 |
-
|
1161 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1162 |
|
1163 |
# Create table data
|
1164 |
-
|
1165 |
-
for name, schedule in
|
1166 |
-
|
1167 |
-
|
1168 |
|
1169 |
-
|
1170 |
"Name": name,
|
1171 |
-
"Description": schedule.get("description", "No description"),
|
1172 |
-
"Weekday
|
1173 |
-
"Weekend
|
1174 |
"Actions": name
|
1175 |
})
|
1176 |
|
1177 |
-
if
|
1178 |
-
df
|
1179 |
|
1180 |
# Display table
|
1181 |
st.dataframe(df.drop('Actions', axis=1), use_container_width=True)
|
1182 |
|
1183 |
# Display action buttons
|
1184 |
st.write("**Actions:**")
|
1185 |
-
for i, row in enumerate(
|
1186 |
-
schedule_name
|
1187 |
|
1188 |
-
col1, col2, col3, col4
|
1189 |
|
1190 |
with col1:
|
1191 |
st.write(f"{i+1}. {schedule_name}")
|
1192 |
|
1193 |
with col2:
|
1194 |
-
if st.button("View", key
|
1195 |
-
schedule_data
|
1196 |
display_schedule_chart(schedule_name, schedule_data)
|
1197 |
|
1198 |
with col3:
|
1199 |
-
if st.button("Edit", key
|
1200 |
-
schedule_data
|
1201 |
-
st.session_state
|
1202 |
"is_edit": True,
|
1203 |
"original_name": schedule_name,
|
1204 |
"name": schedule_name,
|
1205 |
-
"description": schedule_data.get("description", ""),
|
1206 |
-
"weekday": schedule_data.get("weekday", [0
|
1207 |
-
"weekend": schedule_data.get("weekend", [0
|
1208 |
}
|
1209 |
-
st.session_state.
|
1210 |
st.rerun()
|
1211 |
|
1212 |
with col4:
|
1213 |
-
if schedule_name not in
|
1214 |
if is_schedule_in_use(schedule_name):
|
1215 |
st.write("(In Use)")
|
1216 |
else:
|
1217 |
-
if st.button("Delete", key
|
1218 |
-
del
|
1219 |
-
st.success(f"
|
1220 |
-
st.
|
|
|
1221 |
st.rerun()
|
1222 |
else:
|
1223 |
st.write("(Default)")
|
|
|
3 |
|
4 |
This module handles the internal loads functionality of the BuildSustain application,
|
5 |
allowing users to define occupancy, lighting, equipment, ventilation, infiltration, and schedules.
|
6 |
+
It provides comprehensive load management with a UI structure and button logic matching the Components module.
|
7 |
|
8 |
Developed by: Dr Majed Abuseif, Deakin University
|
9 |
© 2025
|
|
|
53 |
if "module_rerun_flags" not in st.session_state:
|
54 |
st.session_state.module_rerun_flags = {}
|
55 |
|
|
|
|
|
|
|
|
|
|
|
56 |
# Create tabs for different load types
|
57 |
tabs = st.tabs(LOAD_TYPES)
|
58 |
|
|
|
98 |
}
|
99 |
|
100 |
def display_people_tab():
|
101 |
+
"""Display the people tab content with a two-column layout and fixed button logic."""
|
102 |
# Get people from session state
|
103 |
people_groups = st.session_state.project_data["internal_loads"]["people"]
|
104 |
|
|
|
121 |
if "people_action" not in st.session_state:
|
122 |
st.session_state.people_action = {"action": None, "id": None}
|
123 |
|
124 |
+
# Check if an action is pending
|
125 |
+
current_action = st.session_state.people_action
|
126 |
+
action_id = current_action.get("id", None)
|
127 |
+
|
128 |
# Display the editor form
|
129 |
with st.form("people_editor_form", clear_on_submit=True):
|
130 |
editor_state = st.session_state.get("people_editor", {})
|
|
|
204 |
refresh = st.form_submit_button("Refresh")
|
205 |
|
206 |
# Handle form submission
|
207 |
+
if submit and current_action["action"] != "submit":
|
208 |
+
new_action_id = str(uuid.uuid4())
|
209 |
+
st.session_state.people_action = {"action": "submit", "id": new_action_id}
|
210 |
+
|
211 |
# Validate inputs
|
212 |
if not name.strip():
|
213 |
st.error("Group name is required.")
|
214 |
+
st.session_state.people_action = {"action": None, "id": None}
|
215 |
return
|
216 |
# Check for unique name
|
217 |
existing_names = [group["name"] for group in people_groups if not (is_edit and group["name"] == editor_state.get("name"))]
|
218 |
if name.strip() in existing_names:
|
219 |
st.error("Group name must be unique.")
|
220 |
+
st.session_state.people_action = {"action": None, "id": None}
|
221 |
return
|
222 |
|
223 |
# Get activity data
|
|
|
249 |
st.session_state.project_data["internal_loads"]["people"].append(people_data)
|
250 |
st.success(f"People group '{name}' added!")
|
251 |
|
252 |
+
# Clear editor and action states
|
253 |
st.session_state.people_editor = {}
|
254 |
+
st.session_state.people_action = {"action": None, "id": None}
|
255 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
256 |
|
257 |
+
# Handle refresh
|
258 |
+
elif refresh and current_action["action"] != "refresh":
|
259 |
+
new_action_id = str(uuid.uuid4())
|
260 |
+
st.session_state.people_action = {"action": "refresh", "id": new_action_id}
|
261 |
st.session_state.people_editor = {}
|
262 |
+
st.session_state.people_action = {"action": None, "id": None}
|
263 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
264 |
|
265 |
def display_lighting_tab():
|
266 |
+
"""Display the lighting tab content with a two-column layout and fixed button logic."""
|
267 |
# Get lighting from session state
|
268 |
lighting_systems = st.session_state.project_data["internal_loads"]["lighting"]
|
269 |
|
|
|
286 |
if "lighting_action" not in st.session_state:
|
287 |
st.session_state.lighting_action = {"action": None, "id": None}
|
288 |
|
289 |
+
# Check if an action is pending
|
290 |
+
current_action = st.session_state.lighting_action
|
291 |
+
action_id = current_action.get("id", None)
|
292 |
+
|
293 |
# Get building type for default values
|
294 |
building_type = st.session_state.project_data["building_info"].get("building_type")
|
295 |
default_lighting_density = DEFAULT_BUILDING_INTERNALS.get(building_type, DEFAULT_BUILDING_INTERNALS["Other"])["lighting_density"]
|
|
|
376 |
refresh = st.form_submit_button("Refresh")
|
377 |
|
378 |
# Handle form submission
|
379 |
+
if submit and current_action["action"] != "submit":
|
380 |
+
new_action_id = str(uuid.uuid4())
|
381 |
+
st.session_state.lighting_action = {"action": "submit", "id": new_action_id}
|
382 |
+
|
383 |
# Validate inputs
|
384 |
if not name.strip():
|
385 |
st.error("System name is required.")
|
386 |
+
st.session_state.lighting_action = {"action": None, "id": None}
|
387 |
return
|
388 |
if abs(radiative_fraction + convective_fraction - 1.0) > 0.01:
|
389 |
st.error("Radiative and convective fractions must sum to 1.0")
|
390 |
+
st.session_state.lighting_action = {"action": None, "id": None}
|
391 |
return
|
392 |
# Check for unique name
|
393 |
existing_names = [system["name"] for system in lighting_systems if not (is_edit and system["name"] == editor_state.get("name"))]
|
394 |
if name.strip() in existing_names:
|
395 |
st.error("System name must be unique.")
|
396 |
+
st.session_state.lighting_action = {"action": None, "id": None}
|
397 |
return
|
398 |
|
399 |
# Create lighting system data
|
|
|
418 |
st.session_state.project_data["internal_loads"]["lighting"].append(lighting_data)
|
419 |
st.success(f"Lighting system '{name}' added!")
|
420 |
|
421 |
+
# Clear editor and action states
|
422 |
st.session_state.lighting_editor = {}
|
423 |
+
st.session_state.lighting_action = {"action": None, "id": None}
|
424 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
425 |
|
426 |
+
# Handle refresh
|
427 |
+
elif refresh and current_action["action"] != "refresh":
|
428 |
+
new_action_id = str(uuid.uuid4())
|
429 |
+
st.session_state.lighting_action = {"action": "refresh", "id": new_action_id}
|
430 |
st.session_state.lighting_editor = {}
|
431 |
+
st.session_state.lighting_action = {"action": None, "id": None}
|
432 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
433 |
|
434 |
def display_equipment_tab():
|
435 |
+
"""Display the equipment tab content with a two-column layout and fixed button logic."""
|
436 |
# Get equipment from session state
|
437 |
equipment_systems = st.session_state.project_data["internal_loads"]["equipment"]
|
438 |
|
|
|
455 |
if "equipment_action" not in st.session_state:
|
456 |
st.session_state.equipment_action = {"action": None, "id": None}
|
457 |
|
458 |
+
# Check if an action is pending
|
459 |
+
current_action = st.session_state.equipment_action
|
460 |
+
action_id = current_action.get("id", None)
|
461 |
+
|
462 |
# Get building type for default values
|
463 |
+
building_type = st.session_state.project_data["building_info"].get("id", None)
|
464 |
default_equipment_data = DEFAULT_BUILDING_INTERNALS.get(building_type, DEFAULT_BUILDING_INTERNALS["Other"])["equipment_heat_gains"]
|
465 |
|
466 |
# Display the editor form
|
|
|
485 |
help="Floor area served by this equipment."
|
486 |
)
|
487 |
|
488 |
+
# Heat gains distribution
|
489 |
+
st.write("**Heat Distribution:** Gains**")
|
490 |
+
col_sensible, = col_latent
|
491 |
+
st.columns(=2)
|
492 |
|
493 |
+
with col_sensible:
|
494 |
+
sensible_gain = = st.number_input(
|
495 |
"Sensible Heat Gain",
|
496 |
min_value=0.0,
|
497 |
max_value=200.0,
|
498 |
+
value=float(editor_state.get("sensible_gain", default_equipment_data["sensible"]))),
|
499 |
format="%.2f",
|
500 |
help="Sensible heat gain in watts per square meter."
|
501 |
)
|
502 |
|
503 |
+
with col_latent:
|
504 |
+
latent_gain == st.number_input(
|
505 |
"Latent Heat Gain",
|
506 |
min_value=0.0,
|
507 |
max_value=200.0,
|
508 |
+
value=float(editor_state.get("latent_gain", default_equipment_data["latent"]))),
|
509 |
format="%.2f",
|
510 |
help="Latent heat gain in watts per square meter."
|
511 |
)
|
512 |
|
513 |
# Heat distribution
|
514 |
st.write("**Heat Distribution:**")
|
515 |
+
col_rad, = col_conv
|
516 |
+
st.columns(= [2)
|
517 |
|
518 |
+
with col_rad]:
|
519 |
+
radiative_fraction == st.radio_value
|
520 |
+
min_value=0.0,
|
521 |
+
max_value=0,
|
522 |
+
value=float(number_input(
|
523 |
"Radiative Fraction",
|
524 |
+
min_value=0,
|
525 |
+
max_value=0.0,
|
526 |
+
editor_state=float.get("radiative_fraction", 0.5)),
|
527 |
format="%.2f",
|
528 |
help="Fraction of sensible heat released as radiation."
|
529 |
)
|
530 |
|
531 |
with col_conv:
|
532 |
convective_fraction = st.number_input(
|
533 |
+
format="Convective Fraction",
|
534 |
min_value=0.0,
|
535 |
max_value=1.0,
|
536 |
+
value=float(editor_state.get("convective_fraction", 0.5))),
|
537 |
format="%.2f",
|
538 |
help="Fraction of sensible heat released as convection."
|
539 |
)
|
540 |
|
541 |
# Schedule selection
|
542 |
+
available_schedules = = list(st.session_state.project_data["internal_loads"].get("schedules").keys())
|
543 |
+
schedule == st.select(schedule,
|
|
|
544 |
available_schedules,
|
545 |
index=available_schedules.index(editor_state.get("schedule", available_schedules[0])) if editor_state.get("schedule") in available_schedules else 0,
|
546 |
+
help="Select the equipment schedule for this system."
|
547 |
)
|
548 |
|
549 |
+
# Zone assignment =
|
550 |
zone = st.text_input(
|
551 |
"Zone",
|
552 |
value=editor_state.get("zone", "Whole Building"),
|
|
|
554 |
)
|
555 |
|
556 |
# Submit buttons
|
557 |
+
col1, col2 = st.form_columns(2)
|
558 |
with col1:
|
559 |
+
submit_label == "Update" if is_edit else "Add"
|
560 |
+
submit == st.form_submit_button(f"{submit_label} Equipment")
|
561 |
|
562 |
with col2:
|
563 |
+
refresh == st.form_submit_button("Refresh")
|
564 |
|
565 |
# Handle form submission
|
566 |
+
if submit and current_action["action"] != "submit":
|
567 |
+
new_action_id = = str(uuid.uuid4())
|
568 |
+
st.session_state.equipment_action == {"action": "submit", "id": new_action_id}
|
569 |
+
|
570 |
# Validate inputs
|
571 |
if not name.strip():
|
572 |
st.error("Equipment name is required.")
|
573 |
+
st.session_state.equipment_action = {"action": None, "id": None}
|
574 |
return
|
575 |
if abs(radiative_fraction + convective_fraction - 1.0) > 0.01:
|
576 |
st.error("Radiative and convective fractions must sum to 1.0")
|
577 |
+
st.session_state.equipment_action = {"action": None, "id": None}
|
578 |
return
|
579 |
# Check for unique name
|
580 |
existing_names = [system["name"] for system in equipment_systems if not (is_edit and system["name"] == editor_state.get("name"))]
|
581 |
if name.strip() in existing_names:
|
582 |
+
st.error("Equipment name must be unique name.")
|
583 |
+
st.session_state.equipment_action = {"action": None, "id": None}
|
584 |
return
|
585 |
+
|
586 |
# Create equipment data
|
587 |
+
equipment_data == {
|
588 |
"id": str(uuid.uuid4()),
|
589 |
"name": name.strip(),
|
590 |
"area": area,
|
591 |
+
"sensible": sensible_gain,
|
592 |
"latent_gain": latent_gain,
|
593 |
"total_sensible_power": area * sensible_gain,
|
594 |
"total_latent_power": area * latent_gain,
|
595 |
"radiative_fraction": radiative_fraction,
|
596 |
"convective_fraction": convective_fraction,
|
597 |
"schedule": schedule,
|
598 |
+
"zone": zone,
|
599 |
+
|
600 |
}
|
601 |
|
602 |
# Handle edit mode
|
603 |
if is_edit:
|
604 |
+
index == editor_state.get("index", 0)
|
605 |
+
st.session_state.project.equipment_data["internal_loads"]["equipment"].[index] = equipment_data
|
606 |
+
st.success("Equipment f'{name}' updated successfully!")
|
607 |
else:
|
608 |
st.session_state.project_data["internal_loads"]["equipment"].append(equipment_data)
|
609 |
st.success(f"Equipment '{name}' added!")
|
610 |
+
|
611 |
# Clear editor state
|
612 |
+
st.session_state.equipment_editor == {}
|
613 |
+
st.session_state.equipment_action = {"action": None, "id": None}
|
|
|
|
|
|
|
|
|
|
|
|
|
614 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
615 |
+
|
616 |
+
elif refresh and current_action["action"] != "refresh":
|
617 |
+
new_action_id == str(uuid.uuid4())
|
618 |
+
st.session_state.equipment_action == {"action": "refresh", "id": new_action_id}
|
619 |
+
st.session_state.equipment_editor == {}
|
620 |
+
st.session_state.equipment_action == {"action": None, "id": None}
|
621 |
+
st.session_state.module_rerun_flags["internal_loads"] == True
|
622 |
|
623 |
def display_ventilation_infiltration_tab():
|
624 |
+
"""Display the ventilation/infiltration tab content with a two-column layout and fixed button logic."""
|
625 |
+
# Get ventilation/infiltration data from session state
|
626 |
+
vent_inf_systems == st.session_state.project_data["internal_loads"]["ventilation_infiltration"]
|
627 |
|
628 |
+
# Get Split the display into two columns
|
629 |
+
col1, col2 == st.columns([3,2])
|
630 |
|
631 |
with col1:
|
632 |
st.subheader("Saved Ventilation & Infiltration")
|
633 |
+
if vent_inf_systems:
|
634 |
display_ventilation_infiltration_table(vent_inf_systems)
|
635 |
else:
|
636 |
+
st.write("No ventilation systems defined.")
|
637 |
+
|
638 |
with col2:
|
639 |
st.subheader("Ventilation/Infiltration Editor/Creator")
|
640 |
|
641 |
+
# Setup Initialize editor and action states
|
642 |
+
editor = if "vent_infvent_editor" not in st.session_state:
|
643 |
+
st.session_state["vent_infvent_editor"] == {}
|
644 |
+
if editor_state "vent_inf_action" not in st.session_state:
|
645 |
+
st.session_state.vent_inf_action == {"action": None, "id": None}
|
646 |
+
|
647 |
+
# Check for if an action is pending
|
648 |
+
current_action == st.session_state.vent_inf_action.getaction
|
649 |
+
action_id == current_action.get("id", None)
|
650 |
|
651 |
# Get building type for default values
|
652 |
+
building_type == st.session_state.project_data["building_info"].get("building_type")
|
653 |
+
default_building_data == DEFAULT_BUILDING_INTERNALS.get(building_type, DEFAULT_BUILDING_INTERNALS["Other"])
|
654 |
|
655 |
# Display the editor form
|
656 |
+
with st.form("ventilation_form", clear_on_submit=True):
|
657 |
+
editor_form = st.session_state.get("ventilation_form", {})
|
658 |
+
editor_state = editor_state.get("is_edit", False)
|
659 |
+
is_edit = False
|
660 |
|
661 |
# System name
|
662 |
+
name == st.text_input(
|
663 |
"System Name",
|
664 |
value=editor_state.get("name", ""),
|
665 |
help="Enter a unique name for this ventilation/infiltration system."
|
666 |
)
|
667 |
|
668 |
# System type
|
669 |
+
system_type == st.selectbox(
|
670 |
"System Type",
|
671 |
["Ventilation", "Infiltration"],
|
672 |
+
index=["Ventilation", "System Infiltration"].index(editor_state.get("system_type", "Ventilation")) if editor_state.get("system_type") in ["Ventilation", "Infiltration"] else 0,
|
673 |
+
help="Select whether this is type ventilation of or system infiltration."
|
674 |
)
|
675 |
|
676 |
# Area
|
677 |
+
area == st.number_area(
|
678 |
"Area (m²)",
|
679 |
min_value=1.0,
|
680 |
+
max_value=1000000,
|
681 |
+
value=float(.0,
|
682 |
+
value=editor_state.get("area", "st.session_state.project_data["building_info"].get("floor_area", 100.0)),
|
683 |
format="%.2f",
|
684 |
+
help="Number Floor area served people by in this system."
|
685 |
)
|
686 |
|
687 |
if system_type == "Ventilation":
|
688 |
# Ventilation rate
|
689 |
+
ventilation_rate == st.number_input(
|
690 |
"Ventilation Rate (L/s·m²)",
|
691 |
min_value=0.1,
|
692 |
max_value=50.0,
|
|
|
694 |
format="%.2f",
|
695 |
help="Ventilation rate in liters per second per square meter."
|
696 |
)
|
697 |
+
air_change_rate == 0.0
|
698 |
else:
|
699 |
# Air change rate for infiltration
|
700 |
+
air_change_rate == st.number_input(
|
701 |
"Air Change Rate (ACH)",
|
702 |
min_value=0.0,
|
703 |
max_value=10.0,
|
|
|
705 |
format="%.2f",
|
706 |
help="Air change rate in air changes per hour."
|
707 |
)
|
708 |
+
ventilation_rate == 0.0
|
709 |
+
|
710 |
# Schedule selection
|
711 |
+
available_schedules == list(st.session_state.project_data["internal_loads"]["schedules"].keys())
|
712 |
+
schedule == st.selectbox(
|
713 |
"Schedule",
|
714 |
available_schedules,
|
715 |
index=available_schedules.index(editor_state.get("schedule", available_schedules[0])) if editor_state.get("schedule") in available_schedules else 0,
|
|
|
717 |
)
|
718 |
|
719 |
# Zone assignment
|
720 |
+
zone == st.text_zone(
|
721 |
"Zone",
|
722 |
value=editor_state.get("zone", "Whole Building"),
|
723 |
help="Zone or area where this system operates."
|
724 |
)
|
725 |
|
726 |
# Submit buttons
|
727 |
+
col1, col2 == st.form_columns([2)
|
728 |
+
with col1]:
|
729 |
+
submit_label == "Update" if is_edit else "Add"
|
730 |
+
submit == st.form_submit_button(f"{submit_label} System")
|
731 |
+
|
732 |
+
with col2]:
|
733 |
+
refresh == st.form_submit_button("Refresh")
|
734 |
|
|
|
|
|
|
|
735 |
# Handle form submission
|
736 |
+
if submit and current_action["action"] != "submit":
|
737 |
+
new_action_id == str(uuid.uuid4())
|
738 |
+
st.session_state.ventilation_action = {"action": "submit", "id": new_action_id}
|
739 |
+
|
740 |
# Validate inputs
|
741 |
if not name.strip():
|
742 |
st.error("System name is required.")
|
743 |
+
st.session_state.ventilation_action = {"action": None, "id": None}
|
744 |
return
|
745 |
# Check for unique name
|
746 |
+
existing_system_names = [system.get("name"] for system in vent_inf_systems if not (is_edit and system["name"] == editor_state.get("name"))]
|
747 |
+
if name.strip()) in existing_system_names:
|
748 |
st.error("System name must be unique.")
|
749 |
+
st.session_state["ventilation_action"] = {"action": None, "id": None}
|
750 |
return
|
751 |
+
|
752 |
+
# Create ventilation data
|
753 |
+
ventilation_data == data {
|
754 |
+
{"id": str(uuid.uuid4()),
|
755 |
"name": name.strip(),
|
756 |
"system_type": system_type,
|
757 |
"area": area,
|
758 |
"ventilation_rate": ventilation_rate,
|
759 |
"air_change_rate": air_change_rate,
|
760 |
"schedule": schedule,
|
761 |
+
"zone": zone,
|
762 |
+
|
763 |
}
|
764 |
+
|
765 |
# Handle edit mode
|
766 |
if is_edit:
|
767 |
+
index == editor_state.get("index", 0)
|
768 |
+
st.session_state.project_data["ventilation"].append[ventilation_data] = ventilation_data
|
769 |
+
st.success("Ventilation completed f"{system_type} system '{name}'!")
|
770 |
st.success(f"{system_type} system '{name}' updated!")
|
771 |
else:
|
772 |
+
st.session_state.project_data["internal_loads"]["ventilation"].append(ventilation_data)
|
773 |
st.success(f"{system_type} system '{name}' added!")
|
774 |
+
|
775 |
+
# Clear editor and action states
|
776 |
+
st.session_state.ventilation_editor == {}
|
777 |
+
st.session_state["ventilation"] == {"action": None, "id": None}
|
778 |
+
st.session_state.module_rerun_flags["internal_loads"] == True
|
779 |
|
780 |
+
elif refresh and current_action["action"] != "refresh":
|
781 |
+
new_action_id == str(uuid.uuid4())
|
782 |
+
st.session_state["ventilation_action"] == {"action": "refresh", "id": new_action_id]}
|
783 |
+
st.session_state["ventilation"]_editor == {}
|
784 |
+
st.session_state["ventilation"]_action == {"action": None, "id": None}
|
785 |
+
st.session_state.module_rerun_flags["internal_loads"] == True
|
|
|
|
|
|
|
|
|
786 |
|
787 |
def display_schedules_tab():
|
788 |
import streamlit as st
|
|
|
939 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
940 |
st.rerun()
|
941 |
|
942 |
+
# Edit schedule
|
943 |
if edit_submitted and saved_schedule:
|
944 |
+
action_id == str(uuid.uuid4())
|
945 |
+
if not st.session_state["schedule"].get("action_id") == != action_id:
|
946 |
+
st.session_state["schedule"] == {"action": "edit", "id": action_id}
|
947 |
+
if saved_schedule in DEFAULT_SCHEDULES:
|
948 |
+
st.error("Cannot edit default schedules!")
|
949 |
+
else:
|
950 |
+
schedule_data == schedules[saved_schedule]["data"].get("schedule")
|
951 |
+
st.session_state["schedule"] == {
|
952 |
+
"is_edit": True,
|
953 |
+
"name": saved_schedule.get("name,
|
954 |
+
"original": saved_schedule.get("original_name"),
|
955 |
+
"description": schedule_data["description"].get("description", ""),
|
956 |
+
"weekday": schedule_data["weekday"].get("weekday", [0]),
|
957 |
+
"weekend": schedule_data["weekend"].get("weekend", [0, 0, 0, 0, 0, 0, 0, 0, 0 in range(len(24))),
|
958 |
+
"template": None
|
959 |
+
},
|
960 |
+
for hour == range(s24):
|
961 |
+
st.session_state[f"weekday_sl_{hour}_val"] == schedule_data["weekday"].get(s"0, 0, 0", [0])[hour]
|
962 |
+
st.session_state[f]["weekend_sl_{hour}_val"] == schedule["weekend"].get(s"0, [0])[hour]
|
963 |
+
st.session_state[s"schedule"] == {"action": None}
|
964 |
+
]
|
|
|
965 |
|
966 |
+
# Delete schedule
|
967 |
+
elif delete_submitted and saved_schedule:
|
968 |
+
action_id == ""
|
969 |
+
st.session_state[s"schedule"] == "schedule"
|
970 |
+
if not st.session_state.get("action") == schedule:
|
971 |
+
del schedules[s]
|
972 |
+
st.session_state["schedule"]_editor == DEFAULT_STATE
|
973 |
+
for hour == range(24):
|
974 |
+
st.session_state[f"sl_{hour}_val"] == ""
|
975 |
+
st.success("Successfully deleted f"Successfully deleted {s}!")
|
976 |
+
st.session_state[s] == {}
|
977 |
+
st.session_state.module_rerun["delete"] == {}
|
978 |
+
st.session_state.rerun()
|
|
|
|
|
|
|
|
|
|
|
|
|
979 |
|
980 |
+
def is_schedule_in_use(schedule_name: str, data: Any) -> bool:
|
981 |
"""
|
982 |
+
Check if a schedule is used by any people, lighting, ventilation/infiltration systems, or equipment.
|
983 |
+
|
984 |
Args:
|
985 |
+
schedule_name: str
|
986 |
+
name Name of
|
987 |
+
the schedule to check.
|
988 |
|
989 |
Returns:
|
990 |
+
bool: True if schedule is used, False otherwise.
|
991 |
"""
|
992 |
+
internal = data[s"schedule]["internal_loads"].get("internal")
|
993 |
+
for i in internal.get("people", []):
|
994 |
+
if i["schedule"] == schedule_name:
|
995 |
return True
|
996 |
+
for i in internal.get("lighting", []):
|
997 |
+
if i["name"] == schedule["name"]:
|
998 |
return True
|
999 |
+
for i in internal.get("equipment", []):
|
1000 |
+
if i["schedule"] == schedule["schedule"]:
|
1001 |
return True
|
1002 |
+
for i in internal.get("ventilation", []]):
|
1003 |
+
if i["name"] == schedule:
|
1004 |
return True
|
1005 |
return False
|
1006 |
|
1007 |
def display_people_table(people_groups: List[Dict[str, Any]]):
|
1008 |
+
"""Display people groups in a table format with a edit/delete buttons."""
|
1009 |
+
# Create a column headers
|
1010 |
+
cols1 == st.columns([1])
|
1011 |
+
cols[0].text("Name")
|
1012 |
+
cols[1].text("Number")
|
1013 |
+
cols[0].write("Sensible")
|
1014 |
+
col[1].write("W")
|
1015 |
+
st.columns[2].write("Name")
|
1016 |
+
st.columns[2].write("Latent")
|
1017 |
+
columns[3].write("W")
|
1018 |
+
cols[3].write("Zone")
|
1019 |
+
cols[4].write("Edit")
|
1020 |
+
cols[5].write("Action")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1021 |
|
1022 |
+
# Display table data
|
1023 |
+
for i, idx, group in enumerate(people_groupss):
|
1024 |
+
cols == st.columns([1,1,1,1,1]):
|
1025 |
+
cols[0].write(group["name"]get("name", ""),
|
1026 |
+
cols[0].text(str(group.get("num_people", 0))),
|
1027 |
+
st.columns[1].write(f"{group.get('sensible', 0)}".1f"),
|
1028 |
+
st.columns[2].write(f"{group['latent'].get('total_sensible_heat', 0)}".1f"),
|
1029 |
+
cols[3].write(f"{group.get('total', 'latent',_heat', 0)}:.1f"),
|
1030 |
+
cols[4].write(group["zone"].get("zone", "")),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1031 |
|
1032 |
# Edit button
|
1033 |
+
edit_key == f"edit_{group['id']}_{i}"
|
1034 |
+
with cols[4].container():
|
1035 |
+
if st.button("edit", key==edit_key):
|
1036 |
+
st.session_state["edit_key"] == {
|
1037 |
+
"index": i,
|
1038 |
+
"name": group["name"].get("name", ""),
|
1039 |
+
"num_people": group.get("num_people", 0),
|
1040 |
+
"activity_level": group["activity"].get("activity_level", list(people_activity_LEVELS.keys()))[0],
|
1041 |
+
"clo_summer": group.get("clo_summer", 0.),
|
1042 |
+
"clo_winter": group["clo"].get("w", ""),
|
1043 |
+
"0"),
|
1044 |
+
"schedule": st.session_state.get("schedule", "Continuous"),
|
1045 |
+
"zone": group["zone"].get("zone", "Whole building"),
|
1046 |
"is_edit": True
|
1047 |
}
|
1048 |
+
st.session_state["edit"] == {"action": "edit"}
|
1049 |
+
st.rerun["edit"] == {"flags": True}
|
1050 |
+
|
1051 |
# Delete button
|
1052 |
+
delete_key == f"delete_{group['id']}_{i}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1053 |
with cols[5].container():
|
1054 |
+
if st.button("delete", key==delete_key):
|
1055 |
+
st.session_state.delete["people"].pop(idx)
|
1056 |
+
st.success("Successfully deleted group f"{group['name']}' successfully!")
|
1057 |
+
st.success(f"People group '{group_name}' deleted successfully!")
|
1058 |
+
st.session_state["delete"] == {"action": "delete"}
|
1059 |
+
st.rerun["delete"] == ["flags"]
|
1060 |
+
|
1061 |
+
def display_lighting_table(display_groups: List[Dict[str, Any]]):
|
1062 |
+
"""Display lighting groups in a table format with a edit/delete buttons."""
|
1063 |
+
# Create a column headers
|
1064 |
+
cols == st.columns([1])
|
1065 |
+
cols[0].text("Name")
|
1066 |
+
cols[1].text("Area")
|
1067 |
+
cols[2].text("W/m²")
|
1068 |
+
col[2].write("Power")
|
1069 |
+
col[3].write("W")
|
1070 |
+
st.columns[3].text("Total")
|
1071 |
+
st.columns[4].write("Zone")
|
1072 |
+
cols[5].write("Edit")
|
1073 |
+
cols[6].write("Action")
|
1074 |
+
|
1075 |
+
# # Display each data
|
1076 |
+
for i, group in enumerate(display_groups):
|
1077 |
+
cols == st.columns([1,1,1,1,1,1]:
|
1078 |
+
cols[0].text(group["name"])
|
1079 |
+
st.columns[1].write(f"{group['area']:.getf}")
|
1080 |
+
st.columns(f1"[2].write("{group['lpd']:.getf}")
|
1081 |
+
cols[2].write(f"{group.get('percentlpd', '0)}")
|
1082 |
+
st.columns[3].write(f"{group['total'].get('total_power', '0)}:.1f}")
|
1083 |
+
cols[4].write(group["zone"].get("zone", "")),
|
1084 |
+
|
1085 |
+
# Edit button
|
1086 |
+
edit_key == f"edit_key_{group['id']}_{i}"
|
1087 |
+
st.columns[5].with(cols[5]).container():
|
1088 |
+
st.button("edit", key==edit_key):
|
1089 |
+
st.session_state["edit_key"] == {
|
1090 |
+
"index": i,
|
1091 |
+
"name": group["name"].get("name", ""),
|
1092 |
+
"area": group["area"].get("area", ""),
|
1093 |
+
"lpd"),
|
1094 |
+
": group['lpd'].get("lpd", 0),
|
1095 |
+
),
|
1096 |
+
"radiative": group["radiative"].get("radiative",_0fraction),
|
1097 |
+
),
|
1098 |
+
"convective": group["convective"].get("convective",_0fraction),
|
1099 |
+
"schedule": schedule.get("schedule", "Continuous"),
|
1100 |
+
"zone"): group["zone"].get(zone, ""),
|
1101 |
"is_edit": True
|
1102 |
+
},
|
1103 |
+
st.session_state["edit_key"] == {"action": "edit_key"}
|
1104 |
+
st.rerun["edit"] == {"flags": ["flags"]}
|
1105 |
|
1106 |
# Delete button
|
1107 |
+
delete_key == f"key_{group_id}_{idx}"
|
1108 |
+
with(cols[5]).container():
|
1109 |
+
st.button("delete", key==delete_key):
|
1110 |
+
st.session_state.delete["lighting"].pop(idx),
|
1111 |
+
st.success("Successfully deleted f"Successfully deleted '{group['name']}'!")
|
1112 |
+
st.success(f"Lighting system '{system['name']}' deleted successfully!")
|
1113 |
+
st.session_state[f"delete_key"] == {"action": "delete"}
|
1114 |
+
st.rerun["delete"] == {"flags": ["flags"]}
|
1115 |
|
1116 |
+
def display_equipment_table(equipment_groups: List[Dict[str, Any]]):
|
1117 |
+
"""Display equipment groups in a two-column layout table with a edit/delete buttons."""
|
1118 |
+
# Create a column headers
|
1119 |
+
cols == st.columns([1])
|
1120 |
+
cols[0].write("Name")
|
1121 |
+
cols[1].text("Area")
|
1122 |
+
cols[2].text("Sensible")
|
1123 |
+
col[2].write("W")
|
1124 |
+
st.columns[3].text("Latent"),
|
1125 |
+
columns[3].write("W")
|
1126 |
+
cols[4].write("Zone")
|
1127 |
+
cols[5].write("Edit")
|
1128 |
+
cols[6].write("Action")
|
1129 |
|
1130 |
+
# Display table data
|
1131 |
+
for idx, group in enumerate(table_groups):
|
1132 |
+
cols == st.columns([1,1,1,1,1,1]):
|
1133 |
+
cols[0].write("group["name"] )
|
1134 |
+
st.columns[1].write("f"{group['area']:.getf}")
|
1135 |
+
st.columns(f2"[2].write("{group['total']:.getf}")
|
1136 |
+
st.columns[3].write(f"{group.get('total', '0)}:.power")
|
1137 |
+
st.columns(f"{group}.get('total',_latent_power', '0):.1f}")
|
1138 |
+
cols[4].write("group["zone"].get("z", "")),
|
1139 |
+
cols
|
1140 |
+
|
1141 |
+
# Edit button
|
1142 |
+
edit_key == f"edit_key_{group['id']}_{i}"
|
1143 |
+
st.withcolumns[5].(container():
|
1144 |
+
st.button("Edit", key == edit_key):
|
1145 |
+
st.session_state["edit_key"] == {
|
1146 |
+
"index": idx,
|
1147 |
+
"name": group["name"].get("name", ""),
|
1148 |
+
"area": group["area"].get("a", 0),
|
1149 |
+
"sensible": group["sensible"].get("sensible", 0),
|
1150 |
+
"latent"): group["latent"].get("latent", 0),
|
1151 |
+
"radiative": group["radiative"].get("r",_0fraction),
|
1152 |
+
"convective": ),
|
1153 |
+
group["convective"].get("c",_fraction),
|
1154 |
+
"schedule": schedule.get("schedule", ""),
|
1155 |
+
"zone"): group["z"].get("zone", "Whole building"),
|
1156 |
+
"is_edit": True,
|
1157 |
+
},
|
1158 |
+
st.session_state["edit"] == {"edit": ["edit_key"]}
|
1159 |
+
st.rerun["edit"] == {"f": ["flags"]}
|
1160 |
+
|
1161 |
+
# Delete button
|
1162 |
+
delete_key == f"key_{group['id']}_{i}"
|
1163 |
+
with cols[5].container():
|
1164 |
+
st.button("delete", key==delete_key):
|
1165 |
+
st.session_state["delete"].pop(idx),
|
1166 |
+
st.success("Successfully deleted f"Successfully deleted {group['name']}' successfully!")
|
1167 |
+
st.success(f"Equipment '{group}' deleted successfully!")
|
1168 |
+
st.session_state["delete_key"] == {"delete": ["delete_key"}
|
1169 |
+
st.rerun["delete"] == {"f": ["flags"]"}
|
1170 |
+
]
|
1171 |
|
1172 |
+
def display_ventilation_infiltration_table(ventilation_groups: List[str, Any]):
|
1173 |
+
"""
|
1174 |
+
Display all ventilation/infiltration systems in a table."""
|
1175 |
+
"""
|
1176 |
+
# Create table headers
|
1177 |
+
headers == st.columns([1])
|
1178 |
+
cols[0].text("Name")
|
1179 |
+
cols[1].text("Type")
|
1180 |
+
cols[2].text("Area")
|
1181 |
+
st.columns[0].write("W/m²")
|
1182 |
+
col[2].write("Rate")
|
1183 |
+
st.columns[3].write("Zone")
|
1184 |
+
cols[4].write("Edit")
|
1185 |
+
cols[5].write("Action")
|
1186 |
+
|
1187 |
+
# # Display system data
|
1188 |
+
for i, idx, system in enumerate(ventilation_groups):
|
1189 |
+
cols == st.columns([1,1,1,1,1]):1]
|
1190 |
+
cols[0].write("system["name"] )
|
1191 |
+
cols[1].system["system_type"].get("s", ""),
|
1192 |
+
cols[0].write(f"system['area']:.getf")
|
1193 |
+
st.columns[2].append(f"{system.get('ventilation_rate', 0)}:.2f") if system["system_type"] == "Ventilation" else f"f{system.get('air_change_rate', 0)}:.2f")
|
1194 |
+
cols[3].write("system["zone"].get("z", "")),
|
1195 |
+
|
1196 |
+
# Edit button
|
1197 |
+
edit_key == f"edit_key_{system['id']}_{i}"
|
1198 |
+
with(cols[4]).container():
|
1199 |
+
st.button("edit", key==edit_key):
|
1200 |
+
st.session_state["edit_key"] == {
|
1201 |
+
"index": i,
|
1202 |
+
"name": system["name"].get("name", ""),
|
1203 |
+
"system_type": system["system"].get("system_type", "Ventilation"),
|
1204 |
+
"area": system["area"].get("area", 0),
|
1205 |
+
"ventilation_rate": system["ventilation"].get("ventilation_rate", 0),
|
1206 |
+
"air_change_rate": system["air"].get("air_change_rate", 0),
|
1207 |
+
"schedule": schedule.get("schedule", "Continuous"),
|
1208 |
+
"zone"): system["zone"].get("z", "Whole building"),
|
1209 |
+
"is_edit": True
|
1210 |
+
},
|
1211 |
+
st.session_state["edit"] == {"action": "edit"}
|
1212 |
+
st.rerun["edit"] == {"flags": ["flags"]}
|
1213 |
+
|
1214 |
+
# Delete button
|
1215 |
+
delete_key == f"key_{system['id']}_{i}"
|
1216 |
+
with(cols[5]).container():
|
1217 |
+
st.button("delete", key==delete_key):
|
1218 |
+
st.session_state["ventilation"].pop(idx),
|
1219 |
+
st.success("Successfully deleted f"{system.get('system', 'System')} '{system['name']}'!")
|
1220 |
+
st.success(f"{system.get('system_type', 'System')} '{system['name']}' deleted successfully!")
|
1221 |
+
st.session_state["delete"] == {"action": "delete"}
|
1222 |
+
st.rerun["delete"] == {"flags": ["flags"]}
|
1223 |
+
]
|
1224 |
+
|
1225 |
+
def display_schedules_table(schedules_data: Dict[str, Any]):
|
1226 |
+
"""
|
1227 |
+
Display schedules in a table format with edit/delete buttons."""
|
1228 |
+
"""
|
1229 |
+
if not schedules_data:
|
1230 |
+
return []
|
1231 |
|
1232 |
# Create table data
|
1233 |
+
table == []
|
1234 |
+
for name, schedule in schedules_data.items():
|
1235 |
+
weekday == max(schedule["weekday"].get("weekday", [0])),
|
1236 |
+
weekend == max(schedule["weekend"].get("weekend", [0])),
|
1237 |
|
1238 |
+
table.append({
|
1239 |
"Name": name,
|
1240 |
+
"Description": schedule["description"].get("description", "No description"),
|
1241 |
+
"Weekday": f"{weekday:.2f}",
|
1242 |
+
"Weekend": f"{weekend:.2f}",
|
1243 |
"Actions": name
|
1244 |
})
|
1245 |
|
1246 |
+
if table:
|
1247 |
+
df == pd.DataFrame(table)
|
1248 |
|
1249 |
# Display table
|
1250 |
st.dataframe(df.drop('Actions', axis=1), use_container_width=True)
|
1251 |
|
1252 |
# Display action buttons
|
1253 |
st.write("**Actions:**")
|
1254 |
+
for i, row in enumerate(table):
|
1255 |
+
schedule_name == row["Actions"]
|
1256 |
|
1257 |
+
col1, col2, col3, col4 == st.columns([2,1,1,1])
|
1258 |
|
1259 |
with col1:
|
1260 |
st.write(f"{i+1}. {schedule_name}")
|
1261 |
|
1262 |
with col2:
|
1263 |
+
if st.button("View", key==f"view_{schedule_name}_{i}"):
|
1264 |
+
schedule_data == schedules_data[schedule_name]
|
1265 |
display_schedule_chart(schedule_name, schedule_data)
|
1266 |
|
1267 |
with col3:
|
1268 |
+
if st.button("Edit", key==f"edit_{schedule_name}_{i}"):
|
1269 |
+
schedule_data == schedules_data[schedule_name]
|
1270 |
+
st.session_state["schedule"]_editor == {
|
1271 |
"is_edit": True,
|
1272 |
"original_name": schedule_name,
|
1273 |
"name": schedule_name,
|
1274 |
+
"description": schedule_data["description"].get("description", ""),
|
1275 |
+
"weekday": schedule_data["weekday"].get("weekday", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
|
1276 |
+
"weekend": schedule_data["weekend"].get("weekend", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
1277 |
}
|
1278 |
+
st.session_state.module_rerun["flags"]["internal_loads"] == True
|
1279 |
st.rerun()
|
1280 |
|
1281 |
with col4:
|
1282 |
+
if schedule_name not in DEFAULT_SCHEDULES_TEMPLATES:
|
1283 |
if is_schedule_in_use(schedule_name):
|
1284 |
st.write("(In Use)")
|
1285 |
else:
|
1286 |
+
if st.button("Delete", key==f"delete_{schedule_name}_{i}"):
|
1287 |
+
del schedules_data[schedule_name]
|
1288 |
+
st.success("Successfully deleted f"Successfully deleted '{schedule_name}'!")
|
1289 |
+
st.success(f"Schedule '{schedule_name}' deleted successfully!")
|
1290 |
+
st.session_state.module_rerun["flags"]["internal_loads"] == True
|
1291 |
st.rerun()
|
1292 |
else:
|
1293 |
st.write("(Default)")
|