mabuseif commited on
Commit
5c60d1e
·
verified ·
1 Parent(s): 2c31938

Update app/hvac_loads.py

Browse files
Files changed (1) hide show
  1. app/hvac_loads.py +24 -64
app/hvac_loads.py CHANGED
@@ -17,6 +17,7 @@ from collections import defaultdict
17
  import logging
18
  import math
19
  from utils.ctf_calculations import CTFCalculator, ComponentType, CTFCoefficients
 
20
 
21
  # Configure logging
22
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -67,32 +68,6 @@ class AdaptiveComfortModel:
67
  return setpoints
68
 
69
  class TFMCalculations:
70
- # Solar calculation constants (from utils/solar.py)
71
- SHGC_COEFFICIENTS = {
72
- "Single Clear": [0.1, -0.0, 0.0, -0.0, 0.0, 0.87],
73
- "Single Tinted": [0.12, -0.0, 0.0, -0.0, 0.8, -0.0],
74
- "Double Clear": [0.14, -0.0, 0.0, -0.0, 0.78, -0.0],
75
- "Double Low-E": [0.2, -0.0, 0.0, 0.7, 0.0, -0.0],
76
- "Double Tinted": [0.15, -0.0, 0.0, -0.0, 0.65, -0.0],
77
- "Double Low-E with Argon": [0.18, -0.0, 0.0, 0.68, 0.0, -0.0],
78
- "Single Low-E Reflective": [0.22, -0.0, 0.0, 0.6, 0.0, -0.0],
79
- "Double Reflective": [0.24, -0.0, 0.0, 0.58, 0.0, -0.0],
80
- "Electrochromic": [0.25, -0.0, 0.5, -0.0, 0.0, -0.0]
81
- }
82
-
83
- GLAZING_TYPE_MAPPING = {
84
- "Single Clear 3mm": "Single Clear",
85
- "Single Clear 6mm": "Single Clear",
86
- "Single Tinted 6mm": "Single Tinted",
87
- "Double Clear 6mm/13mm Air": "Double Clear",
88
- "Double Low-E 6mm/13mm Air": "Double Low-E",
89
- "Double Tinted 6mm/13mm Air": "Double Tinted",
90
- "Double Low-E 6mm/13mm Argon": "Double Low-E with Argon",
91
- "Single Low-E Reflective 6mm": "Single Low-E Reflective",
92
- "Double Reflective 6mm/13mm Air": "Double Reflective",
93
- "Electrochromic 6mm/13mm Air": "Electrochromic"
94
- }
95
-
96
  @staticmethod
97
  def get_component_type(component: Dict[str, Any]) -> ComponentType:
98
  """Map component dictionary 'type' to ComponentType enum."""
@@ -161,18 +136,6 @@ class TFMCalculations:
161
  0.014615 * math.cos(2 * B_rad) - 0.04089 * math.sin(2 * B_rad))
162
  return EOT
163
 
164
- @staticmethod
165
- def calculate_dynamic_shgc(glazing_type: str, cos_theta: float) -> float:
166
- """Calculate dynamic SHGC based on incidence angle."""
167
- if glazing_type not in TFMCalculations.SHGC_COEFFICIENTS:
168
- logger.warning(f"Unknown glazing type '{glazing_type}'. Using default SHGC coefficients for Single Clear.")
169
- glazing_type = "Single Clear"
170
-
171
- c = TFMCalculations.SHGC_COEFFICIENTS[glazing_type]
172
- f_cos_theta = (c[0] + c[1] * cos_theta + c[2] * cos_theta**2 +
173
- c[3] * cos_theta**3 + c[4] * cos_theta**4 + c[5] * cos_theta**5)
174
- return f_cos_theta
175
-
176
  @staticmethod
177
  def get_surface_parameters(component: Dict[str, Any], building_info: Dict, material_library: MaterialLibrary,
178
  project_materials: Dict, project_constructions: Dict,
@@ -192,20 +155,20 @@ class TFMCalculations:
192
  try:
193
  # For windows and skylights, adjust h_o and use shgc instead of absorptivity
194
  if component_type in [ComponentType.WINDOW, ComponentType.SKYLIGHT]:
195
- glazing_material_name = component.get('fenestration', None)
196
- if not glazing_material_name:
197
  logger.warning(f"No fenestration defined for {component_name}. Using default SHGC=0.7, h_o={h_o}.")
198
  absorptivity = component.get('shgc', 0.7) # Use shgc as absorptivity for consistency
199
  else:
200
- glazing_material_obj = (project_glazing_materials.get(glazing_material_name) or
201
- material_library.library_glazing_materials.get(glazing_material_name))
202
  if not glazing_material_obj:
203
- logger.warning(f"Fenestration '{glazing_material_name}' not found for {component_name}. Using default SHGC=0.7, h_o={h_o}.")
204
  absorptivity = component.get('shgc', 0.7)
205
  else:
206
  absorptivity = glazing_material_obj.get('shgc', component.get('shgc', 0.7))
207
  h_o = glazing_material_obj.get('h_o', h_o)
208
- logger.debug(f"Using fenestration '{glazing_material_name}' for {component_name}: shgc={absorptivity}, h_o={h_o}")
209
  emissivity = None # Emissivity not used for fenestrations
210
 
211
  logger.info(f"Surface parameters for {component_name}: tilt={surface_tilt:.1f}, azimuth={surface_azimuth:.1f}, h_o={h_o:.1f}, "
@@ -257,7 +220,7 @@ class TFMCalculations:
257
  try:
258
  material_library = st.session_state.get("material_library")
259
  if not material_library:
260
- from app.material_library import MaterialLibrary
261
  material_library = MaterialLibrary()
262
  st.session_state.material_library = material_library
263
  logger.info(f"Created new MaterialLibrary for {component_name}")
@@ -392,30 +355,27 @@ class TFMCalculations:
392
  solar_heat_gain = 0.0
393
 
394
  if component_type in [ComponentType.WINDOW, ComponentType.SKYLIGHT]:
395
- shgc = 0.7
396
- glazing_material_name = component.get('glazing_material', None)
397
- if glazing_material_name:
398
- glazing_material_obj = (project_glazing_materials.get(glazing_material_name) or
399
- material_library.library_glazing_materials.get(glazing_material_name))
400
  if glazing_material_obj:
401
- shgc = glazing_material_obj.get('shgc', 0.7)
402
  h_o = glazing_material_obj.get('h_o', h_o)
403
  else:
404
- logger.warning(f"Glazing material '{glazing_material_name}' not found for {component_name}. Using default SHGC=0.7.")
405
-
406
- glazing_type = "Single Clear"
407
- if component.get('name') in TFMCalculations.GLAZING_TYPE_MAPPING:
408
- glazing_type = TFMCalculations.GLAZING_TYPE_MAPPING[component.get('name')]
409
 
410
- iac = component.get('iac', 1.0)
 
411
 
412
- shgc_dynamic = shgc * TFMCalculations.calculate_dynamic_shgc(glazing_type, cos_theta)
413
 
414
- solar_heat_gain = component.get('area', 0.0) * shgc_dynamic * I_t * iac / 1000
415
 
416
  logger.info(f"Fenestration solar heat gain for {component_name} at {month}/{day}/{hour}: "
417
  f"{solar_heat_gain:.4f} kW (area={component.get('area', 0.0)}, shgc_dynamic={shgc_dynamic:.4f}, "
418
- f"I_t={I_t:.2f}, iac={iac})")
419
 
420
  elif component_type in [ComponentType.WALL, ComponentType.ROOF]:
421
  surface_resistance = 1/h_o
@@ -716,7 +676,7 @@ class TFMCalculations:
716
  area = building_info.get("floor_area", 100.0)
717
 
718
  if "material_library" not in st.session_state:
719
- from app.material_library import MaterialLibrary
720
  st.session_state.material_library = MaterialLibrary()
721
  logger.info("Initialized MaterialLibrary in session_state for solar calculations")
722
 
@@ -954,7 +914,7 @@ def display_hvac_loads_page():
954
  )
955
  st.session_state.project_data["sim_period"]["base_temp"] = base_temp
956
 
957
- # Indoor Conditions Configuration (unchanged)
958
  st.subheader("Indoor Conditions")
959
  indoor_type = st.selectbox(
960
  "Indoor Conditions Type",
@@ -1017,7 +977,7 @@ def display_hvac_loads_page():
1017
  )
1018
  st.session_state.project_data["indoor_conditions"]["adaptive_acceptability"] = acceptability
1019
 
1020
- # Calculate HVAC Loads (unchanged)
1021
  if st.button("Calculate HVAC Loads"):
1022
  try:
1023
  components = st.session_state.project_data["components"]
@@ -1047,7 +1007,7 @@ def display_hvac_loads_page():
1047
  hvac_settings=hvac_settings
1048
  )
1049
 
1050
- # Update session state with results (unchanged)
1051
  cooling_loads = [load for load in loads if load["total_cooling"] > 0]
1052
  heating_loads = [load for load in loads if load["total_heating"] > 0]
1053
  st.session_state.project_data["hvac_loads"]["cooling"]["hourly"] = cooling_loads
 
17
  import logging
18
  import math
19
  from utils.ctf_calculations import CTFCalculator, ComponentType, CTFCoefficients
20
+ from utils.solar import SolarCalculations # Import SolarCalculations for SHGC data
21
 
22
  # Configure logging
23
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
68
  return setpoints
69
 
70
  class TFMCalculations:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  @staticmethod
72
  def get_component_type(component: Dict[str, Any]) -> ComponentType:
73
  """Map component dictionary 'type' to ComponentType enum."""
 
136
  0.014615 * math.cos(2 * B_rad) - 0.04089 * math.sin(2 * B_rad))
137
  return EOT
138
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  @staticmethod
140
  def get_surface_parameters(component: Dict[str, Any], building_info: Dict, material_library: MaterialLibrary,
141
  project_materials: Dict, project_constructions: Dict,
 
155
  try:
156
  # For windows and skylights, adjust h_o and use shgc instead of absorptivity
157
  if component_type in [ComponentType.WINDOW, ComponentType.SKYLIGHT]:
158
+ fenestration_name = component.get('fenestration', None)
159
+ if not fenestration_name:
160
  logger.warning(f"No fenestration defined for {component_name}. Using default SHGC=0.7, h_o={h_o}.")
161
  absorptivity = component.get('shgc', 0.7) # Use shgc as absorptivity for consistency
162
  else:
163
+ glazing_material_obj = (project_glazing_materials.get(fenestration_name) or
164
+ material_library.library_glazing_materials.get(fenestration_name))
165
  if not glazing_material_obj:
166
+ logger.warning(f"Fenestration '{fenestration_name}' not found for {component_name}. Using default SHGC=0.7, h_o={h_o}.")
167
  absorptivity = component.get('shgc', 0.7)
168
  else:
169
  absorptivity = glazing_material_obj.get('shgc', component.get('shgc', 0.7))
170
  h_o = glazing_material_obj.get('h_o', h_o)
171
+ logger.debug(f"Using fenestration '{fenestration_name}' for {component_name}: shgc={absorptivity}, h_o={h_o}")
172
  emissivity = None # Emissivity not used for fenestrations
173
 
174
  logger.info(f"Surface parameters for {component_name}: tilt={surface_tilt:.1f}, azimuth={surface_azimuth:.1f}, h_o={h_o:.1f}, "
 
220
  try:
221
  material_library = st.session_state.get("material_library")
222
  if not material_library:
223
+ from app.materials_library import MaterialLibrary
224
  material_library = MaterialLibrary()
225
  st.session_state.material_library = material_library
226
  logger.info(f"Created new MaterialLibrary for {component_name}")
 
355
  solar_heat_gain = 0.0
356
 
357
  if component_type in [ComponentType.WINDOW, ComponentType.SKYLIGHT]:
358
+ shgc = component.get('shgc', 0.7)
359
+ fenestration_name = component.get('fenestration', None)
360
+ if fenestration_name:
361
+ glazing_material_obj = (project_glazing_materials.get(fenestration_name) or
362
+ material_library.library_glazing_materials.get(fenestration_name))
363
  if glazing_material_obj:
364
+ shgc = glazing_material_obj.get('shgc', shgc)
365
  h_o = glazing_material_obj.get('h_o', h_o)
366
  else:
367
+ logger.warning(f"Fenestration '{fenestration_name}' not found for {component_name}. Using default SHGC=0.7.")
 
 
 
 
368
 
369
+ glazing_type = SolarCalculations.GLAZING_TYPE_MAPPING.get(component.get('name', ''), "Single Clear")
370
+ shading_coeff = component.get('shading_coefficient', 1.0) # Aligned with components.py
371
 
372
+ shgc_dynamic = shgc * SolarCalculations.calculate_dynamic_shgc(glazing_type, cos_theta)
373
 
374
+ solar_heat_gain = component.get('area', 0.0) * shgc_dynamic * I_t * shading_coeff / 1000
375
 
376
  logger.info(f"Fenestration solar heat gain for {component_name} at {month}/{day}/{hour}: "
377
  f"{solar_heat_gain:.4f} kW (area={component.get('area', 0.0)}, shgc_dynamic={shgc_dynamic:.4f}, "
378
+ f"I_t={I_t:.2f}, shading_coeff={shading_coeff})")
379
 
380
  elif component_type in [ComponentType.WALL, ComponentType.ROOF]:
381
  surface_resistance = 1/h_o
 
676
  area = building_info.get("floor_area", 100.0)
677
 
678
  if "material_library" not in st.session_state:
679
+ from app.materials_library import MaterialLibrary
680
  st.session_state.material_library = MaterialLibrary()
681
  logger.info("Initialized MaterialLibrary in session_state for solar calculations")
682
 
 
914
  )
915
  st.session_state.project_data["sim_period"]["base_temp"] = base_temp
916
 
917
+ # Indoor Conditions Configuration
918
  st.subheader("Indoor Conditions")
919
  indoor_type = st.selectbox(
920
  "Indoor Conditions Type",
 
977
  )
978
  st.session_state.project_data["indoor_conditions"]["adaptive_acceptability"] = acceptability
979
 
980
+ # Calculate HVAC Loads
981
  if st.button("Calculate HVAC Loads"):
982
  try:
983
  components = st.session_state.project_data["components"]
 
1007
  hvac_settings=hvac_settings
1008
  )
1009
 
1010
+ # Update session state with results
1011
  cooling_loads = [load for load in loads if load["total_cooling"] > 0]
1012
  heating_loads = [load for load in loads if load["total_heating"] > 0]
1013
  st.session_state.project_data["hvac_loads"]["cooling"]["hourly"] = cooling_loads