Spaces:
Sleeping
Sleeping
Update utils/cooling_load.py
Browse files- utils/cooling_load.py +90 -64
utils/cooling_load.py
CHANGED
|
@@ -27,6 +27,26 @@ class CoolingLoadCalculator:
|
|
| 27 |
self.ashrae_tables = ASHRAETables()
|
| 28 |
self.heat_transfer = HeatTransferCalculations()
|
| 29 |
self.hours = list(range(24))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
def calculate_hourly_cooling_loads(
|
| 32 |
self,
|
|
@@ -67,21 +87,10 @@ class CoolingLoadCalculator:
|
|
| 67 |
}
|
| 68 |
|
| 69 |
try:
|
| 70 |
-
# Validate
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
raise ValueError(f"Invalid latitude format: {latitude}. Expected format: '24N', '36N', or '48N'")
|
| 75 |
-
if latitude not in valid_latitudes:
|
| 76 |
-
logger.warning(f"Latitude {latitude} not in {valid_latitudes}. Defaulting to '24N'")
|
| 77 |
-
latitude = '24N'
|
| 78 |
-
|
| 79 |
-
valid_months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
|
| 80 |
-
month = outdoor_conditions.get('month', 'JUL').upper()
|
| 81 |
-
if month not in valid_months:
|
| 82 |
-
raise ValueError(f"Invalid month: {month}. Must be one of {valid_months}")
|
| 83 |
-
|
| 84 |
-
logger.debug(f"Using latitude={latitude}, month={month} for calculations")
|
| 85 |
|
| 86 |
# Calculate loads for walls
|
| 87 |
for wall in building_components.get('walls', []):
|
|
@@ -316,6 +325,10 @@ class CoolingLoadCalculator:
|
|
| 316 |
Cooling load in Watts
|
| 317 |
"""
|
| 318 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
cltd = self.ashrae_tables.calculate_corrected_cltd_wall(
|
| 320 |
wall_group=wall.wall_group,
|
| 321 |
orientation=wall.orientation.value,
|
|
@@ -357,6 +370,11 @@ class CoolingLoadCalculator:
|
|
| 357 |
Cooling load in Watts
|
| 358 |
"""
|
| 359 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 360 |
# Validate and map roof_group
|
| 361 |
valid_roof_groups = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
|
| 362 |
roof_group = roof.roof_group
|
|
@@ -366,12 +384,6 @@ class CoolingLoadCalculator:
|
|
| 366 |
else:
|
| 367 |
raise ValueError(f"Invalid roof group: {roof_group}. Must be one of {valid_roof_groups}")
|
| 368 |
|
| 369 |
-
# Validate and map latitude
|
| 370 |
-
valid_latitudes = ['24N', '36N', '48N']
|
| 371 |
-
if latitude not in valid_latitudes:
|
| 372 |
-
logger.warning(f"Latitude {latitude} not in {valid_latitudes}. Defaulting to '24N'")
|
| 373 |
-
latitude = '24N'
|
| 374 |
-
|
| 375 |
cltd = self.ashrae_tables.calculate_corrected_cltd_roof(
|
| 376 |
roof_group=roof_group,
|
| 377 |
hour=hour,
|
|
@@ -414,20 +426,10 @@ class CoolingLoadCalculator:
|
|
| 414 |
Dictionary with conduction and solar loads in Watts
|
| 415 |
"""
|
| 416 |
try:
|
| 417 |
-
# Validate
|
| 418 |
-
|
| 419 |
-
month_upper =
|
| 420 |
-
|
| 421 |
-
raise ValueError(f"Invalid month: {month}. Must be one of {valid_months}")
|
| 422 |
-
|
| 423 |
-
# Validate latitude
|
| 424 |
-
valid_latitudes = ['24N', '36N', '48N']
|
| 425 |
-
scl_latitude = latitude
|
| 426 |
-
if not isinstance(latitude, str) or '_' in latitude:
|
| 427 |
-
raise ValueError(f"Invalid latitude format: {latitude}. Expected format: '24N', '36N', or '48N'")
|
| 428 |
-
if latitude not in valid_latitudes:
|
| 429 |
-
logger.warning(f"Latitude {latitude} not in {valid_latitudes}. Defaulting to '24N'")
|
| 430 |
-
scl_latitude = '24N'
|
| 431 |
|
| 432 |
# Conduction load
|
| 433 |
delta_t = outdoor_temp - indoor_temp
|
|
@@ -437,26 +439,40 @@ class CoolingLoadCalculator:
|
|
| 437 |
# Note: Solar altitude is not computed directly, as ASHRAE SCL tables (via get_scl)
|
| 438 |
# account for solar geometry effects based on month, orientation, hour, and latitude.
|
| 439 |
logger.debug(f"Calling get_scl with month={month_upper}, orientation={window.orientation.value}, hour={hour}, latitude={scl_latitude}")
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
|
|
|
| 452 |
scl = self.ashrae_tables.get_scl(
|
| 453 |
-
month=
|
| 454 |
orientation=window.orientation.value,
|
| 455 |
hour=hour,
|
| 456 |
-
latitude=
|
| 457 |
)
|
| 458 |
-
|
| 459 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 460 |
|
| 461 |
solar_load = window.area * window.shgc * scl * shading_coefficient
|
| 462 |
|
|
@@ -722,7 +738,7 @@ if __name__ == "__main__":
|
|
| 722 |
'relative_humidity': 50.0,
|
| 723 |
'ground_temperature': 20.0,
|
| 724 |
'month': 'Jul',
|
| 725 |
-
'latitude': '
|
| 726 |
'wind_speed': 4
|
| 727 |
}
|
| 728 |
|
|
@@ -741,15 +757,25 @@ if __name__ == "__main__":
|
|
| 741 |
|
| 742 |
building_volume = 300.0
|
| 743 |
|
| 744 |
-
#
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
| 752 |
-
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
self.ashrae_tables = ASHRAETables()
|
| 28 |
self.heat_transfer = HeatTransferCalculations()
|
| 29 |
self.hours = list(range(24))
|
| 30 |
+
self.valid_latitudes = ['24N', '36N', '48N']
|
| 31 |
+
self.valid_months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
|
| 32 |
+
|
| 33 |
+
def validate_latitude(self, latitude: str) -> str:
|
| 34 |
+
"""Validate and return a valid latitude."""
|
| 35 |
+
if not isinstance(latitude, str) or '_' in latitude:
|
| 36 |
+
logger.warning(f"Invalid latitude format: {latitude}. Defaulting to '24N'")
|
| 37 |
+
return '24N'
|
| 38 |
+
if latitude not in self.valid_latitudes:
|
| 39 |
+
logger.warning(f"Latitude {latitude} not in {self.valid_latitudes}. Defaulting to '24N'")
|
| 40 |
+
return '24N'
|
| 41 |
+
return latitude
|
| 42 |
+
|
| 43 |
+
def validate_month(self, month: str) -> str:
|
| 44 |
+
"""Validate and return a valid month in uppercase."""
|
| 45 |
+
month_upper = month.upper()
|
| 46 |
+
if month_upper not in self.valid_months:
|
| 47 |
+
logger.warning(f"Invalid month: {month}. Defaulting to 'JUL'")
|
| 48 |
+
return 'JUL'
|
| 49 |
+
return month_upper
|
| 50 |
|
| 51 |
def calculate_hourly_cooling_loads(
|
| 52 |
self,
|
|
|
|
| 87 |
}
|
| 88 |
|
| 89 |
try:
|
| 90 |
+
# Validate inputs
|
| 91 |
+
latitude = self.validate_latitude(outdoor_conditions.get('latitude', '24N'))
|
| 92 |
+
month = self.validate_month(outdoor_conditions.get('month', 'JUL'))
|
| 93 |
+
logger.debug(f"calculate_hourly_cooling_loads: latitude={latitude}, month={month}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
# Calculate loads for walls
|
| 96 |
for wall in building_components.get('walls', []):
|
|
|
|
| 325 |
Cooling load in Watts
|
| 326 |
"""
|
| 327 |
try:
|
| 328 |
+
latitude = self.validate_latitude(latitude)
|
| 329 |
+
month = self.validate_month(month)
|
| 330 |
+
logger.debug(f"calculate_wall_cooling_load: latitude={latitude}, month={month}")
|
| 331 |
+
|
| 332 |
cltd = self.ashrae_tables.calculate_corrected_cltd_wall(
|
| 333 |
wall_group=wall.wall_group,
|
| 334 |
orientation=wall.orientation.value,
|
|
|
|
| 370 |
Cooling load in Watts
|
| 371 |
"""
|
| 372 |
try:
|
| 373 |
+
# Validate inputs
|
| 374 |
+
latitude = self.validate_latitude(latitude)
|
| 375 |
+
month = self.validate_month(month)
|
| 376 |
+
logger.debug(f"calculate_roof_cooling_load: latitude={latitude}, month={month}")
|
| 377 |
+
|
| 378 |
# Validate and map roof_group
|
| 379 |
valid_roof_groups = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
|
| 380 |
roof_group = roof.roof_group
|
|
|
|
| 384 |
else:
|
| 385 |
raise ValueError(f"Invalid roof group: {roof_group}. Must be one of {valid_roof_groups}")
|
| 386 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
cltd = self.ashrae_tables.calculate_corrected_cltd_roof(
|
| 388 |
roof_group=roof_group,
|
| 389 |
hour=hour,
|
|
|
|
| 426 |
Dictionary with conduction and solar loads in Watts
|
| 427 |
"""
|
| 428 |
try:
|
| 429 |
+
# Validate inputs
|
| 430 |
+
scl_latitude = self.validate_latitude(latitude)
|
| 431 |
+
month_upper = self.validate_month(month)
|
| 432 |
+
logger.debug(f"calculate_window_cooling_load: latitude={scl_latitude}, month={month_upper}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
|
| 434 |
# Conduction load
|
| 435 |
delta_t = outdoor_temp - indoor_temp
|
|
|
|
| 439 |
# Note: Solar altitude is not computed directly, as ASHRAE SCL tables (via get_scl)
|
| 440 |
# account for solar geometry effects based on month, orientation, hour, and latitude.
|
| 441 |
logger.debug(f"Calling get_scl with month={month_upper}, orientation={window.orientation.value}, hour={hour}, latitude={scl_latitude}")
|
| 442 |
+
|
| 443 |
+
# Try different month formats to handle potential get_scl issues
|
| 444 |
+
month_formats = [
|
| 445 |
+
(month_upper, "uppercase"), # e.g., 'JUL'
|
| 446 |
+
(month_upper.capitalize(), "capitalized"), # e.g., 'Jul'
|
| 447 |
+
(str({'JAN': 1, 'FEB': 2, 'MAR': 3, 'APR': 4, 'MAY': 5, 'JUN': 6,
|
| 448 |
+
'JUL': 7, 'AUG': 8, 'SEP': 9, 'OCT': 10, 'NOV': 11, 'DEC': 12}[month_upper]), "numeric") # e.g., '7'
|
| 449 |
+
]
|
| 450 |
+
|
| 451 |
+
scl = None
|
| 452 |
+
for month_value, format_name in month_formats:
|
| 453 |
+
try:
|
| 454 |
+
logger.debug(f"Trying get_scl with month format '{format_name}': month={month_value}")
|
| 455 |
scl = self.ashrae_tables.get_scl(
|
| 456 |
+
month=month_value,
|
| 457 |
orientation=window.orientation.value,
|
| 458 |
hour=hour,
|
| 459 |
+
latitude=scl_latitude
|
| 460 |
)
|
| 461 |
+
logger.debug(f"Success with month format '{format_name}'")
|
| 462 |
+
break
|
| 463 |
+
except Exception as e:
|
| 464 |
+
logger.warning(f"get_scl failed with month format '{format_name}': {str(e)}")
|
| 465 |
+
continue
|
| 466 |
+
|
| 467 |
+
# Final fallback: Use latitude='24N' with default month='JUL'
|
| 468 |
+
if scl is None:
|
| 469 |
+
logger.warning(f"All month formats failed. Retrying with fallback latitude='24N', month='JUL'")
|
| 470 |
+
scl = self.ashrae_tables.get_scl(
|
| 471 |
+
month='JUL',
|
| 472 |
+
orientation=window.orientation.value,
|
| 473 |
+
hour=hour,
|
| 474 |
+
latitude='24N'
|
| 475 |
+
)
|
| 476 |
|
| 477 |
solar_load = window.area * window.shgc * scl * shading_coefficient
|
| 478 |
|
|
|
|
| 738 |
'relative_humidity': 50.0,
|
| 739 |
'ground_temperature': 20.0,
|
| 740 |
'month': 'Jul',
|
| 741 |
+
'latitude': '24N',
|
| 742 |
'wind_speed': 4
|
| 743 |
}
|
| 744 |
|
|
|
|
| 757 |
|
| 758 |
building_volume = 300.0
|
| 759 |
|
| 760 |
+
# Test with multiple latitudes and months
|
| 761 |
+
test_cases = [
|
| 762 |
+
{'latitude': '24N', 'month': 'Jul'},
|
| 763 |
+
{'latitude': '36N', 'month': 'Jul'},
|
| 764 |
+
{'latitude': '48N', 'month': 'Jan'},
|
| 765 |
+
{'latitude': 'invalid', 'month': 'invalid'} # Test invalid inputs
|
| 766 |
+
]
|
| 767 |
+
|
| 768 |
+
for case in test_cases:
|
| 769 |
+
outdoor_conditions['latitude'] = case['latitude']
|
| 770 |
+
outdoor_conditions['month'] = case['month']
|
| 771 |
+
try:
|
| 772 |
+
hourly_loads = calculator.calculate_hourly_cooling_loads(
|
| 773 |
+
building_components,
|
| 774 |
+
outdoor_conditions,
|
| 775 |
+
indoor_conditions,
|
| 776 |
+
internal_loads,
|
| 777 |
+
building_volume
|
| 778 |
+
)
|
| 779 |
+
print(f"Success for latitude={case['latitude']}, month={case['month']}: Hourly Loads calculated")
|
| 780 |
+
except Exception as e:
|
| 781 |
+
print(f"Error for latitude={case['latitude']}, month={case['month']}: {str(e)}")
|