Sign inSign up

irfanuruchi/fluid-lab-cfd

By irfanuruchi

Updated 4 months ago

Image
0

400

irfanuruchi/fluid-lab-cfd repository overview

Fluid Lab CFD

Interactive 2D fluid simulation lab using Fortran, MPI, CUDA, FastAPI, Docker, and a web UI.

This project was built for my Parallel Programming project. The goal is to show how the same CFD-style workload behaves on different execution models:

  • CPU Fortran
  • MPI parallel Fortran
  • CUDA GPU
  • Dockerized deployment

The app runs a 2D incompressible fluid simulation and visualizes a moving aerospace-style body with a vorticity wake and streamlines. It is not meant to be a full industrial CFD solver, but it is more than a basic classroom example because it includes numerical methods, MPI decomposition, CUDA acceleration, benchmarking, and a live browser interface.


What it does

Fluid Lab CFD allows the user to:

  • run a 2D fluid simulation from the browser
  • compare CPU, MPI, and CUDA execution modes
  • visualize vorticity, wake behavior, and streamlines
  • benchmark speedup and MPI efficiency
  • detect CPU core count and warn about MPI oversubscription
  • run everything inside Docker

The interface is kept simple on purpose. The main controls are grid size, iteration count, execution mode, and MPI process count.


Math behind the simulation

The simulation is based on the 2D incompressible Navier-Stokes equations using the vorticity-streamfunction formulation.

Instead of solving directly for pressure, the solver uses:

∂ω/∂t + u ∂ω/∂x + v ∂ω/∂y = ν ∇²ω

∇²ψ = -ω

u = ∂ψ/∂y
v = -∂ψ/∂x

Where:

ω = vorticity
ψ = streamfunction
u, v = velocity components
ν = viscosity

This formulation is useful for a 2D fluid demo because the pressure term is avoided and the velocity field can be recovered from the streamfunction.


Numerical methods

The solver uses a finite difference grid.

Main numerical parts:

  • Jacobi iteration for the streamfunction Poisson equation
  • sign-aware upwind scheme for advection
  • 5-point Laplacian stencil for diffusion
  • explicit time stepping
  • grid-scaled timestep for stability
  • moving body / wake forcing for the aerospace-style visualization

The Poisson equation is solved approximately using Jacobi iterations:

ψ(i,j) = 1/4 * (ψ(i+1,j) + ψ(i-1,j) + ψ(i,j+1) + ψ(i,j-1) + h²ω(i,j))

Velocity is calculated from the streamfunction:

u = (ψ(i,j+1) - ψ(i,j-1)) / 2h
v = -(ψ(i+1,j) - ψ(i-1,j)) / 2h

The vorticity update combines advection, diffusion, and a moving body wake term.

The aerospace body is handled with an immersed-boundary-inspired mask. This is a simplified way to represent a moving object inside the flow without making a full body-fitted mesh.


Parallel programming part

CPU Fortran

The CPU version is the baseline solver.

It is written in Fortran and compiled with optimization flags. This gives a clean baseline for comparing MPI and CUDA.


MPI Fortran

The MPI version uses row-wise domain decomposition.

Each MPI process owns part of the grid. Neighboring ranks exchange halo rows so the finite difference stencil can use boundary data from adjacent partitions.

The important MPI idea is:

each rank computes its own rows
halo rows are exchanged between neighbouring ranks
rank 0 gathers the final result

The Poisson solver needs repeated halo exchange, so MPI speedup is not perfectly linear. This is expected and important for the project.

In practice:

more MPI processes does not always mean perfect speedup

At higher process counts, communication overhead becomes more visible.

The web interface also detects the available CPU core count and warns the user if the selected MPI process count oversubscribes the machine.

Oversubscription is allowed, but it may reduce performance because multiple MPI ranks share the same CPU cores.


CUDA GPU

The CUDA version runs the stencil-style CFD workload on the GPU.

This is useful because many grid cells can be updated in parallel. For larger grids, CUDA can give much higher speedup compared with the CPU baseline.

CUDA mode requires:

  • NVIDIA GPU
  • NVIDIA driver
  • NVIDIA Container Toolkit

The CUDA preview uses real CUDA runtime, but the visual preview is cleaned so the browser shows a readable wake visualization. Benchmark mode still reports real solver timing.


Docker images

There are two Docker images.

CPU / MPI image

This image supports CPU Fortran and MPI.

It is multi-architecture:

linux/amd64
linux/arm64

Run:

docker run --rm --shm-size=2g -p 8000:8000 irfanuruchi/fluid-lab-cfd:cpu

This image is useful for normal machines, including x64 and ARM64 systems.


CUDA image

This image supports CPU, MPI, and CUDA.

It is for NVIDIA GPU machines:

linux/amd64

Run:

docker run --rm --gpus all --shm-size=2g -p 8000:8000 irfanuruchi/fluid-lab-cfd:cuda

The latest tag points to the CUDA image:

docker run --rm --gpus all --shm-size=2g -p 8000:8000 irfanuruchi/fluid-lab-cfd:latest

Open the app

After starting the container, open:

http://localhost:8000

Build locally

CUDA build
docker build -t fluid-lab .
docker run --rm --gpus all --shm-size=2g -p 8000:8000 fluid-lab
CPU/MPI build
docker build -f Dockerfile.cpu -t fluid-lab-cpu .
docker run --rm --shm-size=2g -p 8000:8000 fluid-lab-cpu

For preview:

Grid: 480 - 1000
Iterations: 1200
MPI processes: 4 - 12

For benchmark:

Grid: 720 - 1800
Iterations: 3000+
MPI processes: depends on CPU cores

For large MPI runs inside Docker, this is recommended:

--shm-size=2g

Without larger shared memory, large MPI workloads can fail inside Docker.


Example benchmark result

Example result from testing:

CPU baseline: 10.35 sec

CUDA GPU runtime: 0.2045 sec
CUDA speedup: 50.62x

MPI 24 processes runtime: 0.8776 sec
MPI speedup: 11.79x
MPI efficiency: 49%

This result shows the main idea of the project:

  • CPU is the baseline
  • MPI improves runtime, but efficiency drops as process count increases
  • CUDA gives the highest speedup for this type of parallel grid workload

MPI efficiency decreases because the solver needs communication during halo exchange, especially during the Poisson iterations.


Project structure

fluid-project/
├── backend/
│   └── main.py
├── solvers/
│   ├── fortran_cpu/
│   │   └── fluid_cpu.f90
│   ├── fortran_mpi/
│   │   └── fluid_mpi.f90
│   └── cuda_gpu/
│       └── fluid_cuda.cu
├── web/
│   ├── index.html
│   ├── app.js
│   └── style.css
├── Dockerfile
├── Dockerfile.cpu
├── requirements.txt
└── README.md

Notes

This is a student HPC/CFD project, not a production CFD solver.

The goal is to demonstrate the connection between numerical methods and parallel execution:

  • CPU baseline performance
  • MPI speedup and efficiency
  • halo exchange communication overhead
  • CUDA acceleration for stencil computation
  • practical Docker deployment

The project also shows that parallel programming is not only about using more cores. Memory layout, communication cost, workload size, synchronization, and the execution model all matter.


Author

Built by Irfan Uruchi as a Parallel Programming project.

Tag summary

Content type

Image

Digest

sha256:16af100b1

Size

242 MB

Last updated

4 months ago

docker pull irfanuruchi/fluid-lab-cfd