mabuseif commited on
Commit
cc5de30
·
verified ·
1 Parent(s): fd1943c

Update data/climate_data.py

Browse files
Files changed (1) hide show
  1. data/climate_data.py +120 -88
data/climate_data.py CHANGED
@@ -223,94 +223,126 @@ class ClimateData:
223
  return wet_bulb
224
 
225
  def display_climate_input(self, session_state: Dict[str, Any]):
226
- """Display Streamlit interface for EPW upload and visualizations."""
227
- st.title("Climate Data Analysis")
228
-
229
- if not session_state.building_info.get("country") or not session_state.building_info.get("city"):
230
- st.warning("Please enter country and city in Building Information first.")
231
- st.button("Go to Building Information", on_click=lambda: setattr(session_state, "page", "Building Information"))
232
- return
233
-
234
- st.subheader(f"Location: {session_state.building_info['country']}, {session_state.building_info['city']}")
235
- uploaded_file = st.file_uploader("Upload EPW File", type=["epw"])
236
-
237
- if uploaded_file:
238
- try:
239
- epw_content = uploaded_file.read().decode("utf-8")
240
- epw_lines = epw_content.splitlines()
241
- header = next(line for line in epw_lines if line.startswith("LOCATION"))
242
- header_parts = header.split(",")
243
- city = header_parts[1].strip()
244
- state_province = header_parts[2].strip() or "N/A"
245
- country = header_parts[3].strip()
246
- latitude = float(header_parts[6])
247
- longitude = float(header_parts[7])
248
- elevation = float(header_parts[8])
249
-
250
- data_start_idx = next(i for i, line in enumerate(epw_lines) if line.startswith("DATA PERIODS")) + 1
251
- epw_data = pd.read_csv(StringIO("\n".join(epw_lines[data_start_idx:])), header=None, dtype=str)
252
-
253
- if len(epw_data) != 8760:
254
- raise ValueError(f"EPW file has {len(epw_data)} records, expected 8760.")
255
- if len(epw_data.columns) != 35:
256
- raise ValueError(f"EPW file has {len(epw_data.columns)} columns, expected 35.")
257
-
258
- for col in [1, 6, 8, 9, 13, 20, 21]:
259
- epw_data[col] = pd.to_numeric(epw_data[col], errors='coerce')
260
- if epw_data[col].isna().all():
261
- raise ValueError(f"Column {col} contains only non-numeric or missing data.")
262
-
263
- location = ClimateLocation(
264
- epw_file=epw_data,
265
- id=f"{country[:1].upper()}{city[:3].upper()}",
266
- country=country,
267
- state_province=state_province,
268
- city=city,
269
- latitude=latitude,
270
- longitude=longitude,
271
- elevation=elevation
272
- )
273
- self.add_location(location)
274
- climate_data_dict = location.to_dict()
275
- if not self.validate_climate_data(climate_data_dict):
276
- raise ValueError("Invalid climate data extracted from EPW file.")
277
- session_state["climate_data"] = climate_data_dict
278
- st.success("Climate data extracted from EPW file!")
279
-
280
- tab1, tab2, tab3, tab4, tab5 = st.tabs([
281
- "General Information",
282
- "Psychrometric Chart",
283
- "Sun Shading Chart",
284
- "Temperature Range",
285
- "Wind Rose"
286
- ])
287
-
288
- with tab1:
289
- self.display_design_conditions(location)
290
-
291
- with tab2:
292
- self.plot_psychrometric_chart(location, epw_data)
293
-
294
- with tab3:
295
- self.plot_sun_shading_chart(location)
296
-
297
- with tab4:
298
- self.plot_temperature_range(location, epw_data)
299
-
300
- with tab5:
301
- self.plot_wind_rose(epw_data)
302
-
303
- except Exception as e:
304
- st.error(f"Error processing EPW file: {str(e)}. Ensure it has 8760 hourly records and correct format.")
305
-
306
- col1, col2 = st.columns(2)
307
- with col1:
308
- st.button("Back to Building Information", on_click=lambda: setattr(session_state, "page", "Building Information"))
309
- with col2:
310
- if self.locations:
311
- st.button("Continue to Building Components", on_click=lambda: setattr(session_state, "page", "Building Components"))
312
- else:
313
- st.button("Continue to Building Components", disabled=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
 
315
  def display_design_conditions(self, location: ClimateLocation):
316
  """Display design conditions for HVAC calculations using Markdown."""
 
223
  return wet_bulb
224
 
225
  def display_climate_input(self, session_state: Dict[str, Any]):
226
+ """Display Streamlit interface for EPW upload and visualizations."""
227
+ st.title("Climate Data Analysis")
228
+
229
+ if not session_state.building_info.get("country") or not session_state.building_info.get("city"):
230
+ st.warning("Please enter country and city in Building Information first.")
231
+ st.button("Go to Building Information", on_click=lambda: setattr(session_state, "page", "Building Information"))
232
+ return
233
+
234
+ st.subheader(f"Location: {session_state.building_info['country']}, {session_state.building_info['city']}")
235
+ uploaded_file = st.file_uploader("Upload EPW File", type=["epw"])
236
+
237
+ # Initialize location and epw_data for display
238
+ location = None
239
+ epw_data = None
240
+
241
+ if uploaded_file:
242
+ try:
243
+ # Process new EPW file (existing code)
244
+ epw_content = uploaded_file.read().decode("utf-8")
245
+ epw_lines = epw_content.splitlines()
246
+ header = next(line for line in epw_lines if line.startswith("LOCATION"))
247
+ header_parts = header.split(",")
248
+ city = header_parts[1].strip()
249
+ state_province = header_parts[2].strip() or "N/A"
250
+ country = header_parts[3].strip()
251
+ latitude = float(header_parts[6])
252
+ longitude = float(header_parts[7])
253
+ elevation = float(header_parts[8])
254
+
255
+ data_start_idx = next(i for i, line in enumerate(epw_lines) if line.startswith("DATA PERIODS")) + 1
256
+ epw_data = pd.read_csv(StringIO("\n".join(epw_lines[data_start_idx:])), header=None, dtype=str)
257
+
258
+ if len(epw_data) != 8760:
259
+ raise ValueError(f"EPW file has {len(epw_data)} records, expected 8760.")
260
+ if len(epw_data.columns) != 35:
261
+ raise ValueError(f"EPW file has {len(epw_data.columns)} columns, expected 35.")
262
+
263
+ for col in [1, 6, 8, 9, 13, 20, 21]:
264
+ epw_data[col] = pd.to_numeric(epw_data[col], errors='coerce')
265
+ if epw_data[col].isna().all():
266
+ raise ValueError(f"Column {col} contains only non-numeric or missing data.")
267
+
268
+ location = ClimateLocation(
269
+ epw_file=epw_data,
270
+ id=f"{country[:1].upper()}{city[:3].upper()}",
271
+ country=country,
272
+ state_province=state_province,
273
+ city=city,
274
+ latitude=latitude,
275
+ longitude=longitude,
276
+ elevation=elevation
277
+ )
278
+ self.add_location(location)
279
+ climate_data_dict = location.to_dict()
280
+ if not self.validate_climate_data(climate_data_dict):
281
+ raise ValueError("Invalid climate data extracted from EPW file.")
282
+ session_state["climate_data"] = climate_data_dict
283
+ st.success("Climate data extracted from EPW file!")
284
+
285
+ except Exception as e:
286
+ st.error(f"Error processing EPW file: {str(e)}. Ensure it has 8760 hourly records and correct format.")
287
+
288
+ # Check for existing data in session_state
289
+ elif "climate_data" in session_state and self.validate_climate_data(session_state["climate_data"]):
290
+ # Reconstruct location and epw_data from session_state
291
+ climate_data_dict = session_state["climate_data"]
292
+ location = ClimateLocation(
293
+ epw_file=pd.DataFrame(), # Empty DataFrame since hourly_data is in climate_data_dict
294
+ **{k: v for k, v in climate_data_dict.items() if k != "hourly_data"}
295
+ )
296
+ location.hourly_data = climate_data_dict["hourly_data"]
297
+ self.add_location(location)
298
+
299
+ # Reconstruct epw_data for plotting
300
+ hourly_data = climate_data_dict["hourly_data"]
301
+ epw_data = pd.DataFrame({
302
+ 1: [d["month"] for d in hourly_data], # Month
303
+ 6: [d["dry_bulb"] for d in hourly_data], # Dry-bulb temperature
304
+ 8: [d["relative_humidity"] for d in hourly_data], # Relative humidity
305
+ 13: [d["global_horizontal_radiation"] for d in hourly_data], # Global horizontal radiation
306
+ 20: [d["wind_direction"] for d in hourly_data], # Wind direction
307
+ 21: [d["wind_speed"] for d in hourly_data], # Wind speed
308
+ 9: [climate_data_dict["pressure"]] * len(hourly_data) # Pressure (mean value)
309
+ })
310
+ st.info("Displaying previously extracted climate data.")
311
+
312
+ # Display tabs if location and epw_data are available
313
+ if location and epw_data is not None:
314
+ tab1, tab2, tab3, tab4, tab5 = st.tabs([
315
+ "General Information",
316
+ "Psychrometric Chart",
317
+ "Sun Shading Chart",
318
+ "Temperature Range",
319
+ "Wind Rose"
320
+ ])
321
+
322
+ with tab1:
323
+ self.display_design_conditions(location)
324
+
325
+ with tab2:
326
+ self.plot_psychrometric_chart(location, epw_data)
327
+
328
+ with tab3:
329
+ self.plot_sun_shading_chart(location)
330
+
331
+ with tab4:
332
+ self.plot_temperature_range(location, epw_data)
333
+
334
+ with tab5:
335
+ self.plot_wind_rose(epw_data)
336
+
337
+ # Navigation buttons
338
+ col1, col2 = st.columns(2)
339
+ with col1:
340
+ st.button("Back to Building Information", on_click=lambda: setattr(session_state, "page", "Building Information"))
341
+ with col2:
342
+ if self.locations:
343
+ st.button("Continue to Building Components", on_click=lambda: setattr(session_state, "page", "Building Components"))
344
+ else:
345
+ st.button("Continue to Building Components", disabled=True)
346
 
347
  def display_design_conditions(self, location: ClimateLocation):
348
  """Display design conditions for HVAC calculations using Markdown."""