//! Sample data and configurations for WeatherCast demo. //! //! Provides pre-configured scenarios for different types of weather //! predictions including global forecasts, regional high-resolution //! forecasts, and ensemble predictions. use weathercast_shared::{ AtmosphericState, GridPoint, MeshConfig, PredictionConfig, TrainingConfig, }; // ============================================================================ // Global Forecast Configurations // ============================================================================ /// Create a global medium-range forecast configuration. #[must_use] pub fn global_forecast() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig::from_refinement(5); // ~40km resolution let pred_config = PredictionConfig { lead_time: 240.0, // 10 days ensemble_size: 1, resolution: 0.25, time_step: 6.0, num_steps: 40, multi_scale: true, variables: vec![ "temperature".to_string(), "geopotential".to_string(), "humidity".to_string(), "wind_u".to_string(), "wind_v".to_string(), ], pressure_levels: vec![1000.0, 925.0, 850.0, 700.0, 500.0, 300.0, 200.0, 50.0], }; (mesh_config, pred_config) } /// Create a short-range global forecast (0-72h). #[must_use] pub fn global_short_range() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig::from_refinement(5); let pred_config = PredictionConfig { lead_time: 72.0, time_step: 3.0, num_steps: 24, ..PredictionConfig::default() }; (mesh_config, pred_config) } // ============================================================================ // Regional Forecast Configurations // ============================================================================ /// Create a regional high-resolution forecast for North America. #[must_use] pub fn regional_forecast() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig { refinement_levels: 6, num_nodes: 40962, num_edges: 122880, num_faces: 81920, avg_edge_length: 20.0, // ~20km multi_scale: true, regional_focus: Some((40.0, -100.0, 2000.0)), // Central US, 2000km radius }; let pred_config = PredictionConfig { lead_time: 48.0, // 2 days time_step: 1.0, // Hourly num_steps: 48, resolution: 0.1, // ~10km effective ensemble_size: 1, multi_scale: true, ..PredictionConfig::default() }; (mesh_config, pred_config) } /// Create a European regional forecast. #[must_use] pub fn european_regional() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig { refinement_levels: 6, num_nodes: 40962, num_edges: 122880, num_faces: 81920, avg_edge_length: 15.0, multi_scale: true, regional_focus: Some((50.0, 10.0, 1500.0)), // Central Europe }; let pred_config = PredictionConfig { lead_time: 72.0, time_step: 1.0, num_steps: 72, resolution: 0.1, ..PredictionConfig::default() }; (mesh_config, pred_config) } /// Create an Asian regional forecast. #[must_use] pub fn asian_regional() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig::regional(35.0, 135.0, 2000.0); // Japan/East Asia let pred_config = PredictionConfig { lead_time: 72.0, time_step: 3.0, num_steps: 24, ..PredictionConfig::default() }; (mesh_config, pred_config) } // ============================================================================ // Ensemble Forecast Configurations // ============================================================================ /// Create ensemble forecast configuration (50 members). #[must_use] pub fn ensemble_forecast() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig::from_refinement(4); // Coarser for ensemble let pred_config = PredictionConfig { lead_time: 360.0, // 15 days ensemble_size: 50, time_step: 6.0, num_steps: 60, resolution: 0.5, multi_scale: false, ..PredictionConfig::default() }; (mesh_config, pred_config) } /// Create large ensemble (100 members) for probabilistic forecasting. #[must_use] pub fn large_ensemble() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig::from_refinement(3); // Even coarser let pred_config = PredictionConfig { lead_time: 240.0, ensemble_size: 100, time_step: 12.0, num_steps: 20, resolution: 1.0, ..PredictionConfig::default() }; (mesh_config, pred_config) } // ============================================================================ // High-Resolution Configurations // ============================================================================ /// Create ultra high-resolution forecast (convection-permitting). #[must_use] pub fn high_resolution_forecast() -> (MeshConfig, PredictionConfig) { let mesh_config = MeshConfig { refinement_levels: 7, num_nodes: 163842, num_edges: 491520, num_faces: 327680, avg_edge_length: 5.0, // ~5km (convection-permitting) multi_scale: true, regional_focus: Some((40.0, -100.0, 500.0)), // Small regional domain }; let pred_config = PredictionConfig { lead_time: 24.0, // 1 day time_step: 0.5, // 30-minute steps num_steps: 48, resolution: 0.05, ensemble_size: 1, multi_scale: true, variables: vec![ "temperature".to_string(), "geopotential".to_string(), "humidity".to_string(), "wind_u".to_string(), "wind_v".to_string(), "precipitation".to_string(), "cloud_cover".to_string(), ], pressure_levels: vec![ 1000.0, 925.0, 850.0, 700.0, 600.0, 500.0, 400.0, 300.0, 250.0, 200.0, 150.0, 100.0, 50.0, ], }; (mesh_config, pred_config) } // ============================================================================ // Sample Atmospheric States // ============================================================================ /// Create initial state for mid-latitude cyclone. #[must_use] pub fn midlatitude_cyclone() -> AtmosphericState { AtmosphericState { temperature: vec![280.0, 278.0, 275.0, 265.0, 248.0, 225.0, 215.0, 200.0], geopotential: vec![0.0, 800.0, 1500.0, 3100.0, 5600.0, 9200.0, 11800.0, 20500.0], humidity: vec![0.015, 0.012, 0.008, 0.003, 0.001, 0.0002, 0.00005, 0.000001], wind_u: vec![-5.0, -8.0, -15.0, -25.0, -40.0, -50.0, -45.0, -25.0], wind_v: vec![10.0, 15.0, 20.0, 25.0, 20.0, 10.0, 5.0, 0.0], pressure_levels: vec![1000.0, 925.0, 850.0, 700.0, 500.0, 300.0, 200.0, 50.0], surface_pressure: 99000.0, // Low pressure center temperature_2m: 283.0, wind_u_10m: -5.0, wind_v_10m: 8.0, precipitation: 5.0, timestamp: 0.0, } } /// Create initial state for tropical cyclone. #[must_use] pub fn tropical_cyclone() -> AtmosphericState { AtmosphericState { temperature: vec![299.0, 297.0, 292.0, 280.0, 260.0, 228.0, 217.0, 195.0], geopotential: vec![0.0, 750.0, 1500.0, 3000.0, 5800.0, 9500.0, 12200.0, 20800.0], humidity: vec![ 0.020, 0.018, 0.015, 0.008, 0.002, 0.0001, 0.00001, 0.0000001, ], wind_u: vec![-30.0, -40.0, -50.0, -55.0, -45.0, -20.0, -5.0, 5.0], wind_v: vec![30.0, 40.0, 50.0, 55.0, 45.0, 20.0, 5.0, -5.0], pressure_levels: vec![1000.0, 925.0, 850.0, 700.0, 500.0, 300.0, 200.0, 50.0], surface_pressure: 94000.0, // Very low for hurricane temperature_2m: 300.0, wind_u_10m: -35.0, wind_v_10m: 35.0, precipitation: 50.0, timestamp: 0.0, } } /// Create initial state for high pressure system (anticyclone). #[must_use] pub fn anticyclone() -> AtmosphericState { AtmosphericState { temperature: vec![295.0, 292.0, 287.0, 275.0, 255.0, 228.0, 218.0, 205.0], geopotential: vec![0.0, 820.0, 1550.0, 3150.0, 5750.0, 9400.0, 12100.0, 20600.0], humidity: vec![ 0.008, 0.006, 0.004, 0.002, 0.0005, 0.0001, 0.00002, 0.000001, ], wind_u: vec![2.0, 3.0, 5.0, 8.0, 12.0, 15.0, 10.0, 5.0], wind_v: vec![-2.0, -3.0, -5.0, -8.0, -10.0, -8.0, -5.0, -2.0], pressure_levels: vec![1000.0, 925.0, 850.0, 700.0, 500.0, 300.0, 200.0, 50.0], surface_pressure: 103000.0, // High pressure temperature_2m: 298.0, wind_u_10m: 2.0, wind_v_10m: -1.0, precipitation: 0.0, timestamp: 0.0, } } /// Create initial state for winter storm. #[must_use] pub fn winter_storm() -> AtmosphericState { AtmosphericState { temperature: vec![268.0, 265.0, 260.0, 250.0, 235.0, 215.0, 208.0, 195.0], geopotential: vec![0.0, 700.0, 1350.0, 2800.0, 5200.0, 8800.0, 11500.0, 20000.0], humidity: vec![ 0.003, 0.003, 0.002, 0.001, 0.0005, 0.0001, 0.00002, 0.000001, ], wind_u: vec![-15.0, -20.0, -30.0, -45.0, -55.0, -60.0, -55.0, -30.0], wind_v: vec![5.0, 8.0, 12.0, 15.0, 12.0, 5.0, 0.0, -5.0], pressure_levels: vec![1000.0, 925.0, 850.0, 700.0, 500.0, 300.0, 200.0, 50.0], surface_pressure: 98500.0, temperature_2m: 268.0, wind_u_10m: -12.0, wind_v_10m: 5.0, precipitation: 15.0, // Snow equivalent timestamp: 0.0, } } // ============================================================================ // Sample Locations // ============================================================================ /// Create sample verification locations. #[must_use] pub fn verification_locations() -> Vec { vec![ GridPoint { lat: 40.7128, lon: -74.0060, elevation: 10.0, land_mask: 1.0, }, // New York GridPoint { lat: 34.0522, lon: -118.2437, elevation: 71.0, land_mask: 1.0, }, // Los Angeles GridPoint { lat: 51.5074, lon: -0.1278, elevation: 11.0, land_mask: 1.0, }, // London GridPoint { lat: 35.6762, lon: 139.6503, elevation: 40.0, land_mask: 1.0, }, // Tokyo GridPoint { lat: -33.8688, lon: 151.2093, elevation: 58.0, land_mask: 1.0, }, // Sydney GridPoint { lat: 55.7558, lon: 37.6173, elevation: 156.0, land_mask: 1.0, }, // Moscow GridPoint { lat: -22.9068, lon: -43.1729, elevation: 11.0, land_mask: 1.0, }, // Rio de Janeiro GridPoint { lat: 1.3521, lon: 103.8198, elevation: 15.0, land_mask: 1.0, }, // Singapore ] } /// Create sample ocean locations for marine forecasting. #[must_use] pub fn marine_locations() -> Vec { vec![ GridPoint { lat: 30.0, lon: -60.0, elevation: 0.0, land_mask: 0.0, }, // North Atlantic GridPoint { lat: 0.0, lon: -160.0, elevation: 0.0, land_mask: 0.0, }, // Central Pacific GridPoint { lat: -45.0, lon: 20.0, elevation: 0.0, land_mask: 0.0, }, // Southern Ocean GridPoint { lat: 20.0, lon: 120.0, elevation: 0.0, land_mask: 0.0, }, // South China Sea ] } // ============================================================================ // Training Configurations // ============================================================================ /// Create quick training configuration for testing. #[must_use] pub fn quick_training() -> TrainingConfig { TrainingConfig { epochs: 10, batch_size: 8, learning_rate: 1e-3, weight_decay: 1e-5, num_ar_steps: 2, gradient_accumulation: 1, curriculum: false, variable_weights: vec![ ("temperature".to_string(), 1.0), ("geopotential".to_string(), 1.0), ], noise_level: 0.01, } } /// Create full training configuration. #[must_use] pub fn full_training() -> TrainingConfig { TrainingConfig { epochs: 200, batch_size: 32, learning_rate: 1e-4, weight_decay: 1e-5, num_ar_steps: 12, gradient_accumulation: 4, curriculum: true, variable_weights: vec![ ("temperature".to_string(), 1.0), ("geopotential".to_string(), 0.5), ("humidity".to_string(), 1.0), ("wind_u".to_string(), 1.0), ("wind_v".to_string(), 1.0), ], noise_level: 0.005, } } /// Create fine-tuning configuration. #[must_use] pub fn finetune_training() -> TrainingConfig { TrainingConfig { epochs: 50, batch_size: 16, learning_rate: 1e-5, weight_decay: 1e-6, num_ar_steps: 6, gradient_accumulation: 2, curriculum: false, ..TrainingConfig::default() } } // ============================================================================ // Tests // ============================================================================ #[cfg(test)] mod tests { use super::*; #[test] fn test_global_forecast_config() { let (mesh, pred) = global_forecast(); assert_eq!(mesh.refinement_levels, 5); assert_eq!(pred.lead_time, 240.0); } #[test] fn test_regional_forecast_config() { let (mesh, pred) = regional_forecast(); assert!(mesh.regional_focus.is_some()); assert!(mesh.multi_scale); assert_eq!(pred.time_step, 1.0); } #[test] fn test_ensemble_config() { let (_, pred) = ensemble_forecast(); assert_eq!(pred.ensemble_size, 50); } #[test] fn test_large_ensemble() { let (_, pred) = large_ensemble(); assert_eq!(pred.ensemble_size, 100); } #[test] fn test_high_resolution_config() { let (mesh, pred) = high_resolution_forecast(); assert!(mesh.avg_edge_length < 10.0); assert!(pred.variables.len() > 5); } #[test] fn test_midlatitude_cyclone() { let state = midlatitude_cyclone(); assert!(state.surface_pressure < 101325.0); // Low pressure assert!(state.precipitation > 0.0); } #[test] fn test_tropical_cyclone() { let state = tropical_cyclone(); assert!(state.surface_pressure < 95000.0); // Very low assert!(state.wind_speed(0) > 30.0); // Strong winds } #[test] fn test_anticyclone() { let state = anticyclone(); assert!(state.surface_pressure > 101325.0); // High pressure assert!(state.precipitation == 0.0); } #[test] fn test_winter_storm() { let state = winter_storm(); assert!(state.temperature_2m < 273.0); // Below freezing } #[test] fn test_verification_locations() { let locations = verification_locations(); assert!(!locations.is_empty()); for loc in &locations { assert!(loc.lat >= -90.0 && loc.lat <= 90.0); assert!(loc.lon >= -180.0 && loc.lon <= 180.0); } } #[test] fn test_marine_locations() { let locations = marine_locations(); for loc in &locations { assert_eq!(loc.land_mask, 0.0); // All should be ocean } } #[test] fn test_training_configs() { let quick = quick_training(); let full = full_training(); assert!(quick.epochs < full.epochs); assert!(quick.learning_rate > full.learning_rate); } #[test] fn test_european_regional() { let (mesh, _) = european_regional(); let (lat, lon, _) = mesh.regional_focus.unwrap(); assert!((lat - 50.0).abs() < 1.0); assert!((lon - 10.0).abs() < 1.0); } #[test] fn test_asian_regional() { let (mesh, _) = asian_regional(); assert!(mesh.regional_focus.is_some()); } #[test] fn test_global_short_range() { let (_, pred) = global_short_range(); assert_eq!(pred.lead_time, 72.0); assert_eq!(pred.time_step, 3.0); } #[test] fn test_finetune_training() { let config = finetune_training(); assert!(config.learning_rate < 1e-4); } }