Skip to content

leo-aa88/cnavier

Repository files navigation

cnavier

Explicit incompressible Navier-Stokes solver written in C.

Solves the 2D lid-driven cavity problem using the vorticity-streamfunction formulation, which eliminates pressure from the equations and enforces incompressibility exactly.

Results

Re=1000 lid-driven cavity flow

Vorticity field for the lid-driven cavity at Re=1000.

Method

The governing equations are:

∂ω/∂t + u·∂ω/∂x + v·∂ω/∂y = (1/Re) ∇²ω          (vorticity transport)
∇²ψ = −ω                                        (Poisson equation)
u = ∂ψ/∂y,  v = −∂ψ/∂x                          (velocity recovery)
ω = ∂v/∂x − ∂u/∂y                               (vorticity definition)

At each timestep:

  1. Compute vorticity boundary conditions from current velocity field
  2. Evaluate spatial derivatives of ω using finite differences
  3. Advance ω in time (Euler or RK4)
  4. Solve the Poisson equation for ψ
  5. Recover u and v from ψ

Features

  • Spatial discretisation: finite differences of selectable order (2nd, 4th, or 6th)
  • Time integration: explicit Euler or classical RK4 (4th-order accurate)
  • Poisson solver: three options — Gauss-Seidel, SOR, or FFTW3-based direct DST-I solver (default)
  • Sparse operators: 2D derivative operators built as CSR sparse matrices via Kronecker products, replacing dense O(n³) matrix-vector multiplies with O(7n) SpMV
  • Output: VTK files for visualisation in ParaView

Dependencies

  • gcc
  • libfftw3 — required for the FFT Poisson solver
  • OpenMP — optional; used only if you build with make OPENMP=1 (see below)

Ubuntu/Debian

sudo apt install libfftw3-dev

For parallel builds, install a full GCC toolchain (OpenMP comes with GCC as libgomp; nothing extra beyond the compiler is usually required):

sudo apt install build-essential

Arch Linux

sudo pacman -S fftw

GCC on Arch already includes OpenMP support for make OPENMP=1.

macOS

brew install fftw

Apple’s default compiler is often Clang without OpenMP enabled for -fopenmp. To use OpenMP, install GCC from Homebrew and point CC at it (the exact version suffix may vary):

brew install gcc
CC=gcc-14 make OPENMP=1

Alternatively, install libomp and use Clang with the appropriate -fopenmp / -lomp flags if you maintain a custom toolchain.

OpenMP (quick facts)

You typically do not install a package named “openmp” alone. GCC implements OpenMP and links the runtime (libgomp on Linux). If gcc -fopenmp works on your system, make OPENMP=1 should work.

Build

make

Optional OpenMP (shared-memory parallelism in the hot loops — SpMV, Euler/RK4 RHS, Poisson):

make OPENMP=1

Thread count follows OMP_NUM_THREADS (and the OpenMP runtime defaults). The default make build is unchanged (no OpenMP).

This produces the cnavier binary. Output VTK files are written to output/ — create it first:

mkdir -p output
./cnavier

To clean build artifacts:

make clean

Configuration

All parameters are set at the top of src/main.c:

Physical

Parameter Default Description
Re 1000 Reynolds number
Lx, Ly 1 Domain size

Numerical

Parameter Default Description
nx, ny 64 Grid points in x and y
dt 0.005 Time step
tf 20 Final time
order 6 Finite difference order (2, 4, or 6)
time_scheme 2 1 = Euler, 2 = RK4
poisson_type 3 1 = Gauss-Seidel, 2 = SOR, 3 = FFT
output_interval 10 Write VTK every N iterations

Boundary conditions

The default case is the lid-driven cavity: the top wall moves at u=1, all other walls are stationary no-slip. Boundary conditions are set via u1u4 and v1v4 in main.c.

Output

VTK files are written to output/ and can be opened in ParaView. The vorticity field is exported by default; stream function, velocity components, and pressure can be enabled by uncommenting the relevant printvtk calls in main.c.

Project structure

cnavier/
├── src/
│   ├── main.c          # Simulation loop and configuration
│   ├── linearalg.c     # Dense and sparse (CSR) linear algebra
│   ├── finitediff.c    # Finite difference operators (dense + sparse)
│   ├── fluiddyn.c      # Euler/RK4 time integration, vorticity, continuity
│   ├── poisson.c       # Gauss-Seidel, SOR, and FFT Poisson solvers
│   └── utils.c         # VTK output, random utilities
├── include/
│   ├── linearalg.h
│   ├── finitediff.h
│   ├── fluiddyn.h
│   ├── poisson.h
│   └── utils.h
├── output/             # VTK output files
├── Re1000_cavity_flow_example.png
├── Re1000_cavity_flow_example.mp4
├── LICENSE
├── Makefile
└── README.md

Notes on the FFT Poisson solver

The default poisson_type = 3 uses FFTW3's RODFT00 plan (DST-I) to solve the Poisson equation exactly in O(n² log n). This is orders of magnitude faster than the iterative solvers at high Reynolds numbers where many iterations are required for convergence. FFTW plans are computed once at startup via fft_setup() and reused every timestep.

With RK4 (time_scheme = 2), the Poisson equation is solved once per RK4 stage (5 solves per timestep total). Since each solve is O(n² log n), this remains fast and gives 4th-order temporal accuracy.

Releases

No releases published

Packages

 
 
 

Contributors