mabuseif commited on
Commit
625d246
·
verified ·
1 Parent(s): 07614b6

Update app/hvac_loads.py

Browse files
Files changed (1) hide show
  1. app/hvac_loads.py +84 -45
app/hvac_loads.py CHANGED
@@ -810,42 +810,53 @@ def make_pie(data: Dict[str, float], title: str) -> px.pie:
810
  return fig
811
 
812
  def display_hvac_results_ui(loads: List[Dict[str, Any]]):
813
- """Display HVAC load results with enhanced UI elements."""
814
  st.subheader("HVAC Load Results")
815
 
816
- # Monthly Load Graph
817
- st.subheader("Monthly Heating and Cooling Load")
818
- monthly_df = pd.DataFrame(loads).groupby("month").agg({
819
- "total_cooling": "sum",
820
- "total_heating": "sum"
821
- }).reset_index()
822
- monthly_df = monthly_df.rename(columns={"total_cooling": "Cooling", "total_heating": "Heating"})
823
- fig = px.line(monthly_df, x="month", y=["Cooling", "Heating"], markers=True, title="Monthly Load Summary")
824
- fig.update_xaxes(title="Month", tickvals=list(range(1, 13)))
825
- fig.update_yaxes(title="Load (kW)")
826
- st.plotly_chart(fig)
827
- st.session_state.project_data["hvac_loads"]["monthly_summary"] = monthly_df.to_dict()
828
-
829
- # Two-Column Layout for Equipment Sizing and Pie Charts
830
  col1, col2 = st.columns(2)
831
  with col1:
832
- st.subheader("Equipment Sizing")
833
  cooling_loads = [load for load in loads if load["total_cooling"] > 0]
834
- heating_loads = [load for load in loads if load["total_heating"] > 0]
835
  peak_cooling = max(cooling_loads, key=lambda x: x["total_cooling"]) if cooling_loads else None
836
- peak_heating = max(heating_loads, key=lambda x: x["total_heating"]) if heating_loads else None
837
  if peak_cooling:
838
  st.write(f"**Peak Cooling Load**: {peak_cooling['total_cooling']:.2f} kW")
839
  st.write(f"Occurred on: {peak_cooling['month']}/{peak_cooling['day']} at {peak_cooling['hour']}:00")
840
  else:
841
  st.write("**Peak Cooling Load**: 0.00 kW")
 
 
 
 
 
842
  if peak_heating:
843
  st.write(f"**Peak Heating Load**: {peak_heating['total_heating']:.2f} kW")
844
  st.write(f"Occurred on: {peak_heating['month']}/{peak_heating['day']} at {peak_heating['hour']}:00")
845
  else:
846
  st.write("**Peak Heating Load**: 0.00 kW")
847
 
848
- with col2:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
849
  st.subheader("Cooling Load Breakdown")
850
  cooling_breakdown = {
851
  "Conduction": sum(load["conduction_cooling"] for load in cooling_loads),
@@ -854,18 +865,11 @@ def display_hvac_results_ui(loads: List[Dict[str, Any]]):
854
  "Ventilation": sum(load["ventilation_cooling"] for load in cooling_loads),
855
  "Infiltration": sum(load["infiltration_cooling"] for load in cooling_loads)
856
  }
857
- st.markdown("**Conduction**", help="Heat transfer through building envelope materials.")
858
- st.markdown("**Solar Gains**", help="Radiative heat gains from sun through surfaces and windows.")
859
- st.markdown("**Ventilation**", help="Loads due to outdoor air entering through ventilation systems.")
860
- st.markdown("**Infiltration**", help="Loads due to unintended air leakage through the building envelope.")
861
- st.markdown("**Internal**", help="Heat gains from occupants, lighting, and equipment inside the building.")
862
  cooling_pie = make_pie({k: v for k, v in cooling_breakdown.items() if v > 0}, "Cooling Load Components")
863
  st.plotly_chart(cooling_pie)
864
  st.session_state.project_data["hvac_loads"]["cooling"]["charts"]["pie_by_component"] = cooling_breakdown
865
 
866
- # Second Row for Heating and Orientation Breakdown
867
- col3, col4 = st.columns(2)
868
- with col3:
869
  st.subheader("Heating Load Breakdown")
870
  heating_breakdown = {
871
  "Conduction": sum(load["conduction_heating"] for load in heating_loads),
@@ -876,8 +880,10 @@ def display_hvac_results_ui(loads: List[Dict[str, Any]]):
876
  st.plotly_chart(heating_pie)
877
  st.session_state.project_data["hvac_loads"]["heating"]["charts"]["pie_by_component"] = heating_breakdown
878
 
879
- with col4:
880
- st.subheader("Cooling Load by Orientation")
 
 
881
  orientation_solar = defaultdict(float)
882
  orientation_conduction = defaultdict(float)
883
  for load in cooling_loads:
@@ -886,38 +892,71 @@ def display_hvac_results_ui(loads: List[Dict[str, Any]]):
886
  for key, value in load["conduction_by_orientation"].items():
887
  orientation_conduction[key] += value
888
  orientation_breakdown = {k: orientation_solar[k] + orientation_conduction[k] for k in set(orientation_solar) | set(orientation_conduction)}
889
- orientation_pie = make_pie({k: v for k, v in orientation_breakdown.items() if v > 0}, "Cooling Load by Orientation/Component")
890
  st.plotly_chart(orientation_pie)
891
  st.session_state.project_data["hvac_loads"]["cooling"]["charts"]["pie_by_orientation"] = orientation_breakdown
892
 
893
- # Interactive Filtering
 
 
 
 
 
 
 
 
 
 
 
894
  st.subheader("Explore Hourly Loads")
895
  df = pd.DataFrame(loads)
896
- col5, col6 = st.columns(2)
897
- with col5:
898
- selected_month = st.selectbox("Select Month", sorted(df["month"].unique()), key="filter_month")
899
- with col6:
900
- selected_day = st.selectbox("Select Day", sorted(df[df["month"] == selected_month]["day"].unique()), key="filter_day")
901
- filtered_df = df[(df["month"] == selected_month) & (df["day"] == selected_day)]
902
- st.dataframe(filtered_df[[
903
- "hour", "total_cooling", "total_heating", "conduction_cooling", "solar", "internal",
904
- "ventilation_cooling", "infiltration_cooling", "ventilation_heating", "infiltration_heating"
905
- ]])
 
 
 
 
 
 
 
 
 
906
 
907
  # CSV Export
908
- csv = filtered_df.to_csv(index=False)
909
- st.download_button("Download Hourly Summary as CSV", data=csv, file_name=f"hourly_loads_{selected_month}_{selected_day}.csv")
910
 
911
  def display_hvac_loads_page():
912
  """
913
  Display the HVAC Loads page in the Streamlit application.
914
- Allows users to configure location, simulation period, indoor conditions,
915
- calculates HVAC loads using TFMCalculations, and displays results.
916
  """
917
  try:
918
  st.header("HVAC Loads")
919
  st.markdown("Configure and calculate HVAC loads for the building.")
920
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
921
  # Location Information
922
  st.subheader("Location Information")
923
  climate_data = st.session_state.project_data["climate_data"]
 
810
  return fig
811
 
812
  def display_hvac_results_ui(loads: List[Dict[str, Any]]):
813
+ """Display HVAC load results with enhanced UI elements in a two-column format."""
814
  st.subheader("HVAC Load Results")
815
 
816
+ # First Row: Equipment Sizing (Two Columns)
 
 
 
 
 
 
 
 
 
 
 
 
 
817
  col1, col2 = st.columns(2)
818
  with col1:
819
+ st.subheader("Cooling Equipment Sizing")
820
  cooling_loads = [load for load in loads if load["total_cooling"] > 0]
 
821
  peak_cooling = max(cooling_loads, key=lambda x: x["total_cooling"]) if cooling_loads else None
 
822
  if peak_cooling:
823
  st.write(f"**Peak Cooling Load**: {peak_cooling['total_cooling']:.2f} kW")
824
  st.write(f"Occurred on: {peak_cooling['month']}/{peak_cooling['day']} at {peak_cooling['hour']}:00")
825
  else:
826
  st.write("**Peak Cooling Load**: 0.00 kW")
827
+
828
+ with col2:
829
+ st.subheader("Heating Equipment Sizing")
830
+ heating_loads = [load for load in loads if load["total_heating"] > 0]
831
+ peak_heating = max(heating_loads, key=lambda x: x["total_heating"]) if heating_loads else None
832
  if peak_heating:
833
  st.write(f"**Peak Heating Load**: {peak_heating['total_heating']:.2f} kW")
834
  st.write(f"Occurred on: {peak_heating['month']}/{peak_heating['day']} at {peak_heating['hour']}:00")
835
  else:
836
  st.write("**Peak Heating Load**: 0.00 kW")
837
 
838
+ # Second Row: Monthly Loads Graph (Single Column)
839
+ st.subheader("Monthly Heating and Cooling Load")
840
+ monthly_df = pd.DataFrame(loads).groupby("month").agg({
841
+ "total_cooling": "sum",
842
+ "total_heating": "sum"
843
+ }).reset_index()
844
+ monthly_df = monthly_df.rename(columns={"total_cooling": "Cooling", "total_heating": "Heating"})
845
+ fig = px.bar(
846
+ monthly_df,
847
+ x="month",
848
+ y=["Cooling", "Heating"],
849
+ barmode="group",
850
+ title="Monthly Load Summary"
851
+ )
852
+ fig.update_xaxes(title="Month", tickvals=list(range(1, 13)))
853
+ fig.update_yaxes(title="Load (kW)")
854
+ st.plotly_chart(fig, use_container_width=True)
855
+ st.session_state.project_data["hvac_loads"]["monthly_summary"] = monthly_df.to_dict()
856
+
857
+ # Third Row: Load Breakdown (Two Columns)
858
+ col3, col4 = st.columns(2)
859
+ with col3:
860
  st.subheader("Cooling Load Breakdown")
861
  cooling_breakdown = {
862
  "Conduction": sum(load["conduction_cooling"] for load in cooling_loads),
 
865
  "Ventilation": sum(load["ventilation_cooling"] for load in cooling_loads),
866
  "Infiltration": sum(load["infiltration_cooling"] for load in cooling_loads)
867
  }
 
 
 
 
 
868
  cooling_pie = make_pie({k: v for k, v in cooling_breakdown.items() if v > 0}, "Cooling Load Components")
869
  st.plotly_chart(cooling_pie)
870
  st.session_state.project_data["hvac_loads"]["cooling"]["charts"]["pie_by_component"] = cooling_breakdown
871
 
872
+ with col4:
 
 
873
  st.subheader("Heating Load Breakdown")
874
  heating_breakdown = {
875
  "Conduction": sum(load["conduction_heating"] for load in heating_loads),
 
880
  st.plotly_chart(heating_pie)
881
  st.session_state.project_data["hvac_loads"]["heating"]["charts"]["pie_by_component"] = heating_breakdown
882
 
883
+ # Fourth Row: Heat Gain by Orientation (Two Columns)
884
+ col5, col6 = st.columns(2)
885
+ with col5:
886
+ st.subheader("Cooling Heat Gain by Orientation")
887
  orientation_solar = defaultdict(float)
888
  orientation_conduction = defaultdict(float)
889
  for load in cooling_loads:
 
892
  for key, value in load["conduction_by_orientation"].items():
893
  orientation_conduction[key] += value
894
  orientation_breakdown = {k: orientation_solar[k] + orientation_conduction[k] for k in set(orientation_solar) | set(orientation_conduction)}
895
+ orientation_pie = make_pie({k: v for k, v in orientation_breakdown.items() if v > 0}, "Cooling Heat Gain by Orientation")
896
  st.plotly_chart(orientation_pie)
897
  st.session_state.project_data["hvac_loads"]["cooling"]["charts"]["pie_by_orientation"] = orientation_breakdown
898
 
899
+ with col6:
900
+ st.subheader("Heating Heat Gain by Orientation")
901
+ orientation_conduction = defaultdict(float)
902
+ for load in heating_loads:
903
+ for key, value in load["conduction_by_orientation"].items():
904
+ orientation_conduction[key] += value
905
+ orientation_breakdown = {k: v for k, v in orientation_conduction.items() if v > 0}
906
+ orientation_pie = make_pie(orientation_breakdown, "Heating Heat Gain by Orientation")
907
+ st.plotly_chart(orientation_pie)
908
+ st.session_state.project_data["hvac_loads"]["heating"]["charts"]["pie_by_orientation"] = orientation_breakdown
909
+
910
+ # Fifth Row: Explore Hourly Loads (Single Column)
911
  st.subheader("Explore Hourly Loads")
912
  df = pd.DataFrame(loads)
913
+ # Flatten orientation-based loads
914
+ unique_orientations = set()
915
+ for load in loads:
916
+ unique_orientations.update(load["solar_by_orientation"].keys())
917
+ unique_orientations.update(load["conduction_by_orientation"].keys())
918
+
919
+ columns = [
920
+ "month", "day", "hour",
921
+ "total_cooling", "total_heating",
922
+ "conduction_cooling", "solar", "internal",
923
+ "ventilation_cooling", "infiltration_cooling",
924
+ "ventilation_heating", "infiltration_heating"
925
+ ]
926
+ for orient in sorted(unique_orientations):
927
+ df[f"solar_{orient}"] = df["solar_by_orientation"].apply(lambda x: x.get(orient, 0.0))
928
+ df[f"conduction_{orient}"] = df["conduction_by_orientation"].apply(lambda x: x.get(orient, 0.0))
929
+ columns.extend([f"solar_{orient}", f"conduction_{orient}"])
930
+
931
+ st.dataframe(df[columns])
932
 
933
  # CSV Export
934
+ csv = df[columns].to_csv(index=False)
935
+ st.download_button("Download Hourly Summary as CSV", data=csv, file_name="hourly_loads.csv")
936
 
937
  def display_hvac_loads_page():
938
  """
939
  Display the HVAC Loads page in the Streamlit application.
940
+ Checks for existing results in session state before recalculating.
 
941
  """
942
  try:
943
  st.header("HVAC Loads")
944
  st.markdown("Configure and calculate HVAC loads for the building.")
945
 
946
+ # Check for existing results
947
+ if (st.session_state.project_data.get("hvac_loads", {}).get("cooling", {}).get("hourly") or
948
+ st.session_state.project_data.get("hvac_loads", {}).get("heating", {}).get("hourly")):
949
+ loads = []
950
+ cooling_loads = st.session_state.project_data["hvac_loads"]["cooling"].get("hourly", [])
951
+ heating_loads = st.session_state.project_data["hvac_loads"]["heating"].get("hourly", [])
952
+ loads.extend(cooling_loads)
953
+ loads.extend(heating_loads)
954
+ # Sort loads by month, day, hour to ensure consistent display
955
+ loads = sorted(loads, key=lambda x: (x["month"], x["day"], x["hour"]))
956
+ if loads:
957
+ st.info("Displaying previously calculated HVAC load results.")
958
+ display_hvac_results_ui(loads)
959
+
960
  # Location Information
961
  st.subheader("Location Information")
962
  climate_data = st.session_state.project_data["climate_data"]