Skip to content

Examples

shaia edited this page Mar 4, 2026 · 2 revisions

Examples

This page provides a walkthrough of the example programs included with the CFD library.

Example Programs

Example Description Key Features
minimal_example Simplest possible simulation Basic API usage
minimal_example_3d Simplest 3D simulation 3D grid setup
basic_simulation Standard simulation workflow Output registration
solver_selection Comparing different solvers Solver registry, runtime switching
csv_data_export CSV output for data analysis All CSV output types
animated_flow_simulation Creating animations High-frequency output, vortex setup
simple_animated_flow Simplified animation example Quick animation setup
custom_boundary_conditions Flow around obstacles Manual boundary conditions
custom_source_terms Adding energy sources Source term modification
performance_comparison Benchmarking solvers Performance measurement
runtime_comparison CPU vs GPU comparison GPU acceleration
velocity_visualization Velocity field output VTK velocity vectors
lid_driven_cavity Lid-driven cavity benchmark Validation against Ghia data
lid_driven_cavity_direct Cavity using direct solver API Low-level solver interface
poiseuille_stretched_grid Poiseuille flow on stretched grid Non-uniform grid spacing
taylor_green_convergence Taylor-Green vortex convergence Temporal accuracy verification
pulsatile_inlet_flow Time-varying inlet conditions Time-dependent BCs
poisson_solver_tuning Poisson solver parameter tuning Linear solver configuration
platform_diagnostics Hardware capability detection CPU features, GPU availability

Minimal Example

The simplest way to use the library:

#include "cfd/api/simulation_api.h"
#include <stdio.h>

int main() {
    // Initialize 50x25 2D grid on [0,1] x [0,0.5] (nz=1 for 2D)
    simulation_data* sim = init_simulation(50, 25, 1,
                                           0.0, 1.0, 0.0, 0.5, 0.0, 0.0);

    // Set run prefix for output organization
    simulation_set_run_prefix(sim, "minimal");

    // Register output every 5 steps
    simulation_register_output(sim, OUTPUT_VELOCITY_MAGNITUDE, 5, "velocity_mag");

    // Run 10 steps
    for (int step = 0; step < 10; step++) {
        run_simulation_step(sim);
        simulation_write_outputs(sim, step);
    }

    free_simulation(sim);
    return 0;
}

Key points:

  • init_simulation() creates grid, flow field, and default solver
  • Use nz=1 and zmin=0, zmax=0 for 2D simulations
  • simulation_register_output() sets up automatic file generation
  • simulation_write_outputs() writes files at registered intervals

Basic Simulation

A more complete simulation with progress reporting:

simulation_data* sim = init_simulation(100, 50, 1,
                                       0.0, 1.0, 0.0, 0.5, 0.0, 0.0);
simulation_set_run_prefix(sim, "basic_sim");

// Output every 100 steps
simulation_register_output(sim, OUTPUT_VELOCITY_MAGNITUDE, 100, NULL);

for (int iter = 0; iter < sim->params.max_iter; iter++) {
    run_simulation_step(sim);
    simulation_write_outputs(sim, iter);

    if (iter % 100 == 0) {
        printf("Iteration %d: Output written\n", iter);
    }
}

free_simulation(sim);

Solver Selection

Demonstrates the pluggable solver architecture:

Listing Available Solvers

const char* solver_names[16];
int num_solvers = simulation_list_solvers(solver_names, 16);

printf("Available solvers (%d):\n", num_solvers);
for (int i = 0; i < num_solvers; i++) {
    printf("  %d. %s\n", i + 1, solver_names[i]);
}

Creating with Specific Solver

simulation_data* sim = init_simulation_with_solver(
    100, 50, 1, 0.0, 2.0, 0.0, 1.0, 0.0, 0.0,
    NS_SOLVER_TYPE_PROJECTION_OPTIMIZED
);

Switching Solvers at Runtime

simulation_data* sim = init_simulation(100, 50, 1,
                                       0.0, 2.0, 0.0, 1.0, 0.0, 0.0);

// Run with default solver
for (int step = 0; step < 10; step++) {
    run_simulation_step(sim);
}

// Switch to optimized solver
simulation_set_solver_by_name(sim, NS_SOLVER_TYPE_EXPLICIT_EULER_OPTIMIZED);

// Continue with new solver
for (int step = 10; step < 20; step++) {
    run_simulation_step(sim);
}

Accessing Solver Statistics

run_simulation_step(sim);

const ns_solver_stats_t* stats = simulation_get_stats(sim);
printf("Max velocity: %.4f\n", stats->max_velocity);
printf("Max pressure: %.4f\n", stats->max_pressure);
printf("Elapsed time: %.2f ms\n", stats->elapsed_time_ms);

CSV Data Export

Shows all CSV output types:

simulation_data* sim = init_simulation(100, 50, 1,
                                       0.0, 2.0, 0.0, 1.0, 0.0, 0.0);
simulation_set_run_prefix(sim, "csv_export");

// Time series - global quantities every step
simulation_register_output(sim, OUTPUT_CSV_TIMESERIES, 1, "timeseries");

// Statistics - detailed min/max/avg every 5 steps
simulation_register_output(sim, OUTPUT_CSV_STATISTICS, 5, "statistics");

// Centerline - velocity profiles every 10 steps
simulation_register_output(sim, OUTPUT_CSV_CENTERLINE, 10, "centerline");

// Also VTK for visualization
simulation_register_output(sim, OUTPUT_FULL_FIELD, 20, "flow_field");

for (int step = 0; step < 100; step++) {
    run_simulation_step(sim);
    simulation_write_outputs(sim, step);
}

free_simulation(sim);

Generated files:

  • timeseries.csv: 100 rows with step, time, max_u, max_v, etc.
  • statistics.csv: 20 rows with min/max/avg for all fields
  • centerline_NNN.csv: 10 files with x, u, v, p, rho, T columns

Animated Flow Simulation

Creates smooth animations with vortex initial conditions:

simulation_data* sim = init_simulation(80, 40, 1,
                                       0.0, 4.0, 0.0, 2.0, 0.0, 0.0);
simulation_set_run_prefix(sim, "animated_flow");

// Output every 5 steps for smooth animation
simulation_register_output(sim, OUTPUT_FULL_FIELD, 5, "flow_field");
simulation_register_output(sim, OUTPUT_VELOCITY, 5, "velocity_vectors");

// Setup vortex initial conditions
flow_field* field = sim->field;
grid* g = sim->grid;

for (size_t j = 0; j < field->ny; j++) {
    for (size_t i = 0; i < field->nx; i++) {
        size_t idx = j * field->nx + i;
        double x = g->x[i];
        double y = g->y[j];

        // Create vortex at (1.0, 1.0)
        double r = sqrt((x - 1.0)*(x - 1.0) + (y - 1.0)*(y - 1.0));
        if (r < 0.6) {
            double theta = atan2(y - 1.0, x - 1.0);
            double strength = 2.0 * exp(-r*r / 0.2);
            field->u[idx] += -strength * sin(theta);
            field->v[idx] += strength * cos(theta);
        }
    }
}

// Run simulation
for (int step = 0; step < 200; step++) {
    run_simulation_step(sim);
    simulation_write_outputs(sim, step);
}

free_simulation(sim);

Performance Comparison

Benchmarking different solvers:

void benchmark_solver(const char* name, const char* type,
                      size_t nx, size_t ny, int iterations) {
    simulation_data* sim = init_simulation_with_solver(
        nx, ny, 1, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0, type);

    clock_t start = clock();

    for (int i = 0; i < iterations; i++) {
        run_simulation_step(sim);
    }

    clock_t end = clock();
    double elapsed = (double)(end - start) / CLOCKS_PER_SEC;

    printf("%s: %.3f seconds (%.1f steps/sec)\n",
           name, elapsed, iterations / elapsed);

    free_simulation(sim);
}

int main() {
    size_t nx = 200, ny = 100;
    int iterations = 500;

    benchmark_solver("Basic", NS_SOLVER_TYPE_EXPLICIT_EULER, nx, ny, iterations);
    benchmark_solver("Optimized", NS_SOLVER_TYPE_EXPLICIT_EULER_OPTIMIZED, nx, ny, iterations);
    benchmark_solver("OpenMP", NS_SOLVER_TYPE_EXPLICIT_EULER_OMP, nx, ny, iterations);
    benchmark_solver("Projection", NS_SOLVER_TYPE_PROJECTION, nx, ny, iterations);
    benchmark_solver("RK2", NS_SOLVER_TYPE_RK2, nx, ny, iterations);

    return 0;
}

Building and Running Examples

After building the library:

# Windows
cd build/Release
./minimal_example.exe
./basic_simulation.exe
./solver_selection.exe
./lid_driven_cavity.exe 32        # Requires grid size argument
./lid_driven_cavity_direct.exe 32

# Linux/macOS
cd build
./minimal_example
./basic_simulation
./lid_driven_cavity 32

Output files are created in output/.

See Also

Clone this wiki locally