Skip to content

Solver Guide

shaia edited this page Mar 4, 2026 · 2 revisions

Solver Guide

This guide covers the available solvers, their characteristics, and how to choose the right one for your simulation.

Available Solvers

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

Solver Selection

Using the Simulation API

#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);

Listing Available Solvers

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]);
}

Checking Solver Availability

if (simulation_has_solver(NS_SOLVER_TYPE_EXPLICIT_EULER_GPU)) {
    printf("GPU solver is available\n");
}

Solver Capabilities

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)

Querying Capabilities

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");
}

Solver Statistics

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);

Choosing a Solver

For Learning and Debugging

Use explicit_euler - it's the simplest and easiest to understand.

For Production (CPU)

  • Small grids (< 200x200): projection or explicit_euler
  • Medium grids (200x200 - 1000x1000): projection_optimized or rk2_optimized
  • Large grids with multi-core CPU: projection_omp or rk2_omp

For High Performance (GPU)

  • Requires NVIDIA GPU and CUDA Toolkit
  • Use projection_jacobi_gpu or explicit_euler_gpu
  • Best for grids larger than 500x500

Solver Comparison

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

Solver Parameters

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

Default Values

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

Performance Tips

  1. Match solver to hardware: Use SIMD solvers on modern CPUs, GPU solvers on NVIDIA hardware
  2. Use appropriate grid size: Larger grids benefit more from parallelization
  3. Monitor CFL number: Keep it below 1.0 for stability
  4. Profile your simulation: Use solver statistics to identify bottlenecks
  5. Consider RK2 for accuracy: When temporal accuracy matters, RK2 gives O(dt^2) convergence

See Also