diff --git a/crates/specialized/rtx-fsi/tests/fsi2_embedded3.rs b/crates/specialized/rtx-fsi/tests/fsi2_embedded3.rs index 5afd88b..7920533 100644 --- a/crates/specialized/rtx-fsi/tests/fsi2_embedded3.rs +++ b/crates/specialized/rtx-fsi/tests/fsi2_embedded3.rs @@ -301,7 +301,7 @@ fn fsi2_on_embedded3() { if (step + 1) % 50 == 0 || step + 1 == rigid_steps { last = fl.loads(); let (tot, contrib) = &last; - let (_, on_flag, on_cyl, _) = distribute(&flag_geo, &rest, contrib, fl.width); + let (_, on_flag, on_cyl, _) = distribute(&flag_geo, &rest, contrib, fl.load_width); let t = fl.time(); if let Some(f) = csv.as_mut() { writeln!( @@ -405,7 +405,7 @@ fn fsi2_on_embedded3() { (state, nodal, s.line.clone(), s.c_fluid.clone()) } None => { - let (nodal0, _, _, _) = distribute(&flag_geo, &rest, &contrib0, fl.width); + let (nodal0, _, _, _) = distribute(&flag_geo, &rest, &contrib0, fl.load_width); flag.borrow_mut().set_nodal_forces(&nodal0); let state = flag.borrow_mut().rest_state().unwrap(); // The fluid's own previous line and centreline (its geometry's history). @@ -467,7 +467,8 @@ fn fsi2_on_embedded3() { } let tl = std::time::Instant::now(); let (tot, contrib) = f.loads(); - let (nodal, on_flag, on_cyl, parts_y) = distribute(&flag_geo, &line, &contrib, f.width); + let (nodal, on_flag, on_cyl, parts_y) = + distribute(&flag_geo, &line, &contrib, f.load_width); t_loads.set(t_loads.get() + tl.elapsed().as_secs_f64()); let ts = std::time::Instant::now(); let mut st = flag.borrow_mut(); diff --git a/crates/specialized/rtx-fsi/tests/fsi2_embedded3/fluid.rs b/crates/specialized/rtx-fsi/tests/fsi2_embedded3/fluid.rs index dee7d79..99a0809 100644 --- a/crates/specialized/rtx-fsi/tests/fsi2_embedded3/fluid.rs +++ b/crates/specialized/rtx-fsi/tests/fsi2_embedded3/fluid.rs @@ -144,8 +144,10 @@ pub struct E3Fluid { pub grid: Grid, pub h: f64, pub dt: f64, - /// The z extent the loads are divided by (per unit span). + /// The duct's z extent. pub width: f64, + /// The z extent the last `loads` integrated over (per unit span). + pub load_width: f64, pub lines: Arc>, sink: Arc>>, } @@ -284,6 +286,7 @@ impl E3Fluid { h, dt, width, + load_width: width, lines, sink: Arc::new(Mutex::new(Vec::new())), } @@ -324,14 +327,25 @@ impl E3Fluid { assert!(previous.is_none(), "a load sink was already installed"); let mask = self.device.solver.mask().expect("mask"); let body = self.device.solver.body().expect("body"); - let f = mask - .cut_wall_force(body, &self.field, RHO * NU, t) - .expect("cut wall force"); + // `RTX_E3FSI_LOAD_PLANES=n`: the route on the n mid planes only (per + // unit span of those planes) — a cost knob for a spanwise-uniform + // flow; the whole span by default. + let nz = self.grid.nz; + let n = (super::env_f("RTX_E3FSI_LOAD_PLANES", 0.0) as usize).min(nz); + let f = if n > 0 && n < nz { + let k0 = (nz - n) / 2; + self.load_width = n as f64 * self.h; + mask.cut_wall_force_per_span(body, &self.field, RHO * NU, t, (k0, k0 + n)) + .expect("cut wall force per span") + } else { + self.load_width = self.width; + let f = mask + .cut_wall_force(body, &self.field, RHO * NU, t) + .expect("cut wall force"); + [f[0] / self.width, f[1] / self.width, f[2] / self.width] + }; set_load_sink(None); let contributions = std::mem::take(&mut *self.sink.lock().expect("sink")); - ( - [f[0] / self.width, f[1] / self.width, f[2] / self.width], - contributions, - ) + (f, contributions) } }