8.5 KiB
CelerisLab
GPU-Accelerated Lattice Boltzmann Method (LBM) CFD Solver
CelerisLab is a high-performance computational fluid dynamics (CFD) solver based on the Lattice Boltzmann Method, leveraging NVIDIA CUDA for GPU acceleration. It provides a Python interface for easy integration into scientific workflows while maintaining high computational efficiency through CUDA kernels.
Features
- GPU Acceleration: CUDA-based kernels for high-performance simulations
- D2Q9 / D3Q19 Lattice: 2D and 3D lattice implementations
- Multiple Collision Models: SRT, TRT, and MRT operators; Smagorinsky LES subgrid model
- Dual Streaming Paths: Standard double-buffer pull and memory-efficient esoteric-pull (EsoPull)
- Immersed Boundary Method (IBM): Support for complex geometries (cylinders, arbitrary shapes)
- Flexible Boundary Conditions: NEQ-extrapolation pressure outlet, parabolic/uniform velocity inlet, half-way bounce-back walls
- Layered Configuration: Compile-time parameters organized into Global / Method / Case / Debug tiers
- High-Re Validated: Tested up to Re=5000 (2D cylinder); MRT+LES and SRT+LES stable; TRT+LES stable with tuned Lambda and WMAX
- Python API: High-level
Simulationclass for scripting and RL integration
Installation
Prerequisites
- Python 3.8 or higher
- NVIDIA GPU with CUDA Compute Capability 6.0 or higher
- CUDA Toolkit 11.0 or higher
- NVIDIA drivers
Install from source
git clone <repository_url>
cd CelerisLab
pip install -e . # Installs from src/ directory
Dependencies
pycuda>=2020.1: CUDA Python bindingsnumpy>=1.19.0: Numerical computingscipy>=1.5.0: Scientific computing (special functions for vortex initialization)
Quick Start
from CelerisLab import Simulation
# Path is optional; see Configuration → paths. Example passes the usual relative name.
sim = Simulation("configs/config_lbm.json")
sim.add_cylinder(center=(50, 50), radius=10)
sim.initialize()
for step in range(10000):
sim.run(1)
macro = sim.get_macroscopic() # {"rho": ..., "ux": ..., "uy": ...}
sim.close()
Or as a context manager:
with Simulation("configs/config_lbm.json") as sim:
sim.add_cylinder(center=(96, 64), radius=12)
sim.initialize()
sim.run(5000)
data = sim.get_macroscopic()
Configuration
Where config_lbm.json is loaded from
load_lbm_config() resolves config_lbm.json in this order: an explicit path argument to Simulation(...) / load_lbm_config(path), then $CELERISLAB_CONFIG_DIR/config_lbm.json, then ./configs/config_lbm.json under the current working directory, then the copy shipped inside the installed package at CelerisLab/configs/config_lbm.json. In a source checkout the same file lives at src/CelerisLab/configs/config_lbm.json. There is no top-level configs/ directory at the repository root; from the clone root you can omit the path (Simulation()), set CELERISLAB_CONFIG_DIR, or create your own ./configs/config_lbm.json.
config_lbm.json shape
The on-disk schema matches src/CelerisLab/configs/config_lbm.json (nested sections). Example fragment:
{
"grid": {
"lattice_model": "D2Q9",
"nx": 512,
"ny": 256,
"nz": 1
},
"physics": {
"data_type": "FP32",
"viscosity": 0.0035,
"velocity": 0.03,
"rho": 1.0
},
"method": {
"collision": "SRT",
"streaming": "double_buffer",
"store_precision": "FP32",
"ddf_shifting": false,
"les": { "enabled": false, "cs": 0.16, "closed_form": true },
"trt": { "magic_param": 0.1875 },
"inlet": { "profile": "parabolic", "trt_neq_damp": 0.5 },
"outlet": {
"mode": "neq_extrap",
"backflow_clamp": true,
"blend_alpha": 0.7,
"srt_neq_damp": 0.5
},
"omega_guard": { "min": 0.01, "max": 1.96 }
},
"cuda": {
"threads_per_block": 256,
"compute_capability": "auto"
}
}
Lattice size and model come from grid; viscosity and scales from physics; collision, LES, boundaries, and ω clamps from method (ω upper bound is method.omega_guard.max, not a top-level omega_max). For high-Re runs, keep method.omega_guard.max in the 1.90-1.96 window. See src/CelerisLab/configs/CONFIG.md for the full parameter tables.
Parameter tiers
| Tier | Headers | Examples |
|---|---|---|
| Global/Grid | config_grid.h |
NX, NY, NZ, LATTICE_MODEL; DIM / NQ are derived from LATTICE_MODEL when cuda/compiler_v2.py emits headers (they are not separate keys in JSON) |
| Global/Physics | config_physics.h |
VIS, RHO, U0, flag constants |
| Method | config_method.h |
COLLISION_MODEL, USE_LES, TRT_MAGIC_PARAM, OMEGA_COLLISION_MAX |
| Case | config_objects.h, config_obs.h |
N_OBJS; packed obs macros OBS_* from generate_config(cfg, n_objects=K) (max(N_OBJS,1) × DIM per segment; no extra JSON keys) |
Headers are auto-generated by cuda/compiler_v2.py from LBMConfig; do not edit manually.
API Reference
Simulation
sim = Simulation(lbm_config_path=None, body_config_path=None, device_id=0)
sim.add_cylinder(center, radius) -> int
sim.add_sensor(center, radius) -> int
sim.initialize() # recompiles with N_OBJS when bodies were added
sim.run(steps, checkpoint_interval=0) # wires bodies.action_gpu / bodies.obs_gpu
sim.step(n=1)
sim.bodies # ObjectManager: packed buffers + zero_force_segment_async, ...
sim.get_macroscopic() -> {"rho": ndarray, "ux": ndarray, "uy": ndarray}
sim.get_ddf() -> ndarray
sim.get_flags() -> ndarray
sim.update_runtime_params(omega=..., u_inlet=...)
sim.snapshot() / sim.restore()
sim.save_checkpoint(path=None) -> str # HDF5; default path if omitted
sim.load_checkpoint(path) # restores field, step count, bodies
sim.close()
LBMStepper (advanced)
stepper.step(n=1, *, action_gpu, obs_gpu, stream=None)
Curved BC / sensor lists live on field.curved and field.sensors (CurvedLinkSoA / SensorSoA), filled by ObjectManager.sync_to_gpu(field).
Vortex initialization
from CelerisLab.lbm.initializers import add_vortex
# Superimpose a Lamb–Oseen vortex on an existing LBMField
add_vortex(sim.field, center=(50, 50), radius=10.0, strength=1.0, vortex_type="lamb")
Collision & LES Recommendations
| Use case | Recommended config |
|---|---|
| Low Re (≤ 500) | SRT or TRT, LES off |
| Medium Re (500–2000) | MRT or SRT+LES |
| High Re (2000–5000) | MRT+LES (most robust); SRT+LES; TRT+LES with method.omega_guard.max in 1.90-1.96 (default 1.96) and tuned method.trt.magic_param (default 0.1875) |
Project Layout
src/CelerisLab/
simulation.py High-level API
config.py LBMConfig / BodyConfig dataclasses
cuda/
compiler_v2.py Config header generation + nvcc + PTX load
context.py CUDA context lifecycle
lbm/
field.py GPU memory + ``curved`` / ``sensors`` SoA handles
curved_links.py CurvedLinkSoA / SensorSoA
stepper.py Time-step driver (``action_gpu``, ``obs_gpu``)
initializers.py Vortex superposition
kernels/
kernel_v2.cu Kernel entry (thin wrapper)
config/ Auto-generated headers (``config_grid.h``, …, ``config_obs.h``)
core/ Descriptors, layout, flags, params
operators/ Collision, LES, forcing
boundary/ Inlet, outlet, wall, curved, IBM
streaming/ Double-buffer & esopull
step/ Step orchestration
body/
objects.py SimObject / Cylinder / Sensor
manager.py ObjectManager; packed ``obs_gpu`` / ``obs_pinned``, B3 helpers
common/
preprocess.py Geometry utilities
output/
CelerisLab_stage1_architecture.md Architecture specification (v3)
refactor_brief_stage1.md Refactoring brief
high_re_audit_round1.md 8-round audit log
legacy/ Superseded code (FlowField, compiler v1, macros.h)
Performance
Tested on Tesla V100-SXM2-16GB (CUDA 12.4):
| Config | Grid | MLUPS |
|---|---|---|
| Re100 MRT noLES | 384×192 | ~4200 |
| Re100 EsoPull SRT | 384×192 | ~3900 |
| Re3000 MRT+LES | 384×192 | ~4360 |
Citation
If you use CelerisLab in your research, please cite:
@software{celerislab2026,
author = {Frank14f},
title = {CelerisLab: GPU-Accelerated Lattice Boltzmann Method Solver},
year = {2026},
url = {https://github.com/frank14f/CelerisLab}
}
License
MIT License — see LICENSE file for details.