//! FieldCraft's lattice Boltzmann flow solver (CPU). //! //! It solves a fluid step of the model ([`fieldcraft_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 `fieldcraft_mesh::predicates`). //! //! No code of any lattice Boltzmann package was read; everything is written from these papers and //! the book. //! //! # Determinism //! Double precision and fixed loop orders. Collision and streaming run on threads by fixed blocks //! of cells ([`fieldcraft_parallel`]), each cell's update independent of the others; the wall //! forces and every other sum run in a fixed order on one thread. The same model gives the same //! result bit for bit on any number of threads and 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] fieldcraft_model::Error), #[error(transparent)] Mesh(#[from] fieldcraft_mesh::Error), } pub type Result = std::result::Result; /// 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, } } }