forked from 1b-agent/fieldcraft-upstream
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>
45 lines
1.5 KiB
Rust
45 lines
1.5 KiB
Rust
//! Throughput of the solver (ignored; run with
|
|
//! `cargo test --release -p modelcraft-lbm --test throughput -- --ignored --nocapture`).
|
|
|
|
mod common;
|
|
|
|
use common::*;
|
|
use modelcraft_model::{BoxFace, FaceCondition};
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn cell_updates_per_second() {
|
|
for (name, l, sphere_radius) in [("periodic box", 64usize, 0.0), ("periodic box", 60, 0.0), ("box with a sphere", 64, 16.0)] {
|
|
let side = l as f64;
|
|
let mut d = domain([0.0; 3], [side; 3], 1.0);
|
|
for f in BoxFace::ALL {
|
|
*d.faces.get_mut(f) = FaceCondition::Periodic {};
|
|
}
|
|
d.acceleration = [1e-6, 0.0, 0.0];
|
|
let mut obstacles = Vec::new();
|
|
if sphere_radius > 0.0 {
|
|
d.obstacles = vec!["Ball".into()];
|
|
obstacles.push(obstacle("Ball", sphere([side / 2.0; 3], sphere_radius, 4), &["skin"]));
|
|
}
|
|
let steps = 100;
|
|
let m = model(
|
|
1.0,
|
|
1.0 / 6.0,
|
|
d,
|
|
modelcraft_model::Procedure::Fluid {
|
|
domain: "Flow".into(),
|
|
end_time: None,
|
|
steps: Some(steps),
|
|
time_step: Some(1.0),
|
|
frames: 1,
|
|
magic: None,
|
|
},
|
|
);
|
|
let (setup, mut flow) = prepare(&m, &obstacles);
|
|
let start = std::time::Instant::now();
|
|
run_all(&setup, &mut flow);
|
|
let s = start.elapsed().as_secs_f64();
|
|
println!("{name}, {l}³: {:.1} M cell updates/s", (flow.fluid_cells() as f64 * steps as f64) / s / 1e6);
|
|
}
|
|
}
|