Spaces:
Sleeping
Sleeping
Update app/hvac_loads.py
Browse files- app/hvac_loads.py +259 -1
app/hvac_loads.py
CHANGED
@@ -760,4 +760,262 @@ class TFMCalculations:
|
|
760 |
load["total_cooling"] = 0
|
761 |
load["total_heating"] = 0
|
762 |
final_loads.append(load)
|
763 |
-
return final_loads
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
760 |
load["total_cooling"] = 0
|
761 |
load["total_heating"] = 0
|
762 |
final_loads.append(load)
|
763 |
+
return final_loads
|
764 |
+
|
765 |
+
def display_hvac_loads_page():
|
766 |
+
"""
|
767 |
+
Display the HVAC Loads page in the Streamlit application.
|
768 |
+
Allows users to configure simulation period, indoor conditions, and HVAC settings,
|
769 |
+
calculates HVAC loads using TFMCalculations, and displays results.
|
770 |
+
"""
|
771 |
+
try:
|
772 |
+
st.header("HVAC Loads")
|
773 |
+
st.markdown("Configure and calculate HVAC loads for the building.")
|
774 |
+
|
775 |
+
# Simulation Period Configuration
|
776 |
+
st.subheader("Simulation Period")
|
777 |
+
sim_type = st.selectbox(
|
778 |
+
"Simulation Type",
|
779 |
+
["Full Year", "From-to", "HDD", "CDD"],
|
780 |
+
key="hvac_sim_type",
|
781 |
+
index=["Full Year", "From-to", "HDD", "CDD"].index(st.session_state.project_data["sim_period"]["type"])
|
782 |
+
)
|
783 |
+
st.session_state.project_data["sim_period"]["type"] = sim_type
|
784 |
+
|
785 |
+
if sim_type == "From-to":
|
786 |
+
col1, col2 = st.columns(2)
|
787 |
+
with col1:
|
788 |
+
start_date = st.date_input(
|
789 |
+
"Start Date",
|
790 |
+
value=st.session_state.project_data["sim_period"]["start_date"] or datetime(2025, 1, 1),
|
791 |
+
key="hvac_start_date"
|
792 |
+
)
|
793 |
+
with col2:
|
794 |
+
end_date = st.date_input(
|
795 |
+
"End Date",
|
796 |
+
value=st.session_state.project_data["sim_period"]["end_date"] or datetime(2025, 12, 31),
|
797 |
+
key="hvac_end_date"
|
798 |
+
)
|
799 |
+
st.session_state.project_data["sim_period"]["start_date"] = start_date
|
800 |
+
st.session_state.project_data["sim_period"]["end_date"] = end_date
|
801 |
+
elif sim_type in ["HDD", "CDD"]:
|
802 |
+
base_temp = st.number_input(
|
803 |
+
"Base Temperature (°C)",
|
804 |
+
min_value=0.0,
|
805 |
+
max_value=40.0,
|
806 |
+
value=st.session_state.project_data["sim_period"]["base_temp"],
|
807 |
+
step=0.1,
|
808 |
+
key="hvac_base_temp"
|
809 |
+
)
|
810 |
+
st.session_state.project_data["sim_period"]["base_temp"] = base_temp
|
811 |
+
|
812 |
+
# Indoor Conditions Configuration
|
813 |
+
st.subheader("Indoor Conditions")
|
814 |
+
indoor_type = st.selectbox(
|
815 |
+
"Indoor Conditions Type",
|
816 |
+
["Fixed", "Time-varying", "Adaptive"],
|
817 |
+
key="hvac_indoor_type",
|
818 |
+
index=["Fixed", "Time-varying", "Adaptive"].index(st.session_state.project_data["indoor_conditions"]["type"])
|
819 |
+
)
|
820 |
+
st.session_state.project_data["indoor_conditions"]["type"] = indoor_type
|
821 |
+
|
822 |
+
if indoor_type == "Fixed":
|
823 |
+
col1, col2 = st.columns(2)
|
824 |
+
with col1:
|
825 |
+
cooling_temp = st.number_input(
|
826 |
+
"Cooling Setpoint Temperature (°C)",
|
827 |
+
min_value=18.0,
|
828 |
+
max_value=30.0,
|
829 |
+
value=st.session_state.project_data["indoor_conditions"]["cooling_setpoint"]["temperature"],
|
830 |
+
step=0.1,
|
831 |
+
key="hvac_cooling_temp"
|
832 |
+
)
|
833 |
+
cooling_rh = st.number_input(
|
834 |
+
"Cooling Setpoint Relative Humidity (%)",
|
835 |
+
min_value=30.0,
|
836 |
+
max_value=70.0,
|
837 |
+
value=st.session_state.project_data["indoor_conditions"]["cooling_setpoint"]["rh"],
|
838 |
+
step=1.0,
|
839 |
+
key="hvac_cooling_rh"
|
840 |
+
)
|
841 |
+
with col2:
|
842 |
+
heating_temp = st.number_input(
|
843 |
+
"Heating Setpoint Temperature (°C)",
|
844 |
+
min_value=16.0,
|
845 |
+
max_value=26.0,
|
846 |
+
value=st.session_state.project_data["indoor_conditions"]["heating_setpoint"]["temperature"],
|
847 |
+
step=0.1,
|
848 |
+
key="hvac_heating_temp"
|
849 |
+
)
|
850 |
+
heating_rh = st.number_input(
|
851 |
+
"Heating Setpoint Relative Humidity (%)",
|
852 |
+
min_value=30.0,
|
853 |
+
max_value=70.0,
|
854 |
+
value=st.session_state.project_data["indoor_conditions"]["heating_setpoint"]["rh"],
|
855 |
+
step=1.0,
|
856 |
+
key="hvac_heating_rh"
|
857 |
+
)
|
858 |
+
st.session_state.project_data["indoor_conditions"]["cooling_setpoint"] = {
|
859 |
+
"temperature": cooling_temp,
|
860 |
+
"rh": cooling_rh
|
861 |
+
}
|
862 |
+
st.session_state.project_data["indoor_conditions"]["heating_setpoint"] = {
|
863 |
+
"temperature": heating_temp,
|
864 |
+
"rh": heating_rh
|
865 |
+
}
|
866 |
+
elif indoor_type == "Time-varying":
|
867 |
+
st.write("Define hourly temperature and RH schedule (0-23 hours):")
|
868 |
+
schedule = []
|
869 |
+
for hour in range(24):
|
870 |
+
with st.container():
|
871 |
+
st.markdown(f"**Hour {hour}**")
|
872 |
+
col1, col2 = st.columns(2)
|
873 |
+
with col1:
|
874 |
+
temp = st.number_input(
|
875 |
+
f"Temperature (°C)",
|
876 |
+
min_value=16.0,
|
877 |
+
max_value=30.0,
|
878 |
+
value=24.0,
|
879 |
+
step=0.1,
|
880 |
+
key=f"hvac_schedule_temp_{hour}"
|
881 |
+
)
|
882 |
+
with col2:
|
883 |
+
rh = st.number_input(
|
884 |
+
f"Relative Humidity (%)",
|
885 |
+
min_value=30.0,
|
886 |
+
max_value=70.0,
|
887 |
+
value=50.0,
|
888 |
+
step=1.0,
|
889 |
+
key=f"hvac_schedule_rh_{hour}"
|
890 |
+
)
|
891 |
+
schedule.append({"hour": hour, "temperature": temp, "rh": rh})
|
892 |
+
st.session_state.project_data["indoor_conditions"]["schedule"] = schedule
|
893 |
+
|
894 |
+
# HVAC Settings Configuration
|
895 |
+
st.subheader("HVAC Settings")
|
896 |
+
col1, col2 = st.columns(2)
|
897 |
+
with col1:
|
898 |
+
start_hour = st.number_input(
|
899 |
+
"Operating Start Hour",
|
900 |
+
min_value=0,
|
901 |
+
max_value=23,
|
902 |
+
value=st.session_state.project_data["hvac_settings"]["operating_hours"][0]["start"],
|
903 |
+
step=1,
|
904 |
+
key="hvac_start_hour"
|
905 |
+
)
|
906 |
+
with col2:
|
907 |
+
end_hour = st.number_input(
|
908 |
+
"Operating End Hour",
|
909 |
+
min_value=0,
|
910 |
+
max_value=23,
|
911 |
+
value=st.session_state.project_data["hvac_settings"]["operating_hours"][0]["end"],
|
912 |
+
step=1,
|
913 |
+
key="hvac_end_hour"
|
914 |
+
)
|
915 |
+
system_type = st.selectbox(
|
916 |
+
"HVAC System Type",
|
917 |
+
["Default", "VAV", "CAV", "VRF"],
|
918 |
+
key="hvac_system_type",
|
919 |
+
index=["Default", "VAV", "CAV", "VRF"].index(st.session_state.project_data["hvac_settings"]["system_type"])
|
920 |
+
)
|
921 |
+
st.session_state.project_data["hvac_settings"]["operating_hours"] = [{"start": start_hour, "end": end_hour}]
|
922 |
+
st.session_state.project_data["hvac_settings"]["system_type"] = system_type
|
923 |
+
|
924 |
+
# Calculate HVAC Loads
|
925 |
+
if st.button("Calculate HVAC Loads"):
|
926 |
+
try:
|
927 |
+
components = st.session_state.project_data["components"]
|
928 |
+
hourly_data = st.session_state.project_data["climate_data"]["hourly_data"]
|
929 |
+
indoor_conditions = st.session_state.project_data["indoor_conditions"]
|
930 |
+
internal_loads = st.session_state.project_data["internal_loads"]
|
931 |
+
building_info = st.session_state.project_data["building_info"]
|
932 |
+
sim_period = st.session_state.project_data["sim_period"]
|
933 |
+
hvac_settings = st.session_state.project_data["hvac_settings"]
|
934 |
+
|
935 |
+
if not hourly_data:
|
936 |
+
st.error("No climate data available. Please configure climate data first.")
|
937 |
+
logger.error("HVAC calculation failed: No climate data available")
|
938 |
+
return
|
939 |
+
elif not any(comp_list for comp_list in components.values()):
|
940 |
+
st.error("No building components defined. Please configure components first.")
|
941 |
+
logger.error("HVAC calculation failed: No building components defined")
|
942 |
+
return
|
943 |
+
else:
|
944 |
+
loads = TFMCalculations.calculate_tfm_loads(
|
945 |
+
components=components,
|
946 |
+
hourly_data=hourly_data,
|
947 |
+
indoor_conditions=indoor_conditions,
|
948 |
+
internal_loads=internal_loads,
|
949 |
+
building_info=building_info,
|
950 |
+
sim_period=sim_period,
|
951 |
+
hvac_settings=hvac_settings
|
952 |
+
)
|
953 |
+
|
954 |
+
# Update session state with results
|
955 |
+
cooling_loads = [load for load in loads if load["total_cooling"] > 0]
|
956 |
+
heating_loads = [load for load in loads if load["total_heating"] > 0]
|
957 |
+
st.session_state.project_data["hvac_loads"]["cooling"]["hourly"] = cooling_loads
|
958 |
+
st.session_state.project_data["hvac_loads"]["heating"]["hourly"] = heating_loads
|
959 |
+
st.session_state.project_data["hvac_loads"]["cooling"]["peak"] = max([load["total_cooling"] for load in cooling_loads], default=0)
|
960 |
+
st.session_state.project_data["hvac_loads"]["heating"]["peak"] = max([load["total_heating"] for load in heating_loads], default=0)
|
961 |
+
|
962 |
+
# Store breakdown
|
963 |
+
cooling_breakdown = {
|
964 |
+
"conduction": sum(load["conduction_cooling"] for load in cooling_loads),
|
965 |
+
"solar": sum(load["solar"] for load in cooling_loads if load["total_cooling"] > 0),
|
966 |
+
"internal": sum(load["internal"] for load in cooling_loads if load["total_cooling"] > 0),
|
967 |
+
"ventilation": sum(load["ventilation_cooling"] for load in cooling_loads),
|
968 |
+
"infiltration": sum(load["infiltration_cooling"] for load in cooling_loads)
|
969 |
+
}
|
970 |
+
heating_breakdown = {
|
971 |
+
"conduction": sum(load["conduction_heating"] for load in heating_loads),
|
972 |
+
"ventilation": sum(load["ventilation_heating"] for load in heating_loads),
|
973 |
+
"infiltration": sum(load["infiltration_heating"] for load in heating_loads)
|
974 |
+
}
|
975 |
+
st.session_state.project_data["hvac_loads"]["cooling"]["breakdown"] = cooling_breakdown
|
976 |
+
st.session_state.project_data["hvac_loads"]["heating"]["breakdown"] = heating_breakdown
|
977 |
+
|
978 |
+
# Display Results
|
979 |
+
st.subheader("HVAC Load Results")
|
980 |
+
st.write(f"Peak Cooling Load: {st.session_state.project_data['hvac_loads']['cooling']['peak']:.2f} kW")
|
981 |
+
st.write(f"Peak Heating Load: {st.session_state.project_data['hvac_loads']['heating']['peak']:.2f} kW")
|
982 |
+
|
983 |
+
# Display Breakdown
|
984 |
+
st.subheader("Cooling Load Breakdown")
|
985 |
+
for key, value in cooling_breakdown.items():
|
986 |
+
st.write(f"{key.capitalize()}: {value:.2f} kW")
|
987 |
+
st.subheader("Heating Load Breakdown")
|
988 |
+
for key, value in heating_breakdown.items():
|
989 |
+
st.write(f"{key.capitalize()}: {value:.2f} kW")
|
990 |
+
|
991 |
+
# Optional: Display Hourly Loads Table in Debug Mode
|
992 |
+
if st.session_state.debug_mode:
|
993 |
+
st.subheader("Hourly Loads (Debug Mode)")
|
994 |
+
hourly_df = []
|
995 |
+
for load in loads:
|
996 |
+
hourly_df.append({
|
997 |
+
"Month": load["month"],
|
998 |
+
"Day": load["day"],
|
999 |
+
"Hour": load["hour"],
|
1000 |
+
"Total Cooling (kW)": load["total_cooling"],
|
1001 |
+
"Total Heating (kW)": load["total_heating"],
|
1002 |
+
"Conduction Cooling (kW)": load["conduction_cooling"],
|
1003 |
+
"Solar (kW)": load["solar"],
|
1004 |
+
"Internal (kW)": load["internal"],
|
1005 |
+
"Ventilation Cooling (kW)": load["ventilation_cooling"],
|
1006 |
+
"Infiltration Cooling (kW)": load["infiltration_cooling"],
|
1007 |
+
"Ventilation Heating (kW)": load["ventilation_heating"],
|
1008 |
+
"Infiltration Heating (kW)": load["infiltration_heating"]
|
1009 |
+
})
|
1010 |
+
st.dataframe(hourly_df)
|
1011 |
+
|
1012 |
+
st.success("HVAC loads calculated successfully.")
|
1013 |
+
logger.info("HVAC loads calculated and stored in session state")
|
1014 |
+
|
1015 |
+
except Exception as e:
|
1016 |
+
st.error(f"Error calculating HVAC loads: {str(e)}")
|
1017 |
+
logger.error(f"HVAC calculation error: {str(e)}")
|
1018 |
+
|
1019 |
+
except Exception as e:
|
1020 |
+
st.error(f"Error rendering HVAC Loads page: {str(e)}")
|
1021 |
+
logger.error(f"HVAC page rendering error: {str(e)}")
|