-
Notifications
You must be signed in to change notification settings - Fork 1
Solver Guide
shaia edited this page Mar 4, 2026
·
2 revisions
This guide covers the available solvers, their characteristics, and how to choose the right one for your simulation.
| Solver Type | Description | Best For |
|---|---|---|
explicit_euler |
Basic explicit Euler method | Learning, debugging, small grids |
explicit_euler_optimized |
SIMD-optimized explicit Euler | Large grids on modern CPUs |
explicit_euler_omp |
OpenMP-parallelized explicit Euler | Multi-core systems |
projection |
Projection method for incompressible flow | Accurate pressure-velocity coupling |
projection_optimized |
SIMD-optimized projection method | Production simulations |
projection_omp |
OpenMP-parallelized projection | Multi-core production use |
rk2 |
RK2 (Heun's method) time integration | Second-order temporal accuracy |
rk2_optimized |
SIMD-optimized RK2 | High-accuracy large grids |
rk2_omp |
OpenMP-parallelized RK2 | High-accuracy multi-core |
explicit_euler_gpu |
GPU-accelerated explicit Euler | Very large grids with NVIDIA GPU |
projection_jacobi_gpu |
GPU-accelerated projection | High-performance simulations |
#include "cfd/api/simulation_api.h"
// Option 1: Default solver (explicit_euler)
simulation_data* sim = init_simulation(100, 100, 1,
0.0, 1.0, 0.0, 1.0, 0.0, 0.0);
// Option 2: Specify solver at creation
simulation_data* sim = init_simulation_with_solver(
100, 100, 1, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0,
NS_SOLVER_TYPE_PROJECTION_OPTIMIZED
);
// Option 3: Change solver at runtime
simulation_set_solver_by_name(sim, NS_SOLVER_TYPE_EXPLICIT_EULER_OPTIMIZED);const char* solver_names[16];
int count = simulation_list_solvers(solver_names, 16);
printf("Available solvers:\n");
for (int i = 0; i < count; i++) {
printf(" - %s\n", solver_names[i]);
}if (simulation_has_solver(NS_SOLVER_TYPE_EXPLICIT_EULER_GPU)) {
printf("GPU solver is available\n");
}Each solver reports its capabilities through bitflags:
| Capability | Description |
|---|---|
NS_SOLVER_CAP_INCOMPRESSIBLE |
Supports incompressible flow |
NS_SOLVER_CAP_COMPRESSIBLE |
Supports compressible flow |
NS_SOLVER_CAP_TRANSIENT |
Supports transient (time-dependent) problems |
NS_SOLVER_CAP_STEADY_STATE |
Supports steady-state solutions |
NS_SOLVER_CAP_SIMD |
Uses SIMD (AVX2) optimizations |
NS_SOLVER_CAP_PARALLEL |
Supports parallel execution (OpenMP) |
NS_SOLVER_CAP_GPU |
Uses GPU acceleration (CUDA) |
ns_solver_t* solver = simulation_get_solver(sim);
if (solver->capabilities & NS_SOLVER_CAP_SIMD) {
printf("Using SIMD optimizations\n");
}
if (solver->capabilities & NS_SOLVER_CAP_GPU) {
printf("Using GPU acceleration\n");
}After each step, you can retrieve performance statistics:
run_simulation_step(sim);
const ns_solver_stats_t* stats = simulation_get_stats(sim);
printf("Iterations: %d\n", stats->iterations);
printf("Residual: %.2e\n", stats->residual);
printf("Max velocity: %.4f\n", stats->max_velocity);
printf("Max pressure: %.4f\n", stats->max_pressure);
printf("CFL number: %.4f\n", stats->cfl_number);
printf("Elapsed time: %.2f ms\n", stats->elapsed_time_ms);Use explicit_euler - it's the simplest and easiest to understand.
-
Small grids (< 200x200):
projectionorexplicit_euler -
Medium grids (200x200 - 1000x1000):
projection_optimizedorrk2_optimized -
Large grids with multi-core CPU:
projection_omporrk2_omp
- Requires NVIDIA GPU and CUDA Toolkit
- Use
projection_jacobi_gpuorexplicit_euler_gpu - Best for grids larger than 500x500
| Aspect | Explicit Euler | Projection | RK2 (Heun) |
|---|---|---|---|
| Simplicity | Simplest | More complex | Moderate |
| Temporal order | 1st | 1st | 2nd |
| Stability | CFL limited | Better | CFL limited |
| Pressure | Approximate | Divergence-free | Approximate |
| Speed per step | Fastest | Slowest | Moderate |
Default solver parameters can be customized:
simulation_data* sim = init_simulation(100, 100, 1,
0.0, 1.0, 0.0, 1.0, 0.0, 0.0);
// Modify parameters
sim->params.dt = 0.001; // Time step
sim->params.cfl = 0.2; // CFL number
sim->params.mu = 0.01; // Viscosity
sim->params.max_iter = 200; // Max iterations per step
sim->params.tolerance = 1e-6; // Convergence tolerance| Parameter | Default | Description |
|---|---|---|
dt |
0.001 | Time step size |
cfl |
0.2 | CFL number for stability |
gamma |
1.4 | Specific heat ratio |
mu |
0.01 | Dynamic viscosity |
k |
0.0242 | Thermal conductivity |
max_iter |
100 | Maximum iterations |
tolerance |
1e-6 | Convergence tolerance |
- Match solver to hardware: Use SIMD solvers on modern CPUs, GPU solvers on NVIDIA hardware
- Use appropriate grid size: Larger grids benefit more from parallelization
- Monitor CFL number: Keep it below 1.0 for stability
- Profile your simulation: Use solver statistics to identify bottlenecks
- Consider RK2 for accuracy: When temporal accuracy matters, RK2 gives O(dt^2) convergence
- Getting Started - Basic usage
- Output System - Saving simulation results
- Examples - Working code examples