Files
rustytorch/crates/specialized/rtx-cfd/benches/solver_performance.rs
T
2026-03-04 00:08:42 +00:00

524 lines
17 KiB
Rust

//! Performance benchmarks for RTX CFD solvers
//!
//! Benchmarks key computational kernels and full solver performance
//! across different problem sizes and configurations.
use criterion::{BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
use nalgebra::DVector;
use rtx_cfd::{
discretization::{
DifferencingScheme, FiniteDifferenceMethod, FiniteVolumeMethod, FluxScheme, GridSpacing,
SpatialOrder,
},
solvers::incompressible::{FlowField, SimpleAlgorithm},
turbulence::{KEpsilonModel, KEpsilonVariant, SmagorinskyModel, TurbulenceState},
};
/// Benchmark finite volume method discretization
fn bench_fvm_discretization(c: &mut Criterion) {
let mut group = c.benchmark_group("FVM Discretization");
for size in [100, 500, 1000, 2000].iter() {
group.benchmark_with_input(BenchmarkId::new("scalar", size), size, |b, &size| {
let mut fvm = FiniteVolumeMethod::new(SpatialOrder::Second, FluxScheme::Central)
.with_diffusion_coefficient(1e-3);
// Create 1D mesh
for i in 0..size {
fvm.add_cell(1.0, [i as f64, 0.0, 0.0]);
}
for i in 0..size - 1 {
fvm.add_face([1.0, 0.0, 0.0], 1.0, i, Some(i + 1)).unwrap();
}
let phi = DVector::zeros(size);
let velocity = DVector::zeros(size - 1);
b.iter(|| {
let matrix = fvm.discretize_scalar(black_box(&phi), black_box(&velocity));
black_box(matrix)
});
});
group.benchmark_with_input(BenchmarkId::new("momentum", size), size, |b, &size| {
let mut fvm = FiniteVolumeMethod::new(SpatialOrder::Second, FluxScheme::Upwind)
.with_diffusion_coefficient(1e-3);
for i in 0..size {
fvm.add_cell(1.0, [i as f64, 0.0, 0.0]);
}
for i in 0..size - 1 {
fvm.add_face([1.0, 0.0, 0.0], 1.0, i, Some(i + 1)).unwrap();
}
let velocity = DVector::ones(size);
let pressure = DVector::zeros(size);
b.iter(|| {
let matrix = fvm.discretize_momentum(black_box(&velocity), black_box(&pressure));
black_box(matrix)
});
});
group.benchmark_with_input(
BenchmarkId::new("flux_calculation", size),
size,
|b, &size| {
let mut fvm = FiniteVolumeMethod::new(SpatialOrder::Second, FluxScheme::Central);
for i in 0..size {
fvm.add_cell(1.0, [i as f64, 0.0, 0.0]);
}
for i in 0..size - 1 {
fvm.add_face([1.0, 0.0, 0.0], 1.0, i, Some(i + 1)).unwrap();
}
let phi = DVector::from_fn(size, |i, _| (i as f64).sin());
let velocity = DVector::ones(size - 1);
b.iter(|| {
let fluxes = fvm.calculate_fluxes(black_box(&phi), black_box(&velocity));
black_box(fluxes)
});
},
);
}
group.finish();
}
/// Benchmark finite difference method
fn bench_fdm_discretization(c: &mut Criterion) {
let mut group = c.benchmark_group("FDM Discretization");
for grid_size in [32, 64, 128, 256].iter() {
let total_size = grid_size * grid_size;
group.benchmark_with_input(
BenchmarkId::new("laplacian_2d", grid_size),
&total_size,
|b, &size| {
let spacing = GridSpacing::uniform(1.0 / *grid_size as f64);
let fdm = FiniteDifferenceMethod::new(
SpatialOrder::Second,
DifferencingScheme::Central,
spacing,
[*grid_size, *grid_size, 1],
)
.unwrap();
b.iter(|| {
let matrix = fdm.build_laplacian_2d();
black_box(matrix)
});
},
);
group.benchmark_with_input(
BenchmarkId::new("derivative_1d", grid_size),
grid_size,
|b, &size| {
let spacing = GridSpacing::uniform(1.0 / size as f64);
let fdm = FiniteDifferenceMethod::new(
SpatialOrder::Second,
DifferencingScheme::Central,
spacing,
[size, 1, 1],
)
.unwrap();
b.iter(|| {
let matrix = fdm.build_derivative_matrix_1d(size, 1.0 / size as f64, 1);
black_box(matrix)
});
},
);
group.benchmark_with_input(
BenchmarkId::new("scalar_discretization", grid_size),
&total_size,
|b, &size| {
let spacing = GridSpacing::uniform(1.0 / *grid_size as f64);
let fdm = FiniteDifferenceMethod::new(
SpatialOrder::Second,
DifferencingScheme::Central,
spacing,
[*grid_size, *grid_size, 1],
)
.unwrap();
let phi = DVector::zeros(size);
let velocity = DVector::zeros(size);
b.iter(|| {
let matrix = fdm.discretize_scalar(black_box(&phi), black_box(&velocity));
black_box(matrix)
});
},
);
}
group.finish();
}
/// Benchmark turbulence models
fn bench_turbulence_models(c: &mut Criterion) {
let mut group = c.benchmark_group("Turbulence Models");
for size in [500, 1000, 2000, 5000].iter() {
group.benchmark_with_input(
BenchmarkId::new("k_epsilon_standard", size),
size,
|b, &size| {
let mut model = KEpsilonModel::new(KEpsilonVariant::Standard, size);
let mut state = TurbulenceState::new(size);
state.initialize_k_epsilon(1e-6, 1e-8);
model.initialize_from_state(&state).unwrap();
// Add some velocity gradients for realistic computation
for i in 0..size.min(state.velocity_gradients.len()) {
state.velocity_gradients[i][0][1] = 1.0; // du/dy
}
b.iter(|| {
model.update(black_box(&state), black_box(1e-3)).unwrap();
});
},
);
group.benchmark_with_input(
BenchmarkId::new("k_epsilon_realizable", size),
size,
|b, &size| {
let mut model = KEpsilonModel::new(KEpsilonVariant::Realizable, size);
let mut state = TurbulenceState::new(size);
state.initialize_k_epsilon(1e-6, 1e-8);
model.initialize_from_state(&state).unwrap();
for i in 0..size.min(state.velocity_gradients.len()) {
state.velocity_gradients[i][0][1] = 1.0;
}
b.iter(|| {
model.update(black_box(&state), black_box(1e-3)).unwrap();
});
},
);
group.benchmark_with_input(BenchmarkId::new("smagorinsky", size), size, |b, &size| {
let mut model = SmagorinskyModel::new(size);
let filter_width = DVector::from_element(size, 0.1);
model.set_filter_width(filter_width).unwrap();
let mut state = TurbulenceState::new(size);
for i in 0..size.min(state.velocity_gradients.len()) {
state.velocity_gradients[i][0][1] = 1.0;
}
b.iter(|| {
model.update(black_box(&state), black_box(1e-3)).unwrap();
});
});
group.benchmark_with_input(
BenchmarkId::new("production_terms", size),
size,
|b, &size| {
let model = KEpsilonModel::new(KEpsilonVariant::Standard, size);
let mut state = TurbulenceState::new(size);
state.initialize_k_epsilon(1e-6, 1e-8);
for i in 0..size.min(state.velocity_gradients.len()) {
state.velocity_gradients[i][0][1] = 1.0;
}
b.iter(|| {
let production = model.production_terms(black_box(&state));
black_box(production)
});
},
);
}
group.finish();
}
/// Benchmark flow field operations
fn bench_flow_field_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("Flow Field Operations");
for size in [1000, 5000, 10000, 20000].iter() {
group.benchmark_with_input(
BenchmarkId::new("velocity_operations", size),
size,
|b, &size| {
let mut flow_field = FlowField::new(size);
// Initialize with some values
for i in 0..size {
flow_field
.set_velocity(i, [i as f64, (i * 2) as f64, 0.0])
.unwrap();
}
b.iter(|| {
for i in 0..size {
let vel = flow_field.get_velocity(black_box(i)).unwrap();
black_box(vel);
}
});
},
);
group.benchmark_with_input(
BenchmarkId::new("pressure_operations", size),
size,
|b, &size| {
let mut flow_field = FlowField::new(size);
for i in 0..size {
flow_field.set_pressure(i, i as f64 * 0.1).unwrap();
}
b.iter(|| {
for i in 0..size {
let pressure = flow_field.get_pressure(black_box(i)).unwrap();
black_box(pressure);
}
});
},
);
group.benchmark_with_input(BenchmarkId::new("statistics", size), size, |b, &size| {
let mut flow_field = FlowField::new(size);
// Initialize with realistic velocity field
for i in 0..size {
let u = (i as f64 / size as f64).sin();
let v = (i as f64 / size as f64 * 2.0).cos();
flow_field.set_velocity(i, [u, v, 0.0]).unwrap();
}
b.iter(|| {
let max_vel = flow_field.calculate_max_velocity_magnitude();
let ke = flow_field.calculate_kinetic_energy();
black_box((max_vel, ke));
});
});
}
group.finish();
}
/// Benchmark SIMPLE algorithm
fn bench_simple_algorithm(c: &mut Criterion) {
let mut group = c.benchmark_group("SIMPLE Algorithm");
for grid_size in [32, 64, 128].iter() {
let n_cells = grid_size * grid_size;
group.benchmark_with_input(
BenchmarkId::new("solve_step", grid_size),
&n_cells,
|b, &size| {
let mut flow_field = FlowField::new(size);
// Initialize with some non-trivial field
for i in 0..size {
let u = 1.0 + 0.1 * (i as f64).sin();
let v = 0.1 * (i as f64 * 2.0).cos();
flow_field.set_velocity(i, [u, v, 0.0]).unwrap();
flow_field.set_pressure(i, 0.0).unwrap();
}
let discretization =
FiniteVolumeMethod::new(SpatialOrder::Second, FluxScheme::Upwind)
.with_diffusion_coefficient(1e-3);
let mut solver = SimpleAlgorithm::new()
.with_max_iterations(10) // Limit iterations for benchmarking
.with_tolerance(1e-6)
.with_under_relaxation(0.7, 0.3);
b.iter(|| {
let residual =
solver.solve_step(black_box(&mut flow_field), black_box(&discretization));
black_box(residual)
});
},
);
}
group.finish();
}
/// Benchmark different flux schemes
fn bench_flux_schemes(c: &mut Criterion) {
let mut group = c.benchmark_group("Flux Schemes");
let size = 1000;
let schemes = [
("central", FluxScheme::Central),
("upwind", FluxScheme::Upwind),
("quick", FluxScheme::Quick),
("power_law", FluxScheme::PowerLaw),
];
for (name, scheme) in schemes.iter() {
group.benchmark_with_input(
BenchmarkId::new("flux_calculation", name),
scheme,
|b, &scheme| {
let mut fvm = FiniteVolumeMethod::new(SpatialOrder::Second, scheme)
.with_diffusion_coefficient(1e-3);
for i in 0..size {
fvm.add_cell(1.0, [i as f64, 0.0, 0.0]);
}
for i in 0..size - 1 {
fvm.add_face([1.0, 0.0, 0.0], 1.0, i, Some(i + 1)).unwrap();
}
let phi = DVector::from_fn(size, |i, _| (i as f64 * 0.1).sin());
let velocity =
DVector::from_fn(size - 1, |i, _| 1.0 + 0.5 * (i as f64 * 0.2).cos());
b.iter(|| {
let fluxes = fvm.calculate_fluxes(black_box(&phi), black_box(&velocity));
black_box(fluxes)
});
},
);
}
group.finish();
}
/// Benchmark memory allocation patterns
fn bench_memory_allocation(c: &mut Criterion) {
let mut group = c.benchmark_group("Memory Allocation");
for size in [1000, 5000, 10000].iter() {
group.benchmark_with_input(
BenchmarkId::new("flow_field_creation", size),
size,
|b, &size| {
b.iter(|| {
let flow_field = FlowField::new(black_box(size));
black_box(flow_field);
});
},
);
group.benchmark_with_input(
BenchmarkId::new("turbulence_state_creation", size),
size,
|b, &size| {
b.iter(|| {
let mut state = TurbulenceState::new(black_box(size));
state.initialize_k_epsilon(1e-6, 1e-8);
black_box(state);
});
},
);
group.benchmark_with_input(
BenchmarkId::new("k_epsilon_creation", size),
size,
|b, &size| {
b.iter(|| {
let model = KEpsilonModel::new(KEpsilonVariant::Standard, black_box(size));
black_box(model);
});
},
);
}
group.finish();
}
/// Benchmark scaling with problem size
fn bench_scaling(c: &mut Criterion) {
let mut group = c.benchmark_group("Scaling");
// Test how performance scales with problem size
let sizes = [100, 200, 500, 1000, 2000, 5000];
for size in sizes.iter() {
group.benchmark_with_input(
BenchmarkId::new("total_fvm_workflow", size),
size,
|b, &size| {
b.iter(|| {
// Complete FVM workflow
let mut fvm =
FiniteVolumeMethod::new(SpatialOrder::Second, FluxScheme::Central);
for i in 0..size {
fvm.add_cell(1.0, [i as f64, 0.0, 0.0]);
}
for i in 0..size - 1 {
fvm.add_face([1.0, 0.0, 0.0], 1.0, i, Some(i + 1)).unwrap();
}
let phi = DVector::from_fn(size, |i, _| (i as f64 * 0.1).sin());
let velocity = DVector::ones(size - 1);
let matrix = fvm.discretize_scalar(&phi, &velocity).unwrap();
let fluxes = fvm.calculate_fluxes(&phi, &velocity).unwrap();
black_box((matrix, fluxes));
});
},
);
group.benchmark_with_input(
BenchmarkId::new("total_turbulence_workflow", size),
size,
|b, &size| {
b.iter(|| {
// Complete turbulence modeling workflow
let mut model = KEpsilonModel::new(KEpsilonVariant::Standard, size);
let mut state = TurbulenceState::new(size);
state.initialize_k_epsilon(1e-6, 1e-8);
model.initialize_from_state(&state).unwrap();
for i in 0..size.min(state.velocity_gradients.len()) {
state.velocity_gradients[i][0][1] = 1.0;
}
let production = model.production_terms(&state).unwrap();
model.update(&state, 1e-3).unwrap();
let nu_t = model.turbulent_viscosity(&state).unwrap();
black_box((production, nu_t));
});
},
);
}
group.finish();
}
criterion_group!(
benches,
bench_fvm_discretization,
bench_fdm_discretization,
bench_turbulence_models,
bench_flow_field_operations,
bench_simple_algorithm,
bench_flux_schemes,
bench_memory_allocation,
bench_scaling
);
criterion_main!(benches);