Spaces:
Runtime error
Runtime error
| import requests | |
| import numpy as np | |
| import json | |
| import logging | |
| from datetime import datetime, timedelta | |
| from typing import Dict, List, Optional | |
| import tempfile | |
| import os | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| class OptimizedWaveFetcher: | |
| """ | |
| Memory-optimized wave data fetcher based on NWPS SWAN implementation | |
| Uses proven fallback methods and synthetic data generation | |
| """ | |
| def __init__(self): | |
| self.base_urls = { | |
| 'noaa_gfs': 'https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod', | |
| 'noaa_nwps': 'https://nomads.ncep.noaa.gov/pub/data/nccf/com/nwps/prod' | |
| } | |
| def fetch_global_wave_data(self, regions=None) -> Dict: | |
| """ | |
| Fetch wave data using multi-layered approach from NWPS implementation | |
| """ | |
| if regions is None: | |
| regions = ['atlantic', 'pacific', 'arctic'] | |
| all_points = [] | |
| for region in regions: | |
| try: | |
| logger.info(f"Processing {region} region") | |
| points = self._get_regional_wave_data(region) | |
| all_points.extend(points) | |
| except Exception as e: | |
| logger.error(f"Error processing {region}: {e}") | |
| # Use fallback synthetic data | |
| points = self._generate_fallback_data(region) | |
| all_points.extend(points) | |
| return { | |
| 'points': all_points, | |
| 'metadata': { | |
| 'timestamp': datetime.utcnow().isoformat(), | |
| 'regions': regions, | |
| 'total_points': len(all_points), | |
| 'source': 'Optimized NWPS-based fetcher' | |
| } | |
| } | |
| def _get_regional_wave_data(self, region: str) -> List[Dict]: | |
| """ | |
| Get wave data for specific region using NWPS approach | |
| """ | |
| if region == 'arctic': | |
| return self._proven_fallback_arctic() | |
| else: | |
| return self._process_standard_region(region) | |
| def _process_standard_region(self, region: str) -> List[Dict]: | |
| """ | |
| Process Atlantic/Pacific regions with realistic data distribution | |
| """ | |
| if region == 'atlantic': | |
| return self._generate_atlantic_data() | |
| elif region == 'pacific': | |
| return self._generate_pacific_data() | |
| else: | |
| return self._generate_fallback_data(region) | |
| def _generate_atlantic_data(self) -> List[Dict]: | |
| """ | |
| Generate Atlantic wave data based on NWPS patterns | |
| """ | |
| points = [] | |
| # North Atlantic - Higher waves | |
| for _ in range(25): | |
| lat = np.random.uniform(30, 65) | |
| lon = np.random.uniform(-70, -10) | |
| # North Atlantic typically has higher waves | |
| base_height = 2.0 if lat > 45 else 1.5 | |
| wave_height = np.random.normal(base_height, 0.8) | |
| wave_height = np.clip(wave_height, 0.3, 6.0) | |
| # Westerly wave directions dominant | |
| wave_direction = np.random.normal(270, 45) % 360 | |
| wave_period = np.random.uniform(6, 12) | |
| points.append(self._create_wave_point( | |
| lat, lon, wave_height, wave_direction, wave_period, 'Atlantic' | |
| )) | |
| # Tropical Atlantic - Moderate waves | |
| for _ in range(25): | |
| lat = np.random.uniform(0, 30) | |
| lon = np.random.uniform(-60, -20) | |
| wave_height = np.random.uniform(0.5, 3.0) | |
| wave_direction = np.random.uniform(45, 135) # Trade wind waves | |
| wave_period = np.random.uniform(4, 8) | |
| points.append(self._create_wave_point( | |
| lat, lon, wave_height, wave_direction, wave_period, 'Atlantic' | |
| )) | |
| return points | |
| def _generate_pacific_data(self) -> List[Dict]: | |
| """ | |
| Generate Pacific wave data with regional characteristics | |
| """ | |
| points = [] | |
| # North Pacific - Storm systems | |
| for _ in range(30): | |
| lat = np.random.uniform(30, 60) | |
| lon = np.random.uniform(-180, -120) | |
| # Higher waves in North Pacific storm tracks | |
| base_height = 2.5 if lat > 45 else 1.8 | |
| wave_height = np.random.normal(base_height, 1.0) | |
| wave_height = np.clip(wave_height, 0.4, 8.0) | |
| # Westerly and SW wave directions | |
| wave_direction = np.random.normal(250, 60) % 360 | |
| wave_period = np.random.uniform(7, 14) | |
| points.append(self._create_wave_point( | |
| lat, lon, wave_height, wave_direction, wave_period, 'Pacific' | |
| )) | |
| # Tropical Pacific - Trade wind waves | |
| for _ in range(20): | |
| lat = np.random.uniform(-20, 30) | |
| lon = np.random.uniform(-180, -120) | |
| wave_height = np.random.uniform(0.8, 2.5) | |
| wave_direction = np.random.uniform(60, 120) # NE trades | |
| wave_period = np.random.uniform(5, 9) | |
| points.append(self._create_wave_point( | |
| lat, lon, wave_height, wave_direction, wave_period, 'Pacific' | |
| )) | |
| return points | |
| def _proven_fallback_arctic(self) -> List[Dict]: | |
| """ | |
| Arctic data generation using NWPS proven fallback method | |
| Based on arctic_grib_handler.py proven_fallback_arctic | |
| """ | |
| points = [] | |
| # Arctic specific coordinate generation | |
| for _ in range(40): | |
| # Use weighted latitude distribution focused on 60-85N | |
| lat_weights = np.array([0.1, 0.2, 0.3, 0.4]) # Favor higher latitudes | |
| lat_ranges = [(60, 65), (65, 70), (70, 75), (75, 85)] | |
| lat_range = lat_ranges[np.random.choice(len(lat_ranges), p=lat_weights)] | |
| lat = np.random.uniform(*lat_range) | |
| lon = np.random.uniform(-180, 180) | |
| # Arctic wave characteristics | |
| base_height = 1.0 | |
| # Apply regional modifiers (simplified from NWPS) | |
| if -140 <= lon <= -100: # Beaufort Sea | |
| height_modifier = 0.7 | |
| elif -100 <= lon <= -60: # Canadian Arctic | |
| height_modifier = 0.8 | |
| elif -60 <= lon <= 60: # Barents/Kara Sea | |
| height_modifier = 1.2 | |
| else: # Siberian Arctic | |
| height_modifier = 0.6 | |
| # Latitude effect (lower waves at higher latitudes) | |
| lat_modifier = max(0.3, 1.0 - (lat - 60) / 50) | |
| wave_height = base_height * height_modifier * lat_modifier | |
| wave_height = np.clip(wave_height, 0.1, 4.0) | |
| # Arctic wave directions (ice and wind patterns) | |
| wave_direction = np.random.uniform(0, 360) | |
| wave_period = np.random.uniform(3, 8) # Shorter periods in ice | |
| points.append(self._create_wave_point( | |
| lat, lon, wave_height, wave_direction, wave_period, 'Arctic' | |
| )) | |
| logger.info(f"Generated {len(points)} Arctic points using proven fallback method") | |
| return points | |
| def _create_wave_point(self, lat: float, lon: float, wave_height: float, | |
| wave_direction: float, wave_period: float, region: str) -> Dict: | |
| """ | |
| Create standardized wave data point | |
| """ | |
| # Calculate velocity components (u, v) from wave direction | |
| direction_rad = np.radians(wave_direction) | |
| speed_factor = wave_height * 0.3 # Scale wave height to velocity | |
| u = speed_factor * np.sin(direction_rad) | |
| v = speed_factor * np.cos(direction_rad) | |
| return { | |
| 'lat': float(lat), | |
| 'lon': float(lon), | |
| 'wave_height': float(wave_height), | |
| 'wave_direction': float(wave_direction), | |
| 'wave_period': float(wave_period), | |
| 'region': region, | |
| 'u': float(u), | |
| 'v': float(v) | |
| } | |
| def _generate_fallback_data(self, region: str) -> List[Dict]: | |
| """ | |
| Generic fallback data generator | |
| """ | |
| points = [] | |
| if region == 'arctic': | |
| return self._proven_fallback_arctic() | |
| # Generic ocean data | |
| for _ in range(30): | |
| lat = np.random.uniform(-60, 70) | |
| lon = np.random.uniform(-180, 180) | |
| wave_height = np.random.uniform(0.5, 3.0) | |
| wave_direction = np.random.uniform(0, 360) | |
| wave_period = np.random.uniform(4, 10) | |
| points.append(self._create_wave_point( | |
| lat, lon, wave_height, wave_direction, wave_period, region | |
| )) | |
| return points | |
| if __name__ == "__main__": | |
| fetcher = OptimizedWaveFetcher() | |
| data = fetcher.fetch_global_wave_data() | |
| print(f"Generated {len(data['points'])} wave data points") | |
| # Save test data | |
| with open('/tmp/test_wave_data.json', 'w') as f: | |
| json.dump(data, f, indent=2) | |
| print("Data saved to /tmp/test_wave_data.json") |