mabuseif commited on
Commit
d35dbe4
·
verified ·
1 Parent(s): e761a24

Update data/climate_data.py

Browse files
Files changed (1) hide show
  1. data/climate_data.py +60 -43
data/climate_data.py CHANGED
@@ -92,6 +92,7 @@ class ClimateLocation:
92
  self.longitude = kwargs.get("longitude")
93
  self.elevation = kwargs.get("elevation")
94
  self.time_zone = kwargs.get("time_zone", 0.0) # Default to 0.0 if not provided
 
95
  self.typical_extreme_periods = typical_extreme_periods
96
  self.ground_temperatures = ground_temperatures
97
 
@@ -136,9 +137,6 @@ class ClimateLocation:
136
  # Log wind speed diagnostics
137
  logger.info(f"Wind speed stats: min={wind_speed.min():.1f}, max={wind_speed.max():.1f}, mean={self.wind_speed:.1f}")
138
 
139
- # Assign climate zone
140
- self.climate_zone = ClimateData.assign_climate_zone(self.heating_degree_days, self.cooling_degree_days, np.nanmean(humidity))
141
-
142
  # Store hourly data with enhanced fields
143
  self.hourly_data = []
144
  for i in range(len(months)):
@@ -359,6 +357,7 @@ class ClimateData:
359
  # Clear invalid session_state["climate_data"] to prevent validation errors
360
  if "climate_data" in session_state and not all(key in session_state["climate_data"] for key in ["id", "country", "city"]):
361
  st.warning("Clearing invalid climate data from session state.")
 
362
  del session_state["climate_data"]
363
 
364
  uploaded_file = st.file_uploader("Upload EPW File", type=["epw"])
@@ -376,16 +375,18 @@ class ClimateData:
376
  # Parse header
377
  header = next(line for line in epw_lines if line.startswith("LOCATION"))
378
  header_parts = header.split(",")
 
 
379
  city = header_parts[1].strip() or "Unknown"
380
  # Clean city name by removing suffixes like '.Racecourse'
381
  city = re.sub(r'\..*', '', city)
382
  state_province = header_parts[2].strip() or "Unknown"
383
  country = header_parts[3].strip() or "Unknown"
384
-
385
- latitude = float(header_parts[6])
386
- longitude = float(header_parts[7])
387
- elevation = float(header_parts[8])
388
  time_zone = float(header_parts[5]) if header_parts[5].strip() and ClimateData.is_numeric(header_parts[5]) else 0.0
 
389
 
390
  # Parse TYPICAL/EXTREME PERIODS
391
  typical_extreme_periods = {}
@@ -485,7 +486,8 @@ class ClimateData:
485
  latitude=latitude,
486
  longitude=longitude,
487
  elevation=elevation,
488
- time_zone=time_zone
 
489
  )
490
  self.add_location(location)
491
  climate_data_dict = location.to_dict()
@@ -493,50 +495,64 @@ class ClimateData:
493
  raise ValueError("Invalid climate data extracted from EPW file.")
494
  session_state["climate_data"] = climate_data_dict
495
  st.success("Climate data extracted from EPW file!")
 
496
 
497
  except Exception as e:
498
  st.error(f"Error processing EPW file: {str(e)}. Ensure it has 8760 hourly records and correct format.")
 
499
 
500
- elif "climate_data" in session_state and self.validate_climate_data(session_state["climate_data"]):
501
  # Reconstruct from session_state
502
  climate_data_dict = session_state["climate_data"]
503
-
504
- # Rebuild epw_data from hourly_data with full EPW column structure
505
- hourly_data = climate_data_dict["hourly_data"]
506
- # Create a DataFrame with 35 columns (0 to 34), initialized with NaN
507
- epw_data = pd.DataFrame(np.nan, index=range(len(hourly_data)), columns=range(35))
508
- # Populate relevant columns with hourly_data
509
- epw_data[1] = [d["month"] for d in hourly_data] # Month
510
- epw_data[2] = [d["day"] for d in hourly_data] # Day
511
- epw_data[3] = [d["hour"] for d in hourly_data] # Hour
512
- epw_data[6] = [d["dry_bulb"] for d in hourly_data] # Dry-bulb temperature
513
- epw_data[8] = [d["relative_humidity"] for d in hourly_data] # Relative humidity
514
- epw_data[9] = [d["atmospheric_pressure"] for d in hourly_data] # Pressure
515
- epw_data[13] = [d["global_horizontal_radiation"] for d in hourly_data] # Global horizontal radiation
516
- epw_data[20] = [d["wind_direction"] for d in hourly_data] # Wind direction
517
- epw_data[21] = [d["wind_speed"] for d in hourly_data] # Wind speed
518
-
519
- # Create ClimateLocation with reconstructed epw_data
520
- location = ClimateLocation(
521
- epw_file=epw_data,
522
- typical_extreme_periods=climate_data_dict["typical_extreme_periods"],
523
- ground_temperatures=climate_data_dict["ground_temperatures"],
524
- id=climate_data_dict["id"],
525
- country=climate_data_dict["country"],
526
- state_province=climate_data_dict["state_province"],
527
- city=climate_data_dict["city"],
528
- latitude=climate_data_dict["latitude"],
529
- longitude=climate_data_dict["longitude"],
530
- elevation=climate_data_dict["elevation"],
531
- time_zone=climate_data_dict["time_zone"]
532
- )
533
- # Override hourly_data to ensure consistency
534
- location.hourly_data = climate_data_dict["hourly_data"]
535
- self.add_location(location)
536
- st.info("Displaying previously extracted climate data.")
 
 
 
 
 
 
 
 
 
 
 
537
 
538
  # Display tabs if location and epw_data are available
539
  if location and epw_data is not None:
 
540
  tab1, tab2, tab3, tab4, tab5 = st.tabs([
541
  "General Information",
542
  "Psychrometric Chart",
@@ -562,6 +578,7 @@ class ClimateData:
562
 
563
  else:
564
  st.info("No climate data available. Please upload an EPW file to proceed.")
 
565
 
566
  def display_design_conditions(self, location: ClimateLocation):
567
  """Display design conditions for HVAC calculations using styled HTML."""
 
92
  self.longitude = kwargs.get("longitude")
93
  self.elevation = kwargs.get("elevation")
94
  self.time_zone = kwargs.get("time_zone", 0.0) # Default to 0.0 if not provided
95
+ self.climate_zone = kwargs.get("climate_zone", "Unknown") # Use provided climate_zone
96
  self.typical_extreme_periods = typical_extreme_periods
97
  self.ground_temperatures = ground_temperatures
98
 
 
137
  # Log wind speed diagnostics
138
  logger.info(f"Wind speed stats: min={wind_speed.min():.1f}, max={wind_speed.max():.1f}, mean={self.wind_speed:.1f}")
139
 
 
 
 
140
  # Store hourly data with enhanced fields
141
  self.hourly_data = []
142
  for i in range(len(months)):
 
357
  # Clear invalid session_state["climate_data"] to prevent validation errors
358
  if "climate_data" in session_state and not all(key in session_state["climate_data"] for key in ["id", "country", "city"]):
359
  st.warning("Clearing invalid climate data from session state.")
360
+ logger.warning("Invalid climate_data in session_state, clearing.")
361
  del session_state["climate_data"]
362
 
363
  uploaded_file = st.file_uploader("Upload EPW File", type=["epw"])
 
375
  # Parse header
376
  header = next(line for line in epw_lines if line.startswith("LOCATION"))
377
  header_parts = header.split(",")
378
+ if len(header_parts) < 10:
379
+ raise ValueError("Invalid LOCATION header: too few fields.")
380
  city = header_parts[1].strip() or "Unknown"
381
  # Clean city name by removing suffixes like '.Racecourse'
382
  city = re.sub(r'\..*', '', city)
383
  state_province = header_parts[2].strip() or "Unknown"
384
  country = header_parts[3].strip() or "Unknown"
385
+ climate_zone = header_parts[8].strip() or "Unknown"
386
+ latitude = float(header_parts[6]) if header_parts[6].strip() and ClimateData.is_numeric(header_parts[6]) else 0.0
387
+ longitude = float(header_parts[7]) if header_parts[7].strip() and ClimateData.is_numeric(header_parts[7]) else 0.0
 
388
  time_zone = float(header_parts[5]) if header_parts[5].strip() and ClimateData.is_numeric(header_parts[5]) else 0.0
389
+ elevation = float(header_parts[9]) if header_parts[9].strip() and ClimateData.is_numeric(header_parts[9]) else 0.0
390
 
391
  # Parse TYPICAL/EXTREME PERIODS
392
  typical_extreme_periods = {}
 
486
  latitude=latitude,
487
  longitude=longitude,
488
  elevation=elevation,
489
+ time_zone=time_zone,
490
+ climate_zone=climate_zone
491
  )
492
  self.add_location(location)
493
  climate_data_dict = location.to_dict()
 
495
  raise ValueError("Invalid climate data extracted from EPW file.")
496
  session_state["climate_data"] = climate_data_dict
497
  st.success("Climate data extracted from EPW file!")
498
+ logger.info("Successfully processed EPW file and stored in session_state.")
499
 
500
  except Exception as e:
501
  st.error(f"Error processing EPW file: {str(e)}. Ensure it has 8760 hourly records and correct format.")
502
+ logger.error(f"EPW processing error: {str(e)}")
503
 
504
+ elif "climate_data" in session_state:
505
  # Reconstruct from session_state
506
  climate_data_dict = session_state["climate_data"]
507
+ if not self.validate_climate_data(climate_data_dict):
508
+ st.error("Stored climate data is invalid. Please upload a new EPW file.")
509
+ logger.error("Validation failed for session_state.climate_data: %s", climate_data_dict.get("id", "Unknown"))
510
+ session_state["climate_data"] = {} # Clear invalid data
511
+ else:
512
+ try:
513
+ # Rebuild epw_data from hourly_data with full EPW column structure
514
+ hourly_data = climate_data_dict["hourly_data"]
515
+ # Create a DataFrame with 35 columns (0 to 34), initialized with NaN
516
+ epw_data = pd.DataFrame(np.nan, index=range(len(hourly_data)), columns=range(35))
517
+ # Populate relevant columns with hourly_data
518
+ epw_data[1] = [d["month"] for d in hourly_data] # Month
519
+ epw_data[2] = [d["day"] for d in hourly_data] # Day
520
+ epw_data[3] = [d["hour"] for d in hourly_data] # Hour
521
+ epw_data[6] = [d["dry_bulb"] for d in hourly_data] # Dry-bulb temperature
522
+ epw_data[8] = [d["relative_humidity"] for d in hourly_data] # Relative humidity
523
+ epw_data[9] = [d["atmospheric_pressure"] for d in hourly_data] # Pressure
524
+ epw_data[13] = [d["global_horizontal_radiation"] for d in hourly_data] # Global horizontal radiation
525
+ epw_data[20] = [d["wind_direction"] for d in hourly_data] # Wind direction
526
+ epw_data[21] = [d["wind_speed"] for d in hourly_data] # Wind speed
527
+
528
+ # Create ClimateLocation with reconstructed epw_data
529
+ location = ClimateLocation(
530
+ epw_file=epw_data,
531
+ typical_extreme_periods=climate_data_dict["typical_extreme_periods"],
532
+ ground_temperatures=climate_data_dict["ground_temperatures"],
533
+ id=climate_data_dict["id"],
534
+ country=climate_data_dict["country"],
535
+ state_province=climate_data_dict["state_province"],
536
+ city=climate_data_dict["city"],
537
+ latitude=climate_data_dict["latitude"],
538
+ longitude=climate_data_dict["longitude"],
539
+ elevation=climate_data_dict["elevation"],
540
+ time_zone=climate_data_dict["time_zone"],
541
+ climate_zone=climate_data_dict["climate_zone"]
542
+ )
543
+ # Override hourly_data to ensure consistency
544
+ location.hourly_data = climate_data_dict["hourly_data"]
545
+ self.add_location(location)
546
+ st.info("Displaying previously extracted climate data.")
547
+ logger.info("Successfully reconstructed climate data from session_state for ID: %s", climate_data_dict["id"])
548
+ except Exception as e:
549
+ st.error(f"Error reconstructing climate data: {str(e)}. Please upload a new EPW file.")
550
+ logger.error(f"Reconstruction error: {str(e)}")
551
+ session_state["climate_data"] = {} # Clear invalid data
552
 
553
  # Display tabs if location and epw_data are available
554
  if location and epw_data is not None:
555
+ logger.info("Displaying climate data tabs for location: %s", location.id)
556
  tab1, tab2, tab3, tab4, tab5 = st.tabs([
557
  "General Information",
558
  "Psychrometric Chart",
 
578
 
579
  else:
580
  st.info("No climate data available. Please upload an EPW file to proceed.")
581
+ logger.info("No climate data to display; prompting for EPW upload.")
582
 
583
  def display_design_conditions(self, location: ClimateLocation):
584
  """Display design conditions for HVAC calculations using styled HTML."""