forked from 1b-agent/fieldcraft-upstream
engine: flow-past sample, air past an L-bracket on the floor
file.sample flow-past: air at 25 mm/s past the upright L-bracket in a box of 2.5 mm lattice cells (Re 83), inlet, outlet, a no-slip floor and slip walls; the fluid step reports the force on each named face. Its test holds the drag coefficient on the upright's frontal area between 1 and 3.5 (2.3) and the lattice's mass change under 1 %. No picture: the viewport does not draw flow results yet (M12). Part of #164 (its streamlines wait for a flow display in the viewport) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
cf8ed71e4f
commit
ecdff11e72
3 files changed
+79
-1
No files matched your search
@@ -809,7 +809,7 @@ pub const RECOVERY_LIST: &[Field] = &[path("dir", "Folder", false).hint("the rec
|
||||
pub const RECOVER: &[Field] = &[text("id", "Autosave").req(), path("dir", "Folder", false).hint("the recovery folder")];
|
||||
pub const RECOVERY_DISCARD: &[Field] = &[text("id", "Autosave"), flag("all", "All"), path("dir", "Folder", false).hint("the recovery folder")];
|
||||
pub const SAMPLE: &[Field] =
|
||||
&[choice("name", "Sample", &[("cantilever", "Cantilever"), ("impact", "Impact"), ("parts", "Parts"), ("drop-test", "Drop test"), ("rubber-seal", "Rubber seal")]).req().def("\"cantilever\"")];
|
||||
&[choice("name", "Sample", &[("cantilever", "Cantilever"), ("impact", "Impact"), ("parts", "Parts"), ("drop-test", "Drop test"), ("rubber-seal", "Rubber seal"), ("flow-past", "Flow past a bracket")]).req().def("\"cantilever\"")];
|
||||
pub const COUNT: &[Field] = &[int("count", "Count", 1, 1_000_000).def("1")];
|
||||
|
||||
pub const DECK: &[Field] = &[
|
||||
|
||||
@@ -68,6 +68,13 @@ pub const SAMPLES: &[Sample] = &[
|
||||
design: None,
|
||||
script: |_| rubber_seal(),
|
||||
},
|
||||
Sample {
|
||||
name: "flow-past",
|
||||
label: "Flow Past a Bracket",
|
||||
about: "Air flowing past an L-bracket on the floor: lattice Boltzmann flow and the force on each face",
|
||||
design: Some(UPRIGHT_BRACKET),
|
||||
script: |_| flow_past(),
|
||||
},
|
||||
];
|
||||
|
||||
/// The sample called `name`.
|
||||
@@ -333,6 +340,33 @@ pub fn rubber_seal() -> Value {
|
||||
Value::Array(steps)
|
||||
}
|
||||
|
||||
/// The flow sample's free-stream speed, mm/s.
|
||||
pub const FLOW_SPEED: f64 = 25.0;
|
||||
/// Air at 20 °C: density (t/mm³) and dynamic viscosity (MPa s).
|
||||
const AIR: [f64; 2] = [1.2e-12, 1.8e-11];
|
||||
|
||||
/// Air at [`FLOW_SPEED`] past [`UPRIGHT_BRACKET`] standing on the floor, the upright's back face
|
||||
/// to the wind: a 240 × 120 × 100 mm box of 2.5 mm cells (184 320), a uniform inlet at x_min, an
|
||||
/// outlet at zero pressure at x_max, a no-slip floor and slip walls at the sides and top. Reynolds
|
||||
/// number ρ U h / μ = 83 on the upright's 50 mm height: laminar, a steady wake. Step `Flow` (16 s,
|
||||
/// about 6.7 flow-throughs; ten frames) reports the force on each named face of the bracket.
|
||||
pub fn flow_past() -> Value {
|
||||
let [density, viscosity] = AIR;
|
||||
json!([
|
||||
{"command": "model.units", "params": {"system": "mm-t-s-N-MPa"}},
|
||||
{"command": "model.material.create", "params": {"name": "Air", "density": density, "fluid": {"type": "newtonian", "viscosity": viscosity}}},
|
||||
{"command": "model.fluid_domain.create", "params": {
|
||||
"name": "Wind", "material": "Air", "min": [-60, -40, 0], "max": [180, 80, 100], "spacing": 2.5,
|
||||
"faces": {
|
||||
"x_min": {"type": "velocity", "velocity": [FLOW_SPEED, 0, 0]}, "x_max": {"type": "pressure", "pressure": 0},
|
||||
"y_min": {"type": "slip"}, "y_max": {"type": "slip"}, "z_min": {"type": "wall"}, "z_max": {"type": "slip"}
|
||||
},
|
||||
"obstacles": ["Bracket"], "initial_velocity": [FLOW_SPEED, 0, 0]
|
||||
}},
|
||||
{"command": "model.step.create", "params": {"name": "Flow", "procedure": {"type": "fluid", "domain": "Wind", "end_time": 16, "frames": 10}}},
|
||||
])
|
||||
}
|
||||
|
||||
/// Six times the signed volume of the tetrahedron `p[0..4]` (positive when p3 lies on the side
|
||||
/// p0 → p1 → p2 turns counter-clockwise around).
|
||||
fn signed_volume(p: &[[f64; 3]]) -> f64 {
|
||||
@@ -448,6 +482,29 @@ mod tests {
|
||||
assert!(stiffer > 1.05 && stiffer < 2.5, "bonded {bonded} N, frictionless {free} N");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_flow_sample_opens_ready_to_solve() {
|
||||
let s = open("flow-past");
|
||||
assert_eq!(s.model.fluid_domains().len(), 1);
|
||||
}
|
||||
|
||||
/// The drag on the bracket, as a coefficient on the upright's frontal area (40 × 50 mm), is
|
||||
/// that of a bluff plate standing on a wall at a Reynolds number of 83, raised by the 17 %
|
||||
/// blockage of the box: between 1 and 3.5 (a flat plate broadside to the flow is about 1.2 at
|
||||
/// high Reynolds number and rises as it falls). The lattice conserves mass.
|
||||
#[test]
|
||||
#[ignore = "heavy: cargo xtask test --heavy (CI heavy job)"]
|
||||
fn the_flow_past_the_bracket_has_a_bluff_body_drag() {
|
||||
let mut s = open("flow-past");
|
||||
let r = s.execute("solve.run", &json!({})).unwrap();
|
||||
let r = &r["steps"][0]["summary"];
|
||||
let drag: f64 = r["forces"].as_array().unwrap().iter().filter(|f| f["body"] == "Bracket").map(|f| f["mean"][0].as_f64().unwrap()).sum();
|
||||
let [density, _] = AIR;
|
||||
let cd = drag / (0.5 * density * FLOW_SPEED * FLOW_SPEED * 40.0 * 50.0);
|
||||
assert!(cd > 1.0 && cd < 3.5, "Cd {cd}: {r}");
|
||||
assert!(r["mass"]["relative_change"].as_f64().unwrap().abs() < 0.01, "{r}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_drop_test_opens_ready_to_solve() {
|
||||
let s = open("drop-test");
|
||||
|
||||
@@ -46,3 +46,24 @@ P = 2 (λ − λ⁻²)(C10 + C01/λ) per original area: 3 430 N against 3 466 N
|
||||
the bulge makes it stiffer (shape factor 0.5): 6 518 N, held between 1.05 and 2.5 times the
|
||||
frictionless force. The groove and the plates are prescribed displacements today; with implicit
|
||||
contact (#161) the ring will be pressed by contact against a groove.
|
||||
|
||||
## Flow past a bracket (`flow-past`)
|
||||
|
||||
Air (ρ = 1.2 kg/m³, μ = 1.8 × 10⁻⁵ Pa s) at 25 mm/s past the same L-bracket standing on the
|
||||
floor, the upright's back to the wind. A 240 × 120 × 100 mm box of 2.5 mm cells (184 320),
|
||||
uniform inlet, outlet at zero pressure, a no-slip floor and slip walls at the sides and top;
|
||||
D3Q19 lattice Boltzmann (TRT) for 16 s, about 6.7 flow-throughs, ten frames. Reynolds number
|
||||
83 on the upright's 50 mm height: laminar, a steady wake. About 10 s.
|
||||
|
||||
**Look at:** the step's report (`solve.fluid`, or Results after Solve): the force on every
|
||||
named face of the bracket and on each side of the box, final and time-averaged, and the mass
|
||||
history; `solve.probe` with `points` gives the velocity and pressure in any cell, and with
|
||||
`forces` each face's force history.
|
||||
|
||||
**Check:** the drag on the bracket, as a coefficient on the upright's frontal area
|
||||
(40 × 50 mm), is 2.3 — a bluff plate standing on a wall at low Reynolds number in a box it
|
||||
blocks by 17 %, held between 1 and 3.5 (a flat plate broadside to the flow is about 1.2 at high
|
||||
Reynolds number and rises as it falls); the lattice's mass changes by less than 1 %.
|
||||
|
||||
There is no picture yet: the viewport does not draw flow results (velocity slices and
|
||||
streamlines are planned in M12), so this example is numbers only for now.
|
||||
Reference in new issue
Block a user