//! Sample data and configurations for AeroFlow demo. use aeroflow_shared::{ naca_4digit, AnalysisType, FlowConditions, GeometryType, OperatorConfig, OperatorType, OptimizationConfig, OptimizationObjective, SimulationRequest, TrainingConfig, WingGeometry, }; // ============================================================================ // Airfoil Simulations // ============================================================================ /// Create a NACA 0012 cruise simulation. #[must_use] pub fn naca0012_cruise() -> SimulationRequest { let airfoil = naca_4digit("0012", 100).unwrap_or_default(); SimulationRequest { geometry: GeometryType::Airfoil2D(airfoil), conditions: FlowConditions { velocity: 250.0, // m/s angle_of_attack: 2.0, mach: 0.73, reynolds: 9_000_000.0, ..Default::default() }, operator: OperatorConfig::default(), analysis: AnalysisType::SinglePoint, compute_flow_field: true, export_results: false, } } /// Create a NACA 2412 climb simulation. #[must_use] pub fn naca2412_climb() -> SimulationRequest { let airfoil = naca_4digit("2412", 100).unwrap_or_default(); SimulationRequest { geometry: GeometryType::Airfoil2D(airfoil), conditions: FlowConditions { velocity: 80.0, // m/s angle_of_attack: 5.0, mach: 0.23, reynolds: 4_000_000.0, ..Default::default() }, operator: OperatorConfig::default(), analysis: AnalysisType::SinglePoint, compute_flow_field: true, export_results: false, } } /// Create a NACA 4412 approach simulation. #[must_use] pub fn naca4412_approach() -> SimulationRequest { let airfoil = naca_4digit("4412", 100).unwrap_or_default(); SimulationRequest { geometry: GeometryType::Airfoil2D(airfoil), conditions: FlowConditions { velocity: 60.0, // m/s angle_of_attack: 8.0, mach: 0.17, reynolds: 3_000_000.0, ..Default::default() }, operator: OperatorConfig::default(), analysis: AnalysisType::SinglePoint, compute_flow_field: true, export_results: false, } } /// Create an alpha sweep request. #[must_use] pub fn alpha_sweep_request() -> SimulationRequest { let airfoil = naca_4digit("0012", 100).unwrap_or_default(); SimulationRequest { geometry: GeometryType::Airfoil2D(airfoil), conditions: FlowConditions::default(), operator: OperatorConfig::default(), analysis: AnalysisType::AlphaSweep { alpha_start: -5.0, alpha_end: 15.0, alpha_step: 1.0, }, compute_flow_field: false, export_results: false, } } /// Create a Mach sweep request. #[must_use] pub fn mach_sweep_request() -> SimulationRequest { let airfoil = naca_4digit("0012", 100).unwrap_or_default(); SimulationRequest { geometry: GeometryType::Airfoil2D(airfoil), conditions: FlowConditions { angle_of_attack: 2.0, ..Default::default() }, operator: OperatorConfig::default(), analysis: AnalysisType::MachSweep { mach_start: 0.2, mach_end: 0.8, mach_step: 0.1, }, compute_flow_field: false, export_results: false, } } /// Create a polar generation request. #[must_use] pub fn polar_request() -> SimulationRequest { let airfoil = naca_4digit("2412", 100).unwrap_or_default(); SimulationRequest { geometry: GeometryType::Airfoil2D(airfoil), conditions: FlowConditions::default(), operator: OperatorConfig::default(), analysis: AnalysisType::Polar { cl_targets: vec![0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2], }, compute_flow_field: false, export_results: false, } } // ============================================================================ // Wing Simulations // ============================================================================ /// Create a simple wing simulation. #[must_use] pub fn simple_wing() -> SimulationRequest { let root_airfoil = naca_4digit("2412", 50).unwrap_or_default(); let wing = WingGeometry { root_airfoil, tip_airfoil: None, span: 10.0, root_chord: 2.0, tip_chord: 1.0, sweep_angle: 0.0, dihedral_angle: 5.0, twist_angle: -3.0, }; SimulationRequest { geometry: GeometryType::Wing3D(wing), conditions: FlowConditions { velocity: 50.0, angle_of_attack: 4.0, mach: 0.15, reynolds: 3_000_000.0, ..Default::default() }, operator: OperatorConfig::default(), analysis: AnalysisType::SinglePoint, compute_flow_field: true, export_results: false, } } /// Create a swept wing simulation. #[must_use] pub fn swept_wing() -> SimulationRequest { let root_airfoil = naca_4digit("0012", 50).unwrap_or_default(); let tip_airfoil = naca_4digit("0009", 50).unwrap_or_default(); let wing = WingGeometry { root_airfoil, tip_airfoil: Some(tip_airfoil), span: 15.0, root_chord: 4.0, tip_chord: 1.5, sweep_angle: 25.0, dihedral_angle: 3.0, twist_angle: -2.0, }; SimulationRequest { geometry: GeometryType::Wing3D(wing), conditions: FlowConditions { velocity: 200.0, angle_of_attack: 3.0, mach: 0.6, reynolds: 15_000_000.0, ..Default::default() }, operator: OperatorConfig::default(), analysis: AnalysisType::SinglePoint, compute_flow_field: true, export_results: false, } } // ============================================================================ // Operator Configurations // ============================================================================ /// Create FNO configuration for high-fidelity simulations. #[must_use] pub fn high_fidelity_fno() -> OperatorConfig { OperatorConfig { operator_type: OperatorType::FNO, num_modes: 24, hidden_dim: 128, num_layers: 6, physics_informed: true, grid_resolution: (256, 128), activation: "gelu".to_string(), } } /// Create FNO configuration for fast simulations. #[must_use] pub fn fast_fno() -> OperatorConfig { OperatorConfig { operator_type: OperatorType::FNO, num_modes: 8, hidden_dim: 32, num_layers: 3, physics_informed: false, grid_resolution: (64, 32), activation: "relu".to_string(), } } /// Create DeepONet configuration. #[must_use] pub fn deeponet_config() -> OperatorConfig { OperatorConfig { operator_type: OperatorType::DeepONet, num_modes: 16, hidden_dim: 64, num_layers: 4, physics_informed: true, grid_resolution: (128, 64), activation: "tanh".to_string(), } } /// Create PINO configuration. #[must_use] pub fn pino_config() -> OperatorConfig { OperatorConfig { operator_type: OperatorType::PINO, num_modes: 16, hidden_dim: 64, num_layers: 5, physics_informed: true, grid_resolution: (128, 64), activation: "gelu".to_string(), } } // ============================================================================ // Optimization Configurations // ============================================================================ /// Create drag minimization optimization config. #[must_use] pub fn min_drag_optimization() -> OptimizationConfig { OptimizationConfig { objective: OptimizationObjective::MinDragAtCl { target_cl: 0.5 }, max_iterations: 100, tolerance: 1e-6, population_size: 50, learning_rate: 0.01, ..Default::default() } } /// Create max L/D optimization config. #[must_use] pub fn max_ld_optimization() -> OptimizationConfig { OptimizationConfig { objective: OptimizationObjective::MaxLiftToDrag, max_iterations: 200, tolerance: 1e-7, population_size: 100, learning_rate: 0.005, ..Default::default() } } // ============================================================================ // Training Configurations // ============================================================================ /// Create quick training config. #[must_use] pub fn quick_training() -> TrainingConfig { TrainingConfig { epochs: 50, batch_size: 16, learning_rate: 1e-3, physics_weight: 0.5, data_weight: 1.0, bc_weight: 5.0, num_collocation_points: 5000, curriculum: false, } } /// Create full training config. #[must_use] pub fn full_training() -> TrainingConfig { TrainingConfig { epochs: 200, batch_size: 32, learning_rate: 5e-4, physics_weight: 1.0, data_weight: 1.0, bc_weight: 10.0, num_collocation_points: 20000, curriculum: true, } } // ============================================================================ // Tests // ============================================================================ #[cfg(test)] mod tests { use super::*; #[test] fn test_naca0012_cruise() { let request = naca0012_cruise(); assert!(matches!(request.geometry, GeometryType::Airfoil2D(_))); assert!((request.conditions.mach - 0.73).abs() < 0.01); } #[test] fn test_alpha_sweep() { let request = alpha_sweep_request(); if let AnalysisType::AlphaSweep { alpha_start, alpha_end, alpha_step, } = request.analysis { assert_eq!(alpha_start, -5.0); assert_eq!(alpha_end, 15.0); assert_eq!(alpha_step, 1.0); } else { panic!("Expected AlphaSweep analysis type"); } } #[test] fn test_wing_simulations() { let simple = simple_wing(); let swept = swept_wing(); assert!(matches!(simple.geometry, GeometryType::Wing3D(_))); assert!(matches!(swept.geometry, GeometryType::Wing3D(_))); } #[test] fn test_operator_configs() { let high_fi = high_fidelity_fno(); let fast = fast_fno(); assert!(high_fi.num_modes > fast.num_modes); assert!(high_fi.hidden_dim > fast.hidden_dim); } #[test] fn test_optimization_configs() { let min_drag = min_drag_optimization(); let max_ld = max_ld_optimization(); assert!(matches!( min_drag.objective, OptimizationObjective::MinDragAtCl { .. } )); assert!(matches!( max_ld.objective, OptimizationObjective::MaxLiftToDrag )); } #[test] fn test_training_configs() { let quick = quick_training(); let full = full_training(); assert!(quick.epochs < full.epochs); assert!(quick.num_collocation_points < full.num_collocation_points); } }