-
Notifications
You must be signed in to change notification settings - Fork 1
Examples
shaia edited this page Mar 4, 2026
·
2 revisions
This page provides a walkthrough of the example programs included with the CFD library.
| 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 |
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=1andzmin=0, zmax=0for 2D simulations -
simulation_register_output()sets up automatic file generation -
simulation_write_outputs()writes files at registered intervals
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);Demonstrates the pluggable solver architecture:
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]);
}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
);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);
}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);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
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);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;
}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 32Output files are created in output/.
- Getting Started - Build instructions
- Solver Guide - Solver details
- Output System - Output configuration
- Architecture - Library internals