400 lines
11 KiB
Rust
400 lines
11 KiB
Rust
//! 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);
|
|
}
|
|
}
|