mabuseif commited on
Commit
2aa4b56
·
verified ·
1 Parent(s): f4769bb

Update utils/solar.py

Browse files
Files changed (1) hide show
  1. utils/solar.py +44 -10
utils/solar.py CHANGED
@@ -354,6 +354,11 @@ class SolarCalculations:
354
  continue
355
  for comp in comp_list:
356
  try:
 
 
 
 
 
357
  # Get surface parameters
358
  surface_tilt, surface_azimuth, h_o, emissivity, absorptivity = \
359
  self.get_surface_parameters(comp, building_info)
@@ -361,22 +366,22 @@ class SolarCalculations:
361
  # For windows/skylights, get SHGC from component
362
  shgc = comp.get('shgc', 0.7)
363
  fenestration_name = comp.get('fenestration', None)
364
-
365
  # Calculate angle of incidence (θ)
366
  cos_theta = (math.sin(math.radians(alpha)) * math.cos(math.radians(surface_tilt)) +
367
  math.cos(math.radians(alpha)) * math.sin(math.radians(surface_tilt)) *
368
  math.cos(math.radians(azimuth - surface_azimuth)))
369
  cos_theta = max(min(cos_theta, 1.0), 0.0) # Clamp to [0, 1]
370
-
371
  logger.info(f" Component {comp.get('name', 'unknown_component')} at {month}/{day}/{hour}: "
372
  f"surface_tilt={surface_tilt:.2f}, surface_azimuth={surface_azimuth:.2f}, "
373
  f"cos_theta={cos_theta:.2f}, h_o={h_o:.2f}")
374
-
375
  # Calculate total incident radiation (I_t)
376
  view_factor = (1 - math.cos(math.radians(surface_tilt))) / 2
377
  ground_reflected = ground_reflectivity * ghi * view_factor
378
  I_t = dni * cos_theta + dhi + ground_reflected
379
-
380
  # Initialize result
381
  comp_result = {
382
  "component_id": comp.get('name', 'unknown_component'),
@@ -384,17 +389,46 @@ class SolarCalculations:
384
  "absorptivity": round(absorptivity, 2),
385
  "emissivity": round(emissivity, 2) if emissivity is not None else None
386
  }
387
-
388
- # Calculate sol-air temperature for opaque surfaces
389
- ifsentence = comp.get('type', '').lower() in ['walls', 'roofs']
390
- if ifsentence:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  T_sol_air = CTFCalculator.calculate_sol_air_temperature(
392
  outdoor_temp, I_t, absorptivity, emissivity or 0.9,
393
  h_o, dew_point, total_sky_cover
394
  )
395
  comp_result["sol_air_temp"] = round(T_sol_air, 2)
396
  logger.info(f"Sol-air temp for {comp_result['component_id']} at {month}/{day}/{hour}: {T_sol_air:.2f}°C")
397
-
398
  # Calculate solar heat gain for fenestration
399
  elif comp.get('type', '').lower() in ['windows', 'skylights']:
400
  glazing_type = self.GLAZING_TYPE_MAPPING.get(comp.get('fenestration', ''), 'Single Clear')
@@ -408,7 +442,7 @@ class SolarCalculations:
408
  f"I_t={I_t:.2f}, iac={iac})")
409
 
410
  component_results.append(comp_result)
411
-
412
  except Exception as e:
413
  component_name = comp.get('name', 'unknown_component')
414
  logger.error(f"Error processing component {component_name} at {month}/{day}/{hour}: {str(e)}")
 
354
  continue
355
  for comp in comp_list:
356
  try:
357
+ # Validate adiabatic and ground_contact mutual exclusivity
358
+ if comp.get('adiabatic', False) and comp.get('ground_contact', False):
359
+ logger.warning(f"Component {comp.get('name', 'unknown_component')} has both adiabatic and ground_contact set to True. Treating as adiabatic, setting ground_contact to False.")
360
+ comp['ground_contact'] = False
361
+
362
  # Get surface parameters
363
  surface_tilt, surface_azimuth, h_o, emissivity, absorptivity = \
364
  self.get_surface_parameters(comp, building_info)
 
366
  # For windows/skylights, get SHGC from component
367
  shgc = comp.get('shgc', 0.7)
368
  fenestration_name = comp.get('fenestration', None)
369
+
370
  # Calculate angle of incidence (θ)
371
  cos_theta = (math.sin(math.radians(alpha)) * math.cos(math.radians(surface_tilt)) +
372
  math.cos(math.radians(alpha)) * math.sin(math.radians(surface_tilt)) *
373
  math.cos(math.radians(azimuth - surface_azimuth)))
374
  cos_theta = max(min(cos_theta, 1.0), 0.0) # Clamp to [0, 1]
375
+
376
  logger.info(f" Component {comp.get('name', 'unknown_component')} at {month}/{day}/{hour}: "
377
  f"surface_tilt={surface_tilt:.2f}, surface_azimuth={surface_azimuth:.2f}, "
378
  f"cos_theta={cos_theta:.2f}, h_o={h_o:.2f}")
379
+
380
  # Calculate total incident radiation (I_t)
381
  view_factor = (1 - math.cos(math.radians(surface_tilt))) / 2
382
  ground_reflected = ground_reflectivity * ghi * view_factor
383
  I_t = dni * cos_theta + dhi + ground_reflected
384
+
385
  # Initialize result
386
  comp_result = {
387
  "component_id": comp.get('name', 'unknown_component'),
 
389
  "absorptivity": round(absorptivity, 2),
390
  "emissivity": round(emissivity, 2) if emissivity is not None else None
391
  }
392
+
393
+ # Skip calculations for adiabatic surfaces
394
+ if comp.get('adiabatic', False):
395
+ logger.info(f"Skipping solar calculations for adiabatic component {comp_result['component_id']} at {month}/{day}/{hour}")
396
+ component_results.append(comp_result)
397
+ continue
398
+
399
+ # Handle ground-contact surfaces
400
+ if comp.get('ground_contact', False):
401
+ # Validate component type
402
+ component_type = comp.get('type', '').lower()
403
+ valid_types = ['walls', 'roofs', 'floors']
404
+ if component_type not in valid_types:
405
+ logger.warning(f"Invalid ground-contact component type '{component_type}' for {comp_result['component_id']}. Skipping ground temperature assignment.")
406
+ component_results.append(comp_result)
407
+ continue
408
+
409
+ # Retrieve ground temperature
410
+ climate_data = st.session_state.project_data.get("climate_data", {})
411
+ ground_temperatures = climate_data.get("ground_temperatures", {})
412
+ depth = "2" # Default depth
413
+ if depth not in ground_temperatures or not ground_temperatures[depth]:
414
+ logger.warning(f"No ground temperature data for depth {depth} m for {month}/{day}/{hour}. Using default 18°C.")
415
+ ground_temp = 18.0
416
+ else:
417
+ ground_temp = ground_temperatures[depth][month-1] if len(ground_temperatures[depth]) >= month else 18.0
418
+ comp_result["ground_temp"] = round(ground_temp, 2)
419
+ logger.info(f"Ground-contact component {comp_result['component_id']} at {month}/{day}/{hour}: ground_temp={ground_temp:.2f}°C")
420
+ component_results.append(comp_result)
421
+ continue
422
+
423
+ # Calculate sol-air temperature for opaque surfaces (non-ground-contact)
424
+ if comp.get('type', '').lower() in ['walls', 'roofs'] and not comp.get('ground_contact', False):
425
  T_sol_air = CTFCalculator.calculate_sol_air_temperature(
426
  outdoor_temp, I_t, absorptivity, emissivity or 0.9,
427
  h_o, dew_point, total_sky_cover
428
  )
429
  comp_result["sol_air_temp"] = round(T_sol_air, 2)
430
  logger.info(f"Sol-air temp for {comp_result['component_id']} at {month}/{day}/{hour}: {T_sol_air:.2f}°C")
431
+
432
  # Calculate solar heat gain for fenestration
433
  elif comp.get('type', '').lower() in ['windows', 'skylights']:
434
  glazing_type = self.GLAZING_TYPE_MAPPING.get(comp.get('fenestration', ''), 'Single Clear')
 
442
  f"I_t={I_t:.2f}, iac={iac})")
443
 
444
  component_results.append(comp_result)
445
+
446
  except Exception as e:
447
  component_name = comp.get('name', 'unknown_component')
448
  logger.error(f"Error processing component {component_name} at {month}/{day}/{hour}: {str(e)}")