embedded3 item 9b: the device step carries a static cut-cell mask (e3_cut.cu: cut predictor, apertured merged continuity with the fold, owner-read corrections; device CG off-stencil links) — host = device to 2e-10 (CFD1 cylinder nz 4) and 4e-14 (sphere) under tight tolerances
CI / Clippy Check (push) Failing after 4s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
CI / Format Check (push) Failing after 4s
CI / Build (ubuntu-latest) (push) Failing after 4s
Documentation / Build User Guide (push) Successful in 5s
CI / Build CPU-Only (Explicit) (push) Failing after 56s
Documentation / Build API Documentation (push) Failing after 58s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (macos-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (ubuntu-latest) (push) Canceled after 0s
CI / WASM Build + Size Check (push) Canceled after 0s
CI / Distributed Training Tests (push) Canceled after 0s
CI / CI Success (push) Canceled after 0s
CI / Test (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Clippy Check (push) Failing after 4s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
CI / Format Check (push) Failing after 4s
CI / Build (ubuntu-latest) (push) Failing after 4s
Documentation / Build User Guide (push) Successful in 5s
CI / Build CPU-Only (Explicit) (push) Failing after 56s
Documentation / Build API Documentation (push) Failing after 58s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (macos-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (ubuntu-latest) (push) Canceled after 0s
CI / WASM Build + Size Check (push) Canceled after 0s
CI / Distributed Training Tests (push) Canceled after 0s
CI / CI Success (push) Canceled after 0s
CI / Test (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
0fa05f2056
commit
3b3d6c84c0
@@ -70,6 +70,10 @@ pub struct DeviceCg {
|
||||
at: CudaSlice<f64>,
|
||||
ab: CudaSlice<f64>,
|
||||
ap: CudaSlice<f64>,
|
||||
/// Off-stencil links per cell (CSR; the merged small cells).
|
||||
link_ptr: CudaSlice<u32>,
|
||||
link_idx: CudaSlice<u32>,
|
||||
link_coef: CudaSlice<f64>,
|
||||
b: CudaSlice<f64>,
|
||||
r: CudaSlice<f64>,
|
||||
z: CudaSlice<f64>,
|
||||
@@ -118,6 +122,18 @@ impl DeviceCg {
|
||||
};
|
||||
let up_f = |v: &[f64]| -> CudaSlice<f64> { rt.stream.memcpy_stod(v).expect("upload") };
|
||||
let zeros = || rt.stream.alloc_zeros::<f64>(n).expect("alloc");
|
||||
let lists = problem.link_lists();
|
||||
let mut link_ptr = Vec::with_capacity(n + 1);
|
||||
let mut link_idx = Vec::new();
|
||||
let mut link_coef = Vec::new();
|
||||
link_ptr.push(0u32);
|
||||
for list in &lists {
|
||||
for &(other, c) in list {
|
||||
link_idx.push(other as u32);
|
||||
link_coef.push(c);
|
||||
}
|
||||
link_ptr.push(link_idx.len() as u32);
|
||||
}
|
||||
Self {
|
||||
key: OperatorKey::of(problem, params),
|
||||
n,
|
||||
@@ -134,6 +150,13 @@ impl DeviceCg {
|
||||
at: up_f(&fine.at),
|
||||
ab: up_f(&fine.ab),
|
||||
ap: up_f(&fine.ap),
|
||||
link_ptr: up_u(&link_ptr),
|
||||
link_idx: up_u(&link_idx),
|
||||
link_coef: up_f(if link_coef.is_empty() {
|
||||
&[0.0]
|
||||
} else {
|
||||
&link_coef
|
||||
}),
|
||||
b: zeros(),
|
||||
r: zeros(),
|
||||
z: zeros(),
|
||||
@@ -324,6 +347,9 @@ impl DeviceCg {
|
||||
.arg(&self.ab)
|
||||
.arg(&self.top)
|
||||
.arg(&self.bot)
|
||||
.arg(&self.link_ptr)
|
||||
.arg(&self.link_idx)
|
||||
.arg(&self.link_coef)
|
||||
.arg(&self.ap)
|
||||
.arg(&self.b)
|
||||
.arg(p)
|
||||
@@ -481,6 +507,9 @@ impl DeviceCg {
|
||||
.arg(&self.ab)
|
||||
.arg(&self.top)
|
||||
.arg(&self.bot)
|
||||
.arg(&self.link_ptr)
|
||||
.arg(&self.link_idx)
|
||||
.arg(&self.link_coef)
|
||||
.arg(&self.ap)
|
||||
.arg(&self.d)
|
||||
.arg(&mut self.q)
|
||||
|
||||
@@ -208,7 +208,14 @@ impl Problem {
|
||||
}
|
||||
}
|
||||
for &(a, b, c) in &self.links {
|
||||
if a >= n || b >= n || a == b || !self.active[a] || !self.active[b] || c <= 0.0 || c.is_nan() {
|
||||
if a >= n
|
||||
|| b >= n
|
||||
|| a == b
|
||||
|| !self.active[a]
|
||||
|| !self.active[b]
|
||||
|| c <= 0.0
|
||||
|| c.is_nan()
|
||||
{
|
||||
return Err(format!("invalid link ({a}, {b}, {c})"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
//! fields into a `Field` at instants. Compiled with FMA contraction
|
||||
//! off so the predictors are the host's arithmetic to the bit.
|
||||
|
||||
mod cut;
|
||||
|
||||
use super::{Side, Solver, StepResult};
|
||||
use crate::solvers::incompressible::embedded3::Grid;
|
||||
use crate::solvers::incompressible::embedded3::field::Field;
|
||||
@@ -150,6 +152,8 @@ pub struct DeviceStep {
|
||||
cg_dt: f64,
|
||||
timers: Option<StepTimers>,
|
||||
initialized: bool,
|
||||
/// A static cut-cell mask's tables (item 9b), when the solver has one.
|
||||
cut: Option<cut::DeviceCut>,
|
||||
}
|
||||
|
||||
impl DeviceStep {
|
||||
@@ -177,6 +181,7 @@ impl DeviceStep {
|
||||
let timers = std::env::var("RTX_PROFILE")
|
||||
.is_ok()
|
||||
.then(StepTimers::default);
|
||||
let cut = cut::DeviceCut::build(&solver, grid);
|
||||
Self {
|
||||
solver,
|
||||
grid,
|
||||
@@ -203,9 +208,15 @@ impl DeviceStep {
|
||||
cg_dt: 0.0,
|
||||
timers,
|
||||
initialized: false,
|
||||
cut,
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of virtually merged cells on the device mask (0 without one).
|
||||
pub fn merged_cells(&self) -> usize {
|
||||
self.cut.as_ref().map_or(0, |c| c.merged)
|
||||
}
|
||||
|
||||
pub fn timers(&self) -> Option<StepTimers> {
|
||||
self.timers
|
||||
}
|
||||
@@ -385,6 +396,9 @@ impl DeviceStep {
|
||||
if !self.initialized {
|
||||
self.initialize();
|
||||
}
|
||||
if self.cut.is_some() {
|
||||
return self.advance_cut(dt);
|
||||
}
|
||||
let rt = runtime();
|
||||
let k = kernels();
|
||||
let g = self.grid;
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
//! Item 9b: the device step carrying a static cut-cell mask — the mask's
|
||||
//! tables uploaded once (apertures, face distances, surface velocities at
|
||||
//! the feet, the compatible wall flux, the open faces, the active cells,
|
||||
//! the merged cells' owners and the fold lists) and the step's cut
|
||||
//! kernels (`e3_cut.cu`, appended to `e3_step.cu` at load).
|
||||
|
||||
use super::{DeviceStep, E3Params, E3Ptrs, StepResult};
|
||||
use crate::solvers::incompressible::embedded3::Grid;
|
||||
use crate::solvers::incompressible::embedded3::poisson::device::{cfg, load_module, runtime};
|
||||
use crate::solvers::incompressible::embedded3::poisson::device_cg::DeviceCg;
|
||||
use crate::solvers::incompressible::embedded3::step::Solver;
|
||||
use crate::solvers::incompressible::poisson::MultigridParameters;
|
||||
use cudarc::driver::{
|
||||
CudaFunction, CudaModule, CudaSlice, DevicePtr, DeviceRepr, PushKernelArg, ValidAsZeroBits,
|
||||
};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Instant;
|
||||
|
||||
const CUT_KERNELS: &str = concat!(
|
||||
include_str!("../../../../../kernels/cuda/e3_step.cu"),
|
||||
include_str!("../../../../../kernels/cuda/e3_cut.cu")
|
||||
);
|
||||
|
||||
struct CutKernels {
|
||||
_module: Arc<CudaModule>,
|
||||
predict: CudaFunction,
|
||||
divergence: CudaFunction,
|
||||
fold: CudaFunction,
|
||||
correct: CudaFunction,
|
||||
add_p: CudaFunction,
|
||||
}
|
||||
|
||||
static CUT_KERNELS_ONCE: OnceLock<CutKernels> = OnceLock::new();
|
||||
|
||||
fn cut_kernels() -> &'static CutKernels {
|
||||
CUT_KERNELS_ONCE.get_or_init(|| {
|
||||
let module = load_module(CUT_KERNELS, "e3_cut.cu", true);
|
||||
let f = |name: &str| module.load_function(name).expect(name);
|
||||
CutKernels {
|
||||
predict: f("e3_cut_predict"),
|
||||
divergence: f("e3_cut_divergence"),
|
||||
fold: f("e3_cut_fold"),
|
||||
correct: f("e3_cut_correct"),
|
||||
add_p: f("e3_cut_add_p"),
|
||||
_module: module,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// `struct E3Cut` in e3_cut.cu: 18 device pointers.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct E3CutPtrs {
|
||||
ptrs: [u64; 18],
|
||||
}
|
||||
unsafe impl DeviceRepr for E3CutPtrs {}
|
||||
unsafe impl ValidAsZeroBits for E3CutPtrs {}
|
||||
|
||||
/// The static cut-cell mask on the device.
|
||||
pub(super) struct DeviceCut {
|
||||
a: [CudaSlice<f64>; 3],
|
||||
d: [CudaSlice<f64>; 3],
|
||||
ub: [CudaSlice<f64>; 3],
|
||||
wall_flux: CudaSlice<f64>,
|
||||
open: [CudaSlice<i32>; 3],
|
||||
active: CudaSlice<i32>,
|
||||
owner: CudaSlice<u32>,
|
||||
fold_ptr: CudaSlice<u32>,
|
||||
fold_idx: CudaSlice<u32>,
|
||||
cell_flux: CudaSlice<f64>,
|
||||
pub(super) merged: usize,
|
||||
}
|
||||
|
||||
impl DeviceCut {
|
||||
/// The tables of the solver's cut mask (`None` without one).
|
||||
pub(super) fn build(solver: &Solver, g: Grid) -> Option<Self> {
|
||||
let mask = solver.mask()?;
|
||||
let cut = mask.cut()?;
|
||||
let body = solver.body()?;
|
||||
let rt = runtime();
|
||||
let (nx, ny, nz) = (g.nx, g.ny, g.nz);
|
||||
let h = [g.dx, g.dy, g.dz];
|
||||
let counts = [(nx + 1) * ny * nz, nx * (ny + 1) * nz, nx * ny * (nz + 1)];
|
||||
let up_f = |v: &[f64]| -> CudaSlice<f64> {
|
||||
rt.stream
|
||||
.memcpy_stod(if v.is_empty() { &[0.0f64][..] } else { v })
|
||||
.expect("upload")
|
||||
};
|
||||
let up_i = |v: &[i32]| -> CudaSlice<i32> { rt.stream.memcpy_stod(v).expect("upload") };
|
||||
let up_u = |v: &[u32]| -> CudaSlice<u32> {
|
||||
rt.stream
|
||||
.memcpy_stod(if v.is_empty() { &[0u32][..] } else { v })
|
||||
.expect("upload")
|
||||
};
|
||||
// Surface velocity at the foot per face, and the open flags.
|
||||
let mut ub: [Vec<f64>; 3] = [Vec::new(), Vec::new(), Vec::new()];
|
||||
let mut open: [Vec<i32>; 3] = [Vec::new(), Vec::new(), Vec::new()];
|
||||
for c in 0..3 {
|
||||
let (ni, nj, nk) = match c {
|
||||
0 => (nx + 1, ny, nz),
|
||||
1 => (nx, ny + 1, nz),
|
||||
_ => (nx, ny, nz + 1),
|
||||
};
|
||||
let mut ubc = vec![0.0; counts[c]];
|
||||
let mut opc = vec![0i32; counts[c]];
|
||||
for k in 0..nk {
|
||||
for j in 0..nj {
|
||||
for i in 0..ni {
|
||||
let idx = (k * nj + j) * ni + i;
|
||||
let x = [
|
||||
(i as f64 + if c == 0 { 0.0 } else { 0.5 }) * h[0],
|
||||
(j as f64 + if c == 1 { 0.0 } else { 0.5 }) * h[1],
|
||||
(k as f64 + if c == 2 { 0.0 } else { 0.5 }) * h[2],
|
||||
];
|
||||
ubc[idx] = mask.surface_velocity_at(body, x, c, 0.0);
|
||||
opc[idx] = i32::from(match c {
|
||||
0 => mask.u_open(idx),
|
||||
1 => mask.v_open(idx),
|
||||
_ => mask.w_open(idx),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
ub[c] = ubc;
|
||||
open[c] = opc;
|
||||
}
|
||||
let (wall_flux, _) = mask.wall_flux_table(body, 0.0);
|
||||
let nc = g.cells();
|
||||
let active: Vec<i32> = (0..nc).map(|i| i32::from(mask.cell_active(i))).collect();
|
||||
let owner: Vec<u32> = (0..nc)
|
||||
.map(|i| mask.master(i).unwrap_or(i) as u32)
|
||||
.collect();
|
||||
let mut fold_ptr = Vec::with_capacity(nc + 1);
|
||||
let mut fold_idx = Vec::new();
|
||||
let mut slaves_of: Vec<Vec<u32>> = vec![Vec::new(); nc];
|
||||
let mut merged = 0;
|
||||
for i in 0..nc {
|
||||
if let Some(m) = mask.master(i) {
|
||||
slaves_of[m].push(i as u32);
|
||||
merged += 1;
|
||||
}
|
||||
}
|
||||
fold_ptr.push(0u32);
|
||||
for list in &slaves_of {
|
||||
fold_idx.extend_from_slice(list);
|
||||
fold_ptr.push(fold_idx.len() as u32);
|
||||
}
|
||||
Some(Self {
|
||||
a: [up_f(&cut.a_u), up_f(&cut.a_v), up_f(&cut.a_w)],
|
||||
d: [up_f(&cut.d_u), up_f(&cut.d_v), up_f(&cut.d_w)],
|
||||
ub: [up_f(&ub[0]), up_f(&ub[1]), up_f(&ub[2])],
|
||||
wall_flux: up_f(&wall_flux),
|
||||
open: [up_i(&open[0]), up_i(&open[1]), up_i(&open[2])],
|
||||
active: up_i(&active),
|
||||
owner: up_u(&owner),
|
||||
fold_ptr: up_u(&fold_ptr),
|
||||
fold_idx: up_u(&fold_idx),
|
||||
cell_flux: rt.stream.alloc_zeros::<f64>(nc).expect("alloc"),
|
||||
merged,
|
||||
})
|
||||
}
|
||||
|
||||
fn ptrs(&self) -> E3CutPtrs {
|
||||
let rt = runtime();
|
||||
let s = &rt.stream;
|
||||
let pf = |x: &CudaSlice<f64>| x.device_ptr(s).0;
|
||||
let pi = |x: &CudaSlice<i32>| x.device_ptr(s).0;
|
||||
let pu = |x: &CudaSlice<u32>| x.device_ptr(s).0;
|
||||
E3CutPtrs {
|
||||
ptrs: [
|
||||
pf(&self.a[0]),
|
||||
pf(&self.a[1]),
|
||||
pf(&self.a[2]),
|
||||
pf(&self.d[0]),
|
||||
pf(&self.d[1]),
|
||||
pf(&self.d[2]),
|
||||
pf(&self.ub[0]),
|
||||
pf(&self.ub[1]),
|
||||
pf(&self.ub[2]),
|
||||
pf(&self.wall_flux),
|
||||
pi(&self.open[0]),
|
||||
pi(&self.open[1]),
|
||||
pi(&self.open[2]),
|
||||
pi(&self.active),
|
||||
pu(&self.owner),
|
||||
pu(&self.fold_ptr),
|
||||
pu(&self.fold_idx),
|
||||
pf(&self.cell_flux),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceStep {
|
||||
/// One step on the cut-cell mask (the host `advance` with the cut
|
||||
/// predictor, the apertured merged continuity and the owner-read
|
||||
/// corrections).
|
||||
pub(super) fn advance_cut(&mut self, dt: f64) -> StepResult {
|
||||
let rt = runtime();
|
||||
let k = cut_kernels();
|
||||
let g = self.grid;
|
||||
let t_old = self.solver.time();
|
||||
let t_new = t_old + dt;
|
||||
let t0 = Instant::now();
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.u, &mut self.u_old)
|
||||
.expect("u_old");
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.v, &mut self.v_old)
|
||||
.expect("v_old");
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.w, &mut self.w_old)
|
||||
.expect("w_old");
|
||||
self.upload_tables(t_old);
|
||||
let prm: E3Params = self.params(dt);
|
||||
let ptrs: E3Ptrs = self.ptrs();
|
||||
let cptrs = self.cut.as_ref().expect("cut").ptrs();
|
||||
let counts = [
|
||||
(g.nx + 1) * g.ny * g.nz,
|
||||
g.nx * (g.ny + 1) * g.nz,
|
||||
g.nx * g.ny * (g.nz + 1),
|
||||
];
|
||||
for c in 0..3i32 {
|
||||
unsafe {
|
||||
rt.stream
|
||||
.launch_builder(&k.predict)
|
||||
.arg(&prm)
|
||||
.arg(&ptrs)
|
||||
.arg(&cptrs)
|
||||
.arg(&c)
|
||||
.launch(cfg(counts[c as usize]))
|
||||
.expect("e3_cut_predict");
|
||||
}
|
||||
}
|
||||
self.launch_sides(prm, &ptrs, 0);
|
||||
self.upload_tables(t_new);
|
||||
self.launch_sides(prm, &ptrs, 1);
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.u, &mut self.u_star)
|
||||
.expect("u*");
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.v, &mut self.v_star)
|
||||
.expect("v*");
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.w, &mut self.w_star)
|
||||
.expect("w*");
|
||||
rt.stream.synchronize().expect("sync");
|
||||
let t_pred = t0.elapsed();
|
||||
if self.cg.is_none() || self.cg_dt != dt {
|
||||
let problem = self.solver.poisson_operator(g, dt);
|
||||
let params = MultigridParameters {
|
||||
precision: self.solver.params.poisson_precision,
|
||||
smoother: self.solver.params.poisson_smoother,
|
||||
..MultigridParameters::default()
|
||||
};
|
||||
self.cg = Some(DeviceCg::new(&problem, ¶ms));
|
||||
self.cg_dt = dt;
|
||||
}
|
||||
let anchor = self.solver.anchor_cell(g);
|
||||
let mut total = 0;
|
||||
let mut final_residual = f64::INFINITY;
|
||||
let mut cg_iterations = 0;
|
||||
let mut t_poisson = std::time::Duration::ZERO;
|
||||
let mut t_apply = std::time::Duration::ZERO;
|
||||
let one = 1i32;
|
||||
let zero = 0i32;
|
||||
for corrector in 0..self.solver.params.corrector_steps.max(1) {
|
||||
let tp = Instant::now();
|
||||
unsafe {
|
||||
rt.stream
|
||||
.launch_builder(&k.divergence)
|
||||
.arg(&prm)
|
||||
.arg(&ptrs)
|
||||
.arg(&cptrs)
|
||||
.arg(&one)
|
||||
.launch(cfg(g.cells()))
|
||||
.expect("e3_cut_divergence");
|
||||
rt.stream
|
||||
.launch_builder(&k.fold)
|
||||
.arg(&prm)
|
||||
.arg(&ptrs)
|
||||
.arg(&cptrs)
|
||||
.arg(&one)
|
||||
.arg(&mut self.partial)
|
||||
.launch(cfg(g.cells()))
|
||||
.expect("e3_cut_fold");
|
||||
}
|
||||
let source_scale = self.reduce();
|
||||
let inner_stop = self.solver.inner_stop(g, source_scale);
|
||||
if corrector > 0 {
|
||||
rt.stream.memset_zeros(&mut self.p_prime).expect("p' = 0");
|
||||
}
|
||||
let sol = {
|
||||
let cg = self.cg.as_mut().expect("cg");
|
||||
cg.solve_device(&self.sp, &mut self.p_prime, inner_stop, anchor, 0)
|
||||
};
|
||||
cg_iterations += sol.iterations;
|
||||
t_poisson += tp.elapsed();
|
||||
let ta = Instant::now();
|
||||
for c in 0..3i32 {
|
||||
unsafe {
|
||||
rt.stream
|
||||
.launch_builder(&k.correct)
|
||||
.arg(&prm)
|
||||
.arg(&ptrs)
|
||||
.arg(&cptrs)
|
||||
.arg(&c)
|
||||
.launch(cfg(counts[c as usize]))
|
||||
.expect("e3_cut_correct");
|
||||
}
|
||||
}
|
||||
if prm.periodic_z != 0 {
|
||||
self.launch_sides(prm, &ptrs, 0);
|
||||
}
|
||||
unsafe {
|
||||
rt.stream
|
||||
.launch_builder(&k.add_p)
|
||||
.arg(&prm)
|
||||
.arg(&ptrs)
|
||||
.arg(&cptrs)
|
||||
.launch(cfg(g.cells()))
|
||||
.expect("e3_cut_add_p");
|
||||
rt.stream
|
||||
.launch_builder(&k.divergence)
|
||||
.arg(&prm)
|
||||
.arg(&ptrs)
|
||||
.arg(&cptrs)
|
||||
.arg(&zero)
|
||||
.launch(cfg(g.cells()))
|
||||
.expect("e3_cut_divergence");
|
||||
rt.stream
|
||||
.launch_builder(&k.fold)
|
||||
.arg(&prm)
|
||||
.arg(&ptrs)
|
||||
.arg(&cptrs)
|
||||
.arg(&zero)
|
||||
.arg(&mut self.partial)
|
||||
.launch(cfg(g.cells()))
|
||||
.expect("e3_cut_fold");
|
||||
}
|
||||
let imbalance = self.reduce();
|
||||
let reference_flux = self.solver.reference_flux(g);
|
||||
let mass_residual = if reference_flux > 0.0 {
|
||||
imbalance / reference_flux
|
||||
} else {
|
||||
imbalance
|
||||
};
|
||||
final_residual = mass_residual;
|
||||
total += 1;
|
||||
t_apply += ta.elapsed();
|
||||
if mass_residual < self.solver.params.tolerance {
|
||||
break;
|
||||
}
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.u, &mut self.u_star)
|
||||
.expect("u*");
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.v, &mut self.v_star)
|
||||
.expect("v*");
|
||||
rt.stream
|
||||
.memcpy_dtod(&self.w, &mut self.w_star)
|
||||
.expect("w*");
|
||||
}
|
||||
self.solver.set_time(t_new);
|
||||
if let Some(tm) = self.timers.as_mut() {
|
||||
tm.predictor_ns += t_pred.as_nanos() as u64;
|
||||
tm.poisson_ns += t_poisson.as_nanos() as u64;
|
||||
tm.apply_ns += t_apply.as_nanos() as u64;
|
||||
tm.steps += 1;
|
||||
tm.cg_iterations += cg_iterations as u64;
|
||||
}
|
||||
StepResult {
|
||||
fresh_cells: 0,
|
||||
converged: final_residual < self.solver.params.tolerance,
|
||||
corrector_steps_performed: total,
|
||||
final_residual,
|
||||
poisson_iterations: cg_iterations,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user