mabuseif commited on
Commit
1d6a796
·
verified ·
1 Parent(s): 59c00ea

Update app/hvac_loads.py

Browse files
Files changed (1) hide show
  1. app/hvac_loads.py +73 -45
app/hvac_loads.py CHANGED
@@ -22,6 +22,50 @@ from utils.ctf_calculations import CTFCalculator, ComponentType, CTFCoefficients
22
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
23
  logger = logging.getLogger(__name__)
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  class TFMCalculations:
26
  # Solar calculation constants (from utils/solar.py)
27
  SHGC_COEFFICIENTS = {
@@ -632,7 +676,8 @@ class TFMCalculations:
632
 
633
  @staticmethod
634
  def get_adaptive_comfort_temp(outdoor_temp: float) -> float:
635
- """Calculate adaptive comfort temperature per ASHRAE 55."""
 
636
  if 10 <= outdoor_temp <= 33.5:
637
  return 0.31 * outdoor_temp + 17.8
638
  return 24.0
@@ -662,9 +707,9 @@ class TFMCalculations:
662
  return filtered_data
663
 
664
  @staticmethod
665
- def get_indoor_conditions(indoor_conditions: Dict, hour: int, outdoor_temp: float) -> Dict:
666
  """Determine indoor conditions based on user settings."""
667
- if indoor_conditions["type"] == "Fixed":
668
  mode = "none" if abs(outdoor_temp - 18) < 0.01 else "cooling" if outdoor_temp > 18 else "heating"
669
  if mode == "cooling":
670
  return {
@@ -678,16 +723,10 @@ class TFMCalculations:
678
  }
679
  else:
680
  return {"temperature": 24.0, "rh": 50.0}
681
- elif indoor_conditions["type"] == "Time-varying":
682
- schedule = indoor_conditions.get("schedule", [])
683
- if schedule:
684
- hour_idx = hour % 24
685
- for entry in schedule:
686
- if entry["hour"] == hour_idx:
687
- return {"temperature": entry["temperature"], "rh": entry["rh"]}
688
- return {"temperature": 24.0, "rh": 50.0}
689
  else: # Adaptive
690
- return {"temperature": TFMCalculations.get_adaptive_comfort_temp(outdoor_temp), "rh": 50.0}
 
 
691
 
692
  @staticmethod
693
  def calculate_tfm_loads(components: Dict, hourly_data: List[Dict], indoor_conditions: Dict, internal_loads: Dict, building_info: Dict, sim_period: Dict, hvac_settings: Dict) -> List[Dict]:
@@ -703,6 +742,12 @@ class TFMCalculations:
703
  st.session_state.material_library = MaterialLibrary()
704
  logger.info("Initialized MaterialLibrary in session_state for solar calculations")
705
 
 
 
 
 
 
 
706
  for comp_list in components.values():
707
  for comp in comp_list:
708
  comp['ctf'] = CTFCalculator.calculate_ctf_coefficients(comp)
@@ -711,7 +756,9 @@ class TFMCalculations:
711
  for hour_data in filtered_data:
712
  hour = hour_data["hour"]
713
  outdoor_temp = hour_data["dry_bulb"]
714
- indoor_cond = TFMCalculations.get_indoor_conditions(indoor_conditions, hour, outdoor_temp)
 
 
715
  indoor_temp = indoor_cond["temperature"]
716
  conduction_cooling = conduction_heating = solar = internal = ventilation_cooling = ventilation_heating = infiltration_cooling = infiltration_heating = 0
717
  is_operating = False
@@ -755,8 +802,8 @@ class TFMCalculations:
755
  total_cooling = 0
756
  temp_loads.append({
757
  "hour": hour,
758
- "month": hour_data["month"],
759
- "day": hour_data["day"],
760
  "conduction_cooling": conduction_cooling,
761
  "conduction_heating": conduction_heating,
762
  "solar": solar,
@@ -838,13 +885,13 @@ def display_hvac_loads_page():
838
  st.subheader("Indoor Conditions")
839
  indoor_type = st.selectbox(
840
  "Indoor Conditions Type",
841
- ["Fixed", "Time-varying", "Adaptive"],
842
  key="hvac_indoor_type",
843
- index=["Fixed", "Time-varying", "Adaptive"].index(st.session_state.project_data["indoor_conditions"]["type"])
844
  )
845
  st.session_state.project_data["indoor_conditions"]["type"] = indoor_type
846
 
847
- if indoor_type == "Fixed":
848
  col1, col2 = st.columns(2)
849
  with col1:
850
  cooling_temp = st.number_input(
@@ -888,33 +935,14 @@ def display_hvac_loads_page():
888
  "temperature": heating_temp,
889
  "rh": heating_rh
890
  }
891
- elif indoor_type == "Time-varying":
892
- st.write("Define hourly temperature and RH schedule (0-23 hours):")
893
- schedule = []
894
- for hour in range(24):
895
- with st.container():
896
- st.markdown(f"**Hour {hour}**")
897
- col1, col2 = st.columns(2)
898
- with col1:
899
- temp = st.number_input(
900
- f"Temperature (°C)",
901
- min_value=16.0,
902
- max_value=30.0,
903
- value=24.0,
904
- step=0.1,
905
- key=f"hvac_schedule_temp_{hour}"
906
- )
907
- with col2:
908
- rh = st.number_input(
909
- f"Relative Humidity (%)",
910
- min_value=30.0,
911
- max_value=70.0,
912
- value=50.0,
913
- step=1.0,
914
- key=f"hvac_schedule_rh_{hour}"
915
- )
916
- schedule.append({"hour": hour, "temperature": temp, "rh": rh})
917
- st.session_state.project_data["indoor_conditions"]["schedule"] = schedule
918
 
919
  # HVAC Settings Configuration
920
  st.subheader("HVAC Settings")
 
22
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
23
  logger = logging.getLogger(__name__)
24
 
25
+ class AdaptiveComfortModel:
26
+ @staticmethod
27
+ def compute_daily_mean_temperatures(hourly_data: List[Dict]) -> List[Tuple[Tuple[int, int], float]]:
28
+ daily_means = {}
29
+ for data in hourly_data:
30
+ key = (data["month"], data["day"])
31
+ daily_means.setdefault(key, []).append(data["dry_bulb"])
32
+ return [(key, np.mean(values)) for key, values in sorted(daily_means.items())]
33
+
34
+ @staticmethod
35
+ def compute_running_mean(daily_means: List[float], alpha: float = 0.8) -> List[float]:
36
+ trm = []
37
+ for i, t in enumerate(daily_means):
38
+ if i == 0:
39
+ trm.append(t)
40
+ else:
41
+ trm.append((1 - alpha) * t + alpha * trm[i - 1])
42
+ return trm
43
+
44
+ @staticmethod
45
+ def generate_adaptive_setpoints(hourly_data: List[Dict], acceptability: str = "90") -> Dict[Tuple[int, int], float]:
46
+ daily_mean_data = AdaptiveComfortModel.compute_daily_mean_temperatures(hourly_data)
47
+ daily_keys = [key for key, _ in daily_mean_data]
48
+ daily_values = [value for _, value in daily_mean_data]
49
+ running_means = AdaptiveComfortModel.compute_running_mean(daily_values)
50
+
51
+ setpoints = {}
52
+ for i, key in enumerate(daily_keys):
53
+ trm = running_means[i]
54
+ if acceptability == "80":
55
+ t_min = 0.31 * trm + 13.5
56
+ t_max = 0.31 * trm + 22.5
57
+ elif acceptability == "85":
58
+ t_min = 0.31 * trm + 13.9
59
+ t_max = 0.31 * trm + 22.1
60
+ elif acceptability == "95":
61
+ t_min = 0.31 * trm + 14.7
62
+ t_max = 0.31 * trm + 20.7
63
+ else: # Default to 90%
64
+ t_min = 0.31 * trm + 14.3
65
+ t_max = 0.31 * trm + 21.3
66
+ setpoints[key] = (t_min + t_max) / 2
67
+ return setpoints
68
+
69
  class TFMCalculations:
70
  # Solar calculation constants (from utils/solar.py)
71
  SHGC_COEFFICIENTS = {
 
676
 
677
  @staticmethod
678
  def get_adaptive_comfort_temp(outdoor_temp: float) -> float:
679
+ """Deprecated: Use AdaptiveComfortModel instead."""
680
+ logger.warning("get_adaptive_comfort_temp is deprecated. Use AdaptiveComfortModel.generate_adaptive_setpoints.")
681
  if 10 <= outdoor_temp <= 33.5:
682
  return 0.31 * outdoor_temp + 17.8
683
  return 24.0
 
707
  return filtered_data
708
 
709
  @staticmethod
710
+ def get_indoor_conditions(indoor_conditions: Dict, hour: int, outdoor_temp: float, month: int = 1, day: int = 1, adaptive_setpoints: Optional[Dict[Tuple[int, int], float]] = None) -> Dict:
711
  """Determine indoor conditions based on user settings."""
712
+ if indoor_conditions["type"] == "Fixed Setpoints":
713
  mode = "none" if abs(outdoor_temp - 18) < 0.01 else "cooling" if outdoor_temp > 18 else "heating"
714
  if mode == "cooling":
715
  return {
 
723
  }
724
  else:
725
  return {"temperature": 24.0, "rh": 50.0}
 
 
 
 
 
 
 
 
726
  else: # Adaptive
727
+ key = (month, day)
728
+ temp = adaptive_setpoints.get(key, 24.0) if adaptive_setpoints else 24.0
729
+ return {"temperature": temp, "rh": 50.0}
730
 
731
  @staticmethod
732
  def calculate_tfm_loads(components: Dict, hourly_data: List[Dict], indoor_conditions: Dict, internal_loads: Dict, building_info: Dict, sim_period: Dict, hvac_settings: Dict) -> List[Dict]:
 
742
  st.session_state.material_library = MaterialLibrary()
743
  logger.info("Initialized MaterialLibrary in session_state for solar calculations")
744
 
745
+ if indoor_conditions["type"] == "Adaptive":
746
+ acceptability = indoor_conditions.get("adaptive_acceptability", "90")
747
+ adaptive_setpoints = AdaptiveComfortModel.generate_adaptive_setpoints(hourly_data, acceptability)
748
+ else:
749
+ adaptive_setpoints = None
750
+
751
  for comp_list in components.values():
752
  for comp in comp_list:
753
  comp['ctf'] = CTFCalculator.calculate_ctf_coefficients(comp)
 
756
  for hour_data in filtered_data:
757
  hour = hour_data["hour"]
758
  outdoor_temp = hour_data["dry_bulb"]
759
+ month = hour_data["month"]
760
+ day = hour_data["day"]
761
+ indoor_cond = TFMCalculations.get_indoor_conditions(indoor_conditions, hour, outdoor_temp, month, day, adaptive_setpoints)
762
  indoor_temp = indoor_cond["temperature"]
763
  conduction_cooling = conduction_heating = solar = internal = ventilation_cooling = ventilation_heating = infiltration_cooling = infiltration_heating = 0
764
  is_operating = False
 
802
  total_cooling = 0
803
  temp_loads.append({
804
  "hour": hour,
805
+ "month": month,
806
+ "day": day,
807
  "conduction_cooling": conduction_cooling,
808
  "conduction_heating": conduction_heating,
809
  "solar": solar,
 
885
  st.subheader("Indoor Conditions")
886
  indoor_type = st.selectbox(
887
  "Indoor Conditions Type",
888
+ ["Fixed Setpoints", "Adaptive"],
889
  key="hvac_indoor_type",
890
+ index=["Fixed Setpoints", "Adaptive"].index(st.session_state.project_data["indoor_conditions"]["type"])
891
  )
892
  st.session_state.project_data["indoor_conditions"]["type"] = indoor_type
893
 
894
+ if indoor_type == "Fixed Setpoints":
895
  col1, col2 = st.columns(2)
896
  with col1:
897
  cooling_temp = st.number_input(
 
935
  "temperature": heating_temp,
936
  "rh": heating_rh
937
  }
938
+ elif indoor_type == "Adaptive":
939
+ acceptability = st.selectbox(
940
+ "Adaptive Comfort Acceptability (%)",
941
+ ["80", "85", "90", "95"],
942
+ index=["80", "85", "90", "95"].index(st.session_state.project_data["indoor_conditions"].get("adaptive_acceptability", "90")),
943
+ key="adaptive_acceptability"
944
+ )
945
+ st.session_state.project_data["indoor_conditions"]["adaptive_acceptability"] = acceptability
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
946
 
947
  # HVAC Settings Configuration
948
  st.subheader("HVAC Settings")