diff --git a/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/loads.rs b/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/loads.rs index ce99962..5d51829 100644 --- a/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/loads.rs +++ b/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/loads.rs @@ -252,6 +252,23 @@ impl Mask { /// `F = Σ_outer (σ·n − ρ u (u·n)) A − d/dt ∫ ρ u dV + ∫ f dV`. #[allow(clippy::too_many_arguments)] pub fn control_volume_force( + &self, + f: &Field, + dt: f64, + rho: f64, + mu: f64, + source: Option<&dyn Fn(f64, f64, f64) -> (f64, f64, f64)>, + bx: (usize, usize, usize, usize, usize, usize), + ) -> [f64; 3] { + self.control_volume_force_with_walls(f, dt, rho, mu, source, bx, false) + } + + /// Route B on a box spanning the whole z range between NO-SLIP z walls + /// (`no_slip_z`): the walls' shear on the fluid inside the box (against + /// a wall at rest) is an outer-face stress and enters the balance; + /// without it (slip or periodic sides) the z faces carry nothing. + #[allow(clippy::too_many_arguments)] + pub fn control_volume_force_with_walls( &self, f: &Field, dt: f64, @@ -259,6 +276,7 @@ impl Mask { mu: f64, source: Option<&dyn Fn(f64, f64, f64) -> (f64, f64, f64)>, (i0, i1, j0, j1, k0, k1): (usize, usize, usize, usize, usize, usize), + no_slip_z: bool, ) -> [f64; 3] { let g = self.grid(); let (nx, ny, nz, dx, dy, dz) = (g.nx, g.ny, g.nz, g.dx, g.dy, g.dz); @@ -341,6 +359,20 @@ impl Mask { // z faces on the domain's z sides: no momentum flux and no shear on // a slip wall, and the two faces cancel on a periodic pair — skipped. let full_span = k0 == 0 && k1 == nz; + if full_span && no_slip_z { + let a = dx * dy; + for j in j0..j1 { + for i in i0..i1 { + for k in [0, nz - 1] { + if !self.is_fluid_cell(g.cell(k, j, i)) { + continue; + } + force[0] -= mu * uc(k, j, i) / (0.5 * dz) * a; + force[1] -= mu * vc(k, j, i) / (0.5 * dz) * a; + } + } + } + } for j in (j0..j1).filter(|_| !full_span) { for i in i0..i1 { for (k, sign) in [(k1, 1.0), (k0, -1.0)] { diff --git a/crates/specialized/rtx-cfd/tests/embedded3_dfg_2z.rs b/crates/specialized/rtx-cfd/tests/embedded3_dfg_2z.rs index 622b894..a33f82a 100644 --- a/crates/specialized/rtx-cfd/tests/embedded3_dfg_2z.rs +++ b/crates/specialized/rtx-cfd/tests/embedded3_dfg_2z.rs @@ -129,7 +129,8 @@ fn dfg_3d_2z_on_the_device() { 0, nz, ); - let fcv = mask.control_volume_force(&field, dt, RHO, RHO * NU, None, bx); + let fcv = + mask.control_volume_force_with_walls(&field, dt, RHO, RHO * NU, None, bx, true); let zc = 0.5 * H; let p_front = mask .pressure_at(&field.p, CX - 0.5 * D, CY, zc)