From 6d2872e7d05fd79050859f41405506a6c2f0a246 Mon Sep 17 00:00:00 2001 From: Omar Sobh Date: Thu, 17 Sep 2026 23:10:15 -0500 Subject: [PATCH] =?UTF-8?q?embedded3=20S2-2b-ii=20HELD:=20the=20device=20V?= =?UTF-8?q?-cycle's=20fine=20level=20refreshed=20with=20the=20operator=20(?= =?UTF-8?q?coarser=20levels=20kept=20K=20steps),=20the=20fine=20rhs=20zero?= =?UTF-8?q?ed=20before=20the=20gather=20=E2=80=94=20moving=20circle=20iden?= =?UTF-8?q?tity=201.7e-14=20at=20K=20=3D=2010,=20CG=20+9=20%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- .../embedded3/poisson/device.rs | 42 +++++++++++++++++++ .../embedded3/poisson/device_cg.rs | 5 +++ 2 files changed, 47 insertions(+) diff --git a/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device.rs b/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device.rs index 3e02738..afb956e 100644 --- a/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device.rs +++ b/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device.rs @@ -171,6 +171,48 @@ impl DeviceVcycle { self.levels.len() } + /// Refresh the finest level (its cells, colours, neighbours, parents + /// and coefficients) for a changed operator, keeping the coarser + /// levels: the smoother is exact on the current operator, the coarse + /// correction approximate (a moving body's per-step refresh). + pub fn refresh_fine(&mut self, level0: &LevelExport) { + let rt = runtime(); + let up_u = |v: &[u32]| -> CudaSlice { + rt.stream + .memcpy_stod(if v.is_empty() { &[0u32][..] } else { v }) + .expect("upload") + }; + let up_f = |v: &[f32]| -> CudaSlice { rt.stream.memcpy_stod(v).expect("upload") }; + let lv = &mut self.levels[0]; + lv.n_cells = level0.cells.len(); + lv.n_red = level0.red.len(); + lv.n_black = level0.black.len(); + lv.cells = up_u(&level0.cells); + lv.red = up_u(&level0.red); + lv.black = up_u(&level0.black); + lv.top = up_u(&level0.top); + lv.bot = up_u(&level0.bot); + lv.coarse_of = up_u(&level0.coarse_of); + lv.ae = up_f(&level0.ae); + lv.aw = up_f(&level0.aw); + lv.an = up_f(&level0.an); + lv.as_ = up_f(&level0.as_); + lv.at = up_f(&level0.at); + lv.ab = up_f(&level0.ab); + lv.ap = up_f(&level0.ap); + self.fine_cells = level0.cells.clone(); + } + + /// Zero the finest level's right-hand side (a gather writes only the + /// current cells; stale entries elsewhere would restrict into the + /// coarse levels). + pub fn zero_fine_rhs(&mut self) { + let rt = runtime(); + rt.stream + .memset_zeros(&mut self.levels[0].b) + .expect("b0 = 0"); + } + fn half(&mut self, l: usize, colour: u8) { let rt = runtime(); let k = kernels(); diff --git a/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device_cg.rs b/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device_cg.rs index c4ee0ec..10d1665 100644 --- a/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device_cg.rs +++ b/crates/specialized/rtx-cfd/src/solvers/incompressible/embedded3/poisson/device_cg.rs @@ -242,6 +242,10 @@ impl DeviceCg { self.singular = singular_count > 0; self.active_host = fine.active.clone(); self.key = OperatorKey::of(problem, params); + // The V-cycle's finest level follows the operator (its coarser + // levels stay). + let levels = export_hierarchy(problem, params); + self.vcycle.refresh_fine(&levels[0]); } pub fn n_cells(&self) -> usize { @@ -435,6 +439,7 @@ impl DeviceCg { let k = kernels(); let n_i = self.n_cells as i32; rt.stream.memset_zeros(&mut self.z).expect("z = 0"); + self.vcycle.zero_fine_rhs(); unsafe { rt.stream .launch_builder(&k.gather_f32)