Lattice Boltzmann flow on the CPU: model, solver, engine (M12) (#36)

Model: Newtonian fluid materials; fluid domains (box, spacing, conditions on
the box faces, obstacle bodies with conditions on their named faces, initial
velocity, body acceleration); fluid steps with caps. Deck writers refuse
fluid steps; a fluid-only model needs no mesh in model.check; one step
selector (Model::select_step) for every solver.

New L2 crate modelcraft-lbm: D3Q19 two-relaxation-time collision with Guo
forcing; halfway bounce-back walls (moving walls after Ladd), slip faces,
periodic pairs; Zou–He velocity and pressure faces with the D3Q19
transverse correction; obstacles voxelised from the face-tagged boundary
surface with exact predicates and symbolic perturbation; momentum-exchange
forces per box face and per B-rep face; unit conversion, automatic time step
and Mach/tau limits; bounded runs with frames and force histories.

Engine: model.fluid_domain.create/edit/delete, model.fluid_domain.boundary,
solve.fluid (obstacles from the open design or imported surfaces, lowerable
caps), solve.probe for fluid fields and wall force histories. Fluid Domain,
Inlet & Outlet and Lattice Boltzmann toolbar entries are ready.

Verification (analytic): plane Poiseuille exact with Λ = 3/16 and second
order (2.000) with Λ = 1/4; Couette exact with the wall shear; Taylor–Green
decay second order (2.01, 2.00); staircase pipe; Stokes drag of a sphere
array within 1.7% of Hasimoto at R = 6; Zou–He channel; mass conserved to
round-off; bit-for-bit reproducibility. Benchmark: Schäfer–Turek 2D-1.


Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm

Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-10-13 20:03:12 -04:00
1 parent bd55abea7f
commit a17752a49f
55 files changed
+3800 -64

No files matched your search

+107
View File
@@ -0,0 +1,107 @@
//! ModelCraft's lattice Boltzmann flow solver (CPU).
//!
//! It solves a fluid step of the model ([`modelcraft_model::Procedure::Fluid`]) in its fluid
//! domain: weakly compressible, isothermal, Newtonian flow on a uniform grid of cubic cells that
//! fills the domain's box, less the cells inside the obstacle bodies.
//!
//! - [`voxel`]: which cells the obstacles take, decided with exact predicates from the
//! face-tagged boundary surface, and which face each wall link meets.
//! - [`setup`]: the step in lattice units, the time step, and the stability limits.
//! - [`flow`]: the D3Q19 two-relaxation-time scheme with Guo forcing, halfway bounce-back
//! walls (moving walls after Ladd), slip faces, Zou–He inlets and outlets, and the
//! momentum-exchange force on every wall.
//! - [`solve`]: the time loop, output frames and force histories in model units.
//!
//! # Sources
//! - T. Krüger, H. Kusumaatmaja, A. Kuzmin, O. Shardt, G. Silva, E. M. Viggen, *The Lattice
//! Boltzmann Method: Principles and Practice*, Springer 2017 (velocity sets, equilibria, units,
//! stream–collide, bounce-back, forcing, boundary conditions).
//! - Y. H. Qian, D. d'Humières, P. Lallemand, *Lattice BGK models for Navier–Stokes equation*,
//! EPL 17(6):479, 1992 (D3Q19).
//! - I. Ginzburg, F. Verhaeghe, D. d'Humières, *Two-relaxation-time lattice Boltzmann scheme:
//! about parametrization, velocity, pressure and mixed boundary conditions*, Commun. Comput.
//! Phys. 3(2):427–478, 2008 (TRT and the parameter Λ).
//! - Z. Guo, C. Zheng, B. Shi, *Discrete lattice effects on the forcing term in the lattice
//! Boltzmann method*, PRE 65:046308, 2002 (body force).
//! - A. J. C. Ladd, *Numerical simulations of particulate suspensions via a discretized Boltzmann
//! equation. Part 1*, JFM 271:285–309, 1994 (bounce-back, moving walls, momentum exchange).
//! - R. Mei, D. Yu, W. Shyy, L.-S. Luo, *Force evaluation in the lattice Boltzmann method
//! involving curved geometry*, PRE 65:041203, 2002 (momentum exchange).
//! - Q. Zou, X. He, *On pressure and velocity boundary conditions for the lattice Boltzmann BGK
//! model*, Phys. Fluids 9(6):1591–1598, 1997; M. Hecht, J. Harting, J. Stat. Mech. 2010,
//! P01018 (the D3Q19 transverse correction).
//! - P. Lallemand, L.-S. Luo, *Theory of the lattice Boltzmann method: dispersion, dissipation,
//! isotropy, Galilean invariance, and stability*, PRE 61:6546, 2000 (stability limits).
//! - H. Edelsbrunner, E. P. Mücke, *Simulation of Simplicity*, ACM TOG 9(1):66–104, 1990;
//! J. R. Shewchuk 1997 (exact predicates, through `modelcraft_mesh::predicates`).
//!
//! No code of any lattice Boltzmann package was read; everything is written from these papers and
//! the book.
//!
//! # Determinism
//! Double precision, fixed loop orders, no threads and no parallel reductions: the same model
//! gives the same result bit for bit on every platform, wasm included.
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
#![forbid(unsafe_code)]
// Population arrays are indexed by cell and direction counts fixed when they are allocated.
#![allow(clippy::needless_range_loop)]
pub mod flow;
pub mod lattice;
pub mod setup;
pub mod solve;
pub mod voxel;
pub use flow::{Flow, Group};
pub use setup::{Obstacle, Setup, fluid_step};
pub use solve::{FluidResult, FluidStats, ForceHistory, Frame, run, solve_fluid};
pub use voxel::Grid;
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum Error {
#[error("invalid input: {0}")]
Invalid(String),
#[error("not found: {0}")]
NotFound(String),
#[error("limit reached: {0}")]
Limit(String),
/// The run diverged.
#[error("unstable: {0}")]
Unstable(String),
#[error(transparent)]
Model(#[from] modelcraft_model::Error),
#[error(transparent)]
Mesh(#[from] modelcraft_mesh::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
/// Caps on a run's size and work; a run beyond any of them is refused before it starts.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Limits {
pub max_cells: u64,
pub max_steps: u64,
/// Fluid cells times time steps.
pub max_cell_updates: u64,
/// The memory the output frames may take.
pub max_frame_bytes: u64,
}
impl Limits {
/// 16 million cells: about 5 GB of populations in double precision.
pub const MAX_CELLS: u64 = 16_000_000;
pub const MAX_STEPS: u64 = 10_000_000;
pub const MAX_CELL_UPDATES: u64 = 1_000_000_000_000;
pub const MAX_FRAME_BYTES: u64 = 2_000_000_000;
}
impl Default for Limits {
fn default() -> Self {
Limits {
max_cells: Limits::MAX_CELLS,
max_steps: Limits::MAX_STEPS,
max_cell_updates: Limits::MAX_CELL_UPDATES,
max_frame_bytes: Limits::MAX_FRAME_BYTES,
}
}
}