14#ifndef PECLET_FLOW_TESTS_VOF_ADVECT_SCENES_HPP
15#define PECLET_FLOW_TESTS_VOF_ADVECT_SCENES_HPP
18#include <Kokkos_Core.hpp>
40 return Block{a.inner(), a.extent(), a.ghost(), origin};
48 const long st[3] = {1, e.x,
static_cast<long>(e.x) * e.y};
49 const int dims[3] = {e.x, e.y, e.z};
50 const bool per[3] = {px, py, pz};
51 for (
int a = 0; a < 3; ++a) {
54 const int b = (a + 1) % 3, c = (a + 2) % 3;
55 const long sa = st[a], sb = st[b], sc = st[c];
56 const int N = dims[a] - 2 * g;
58 "vofscene::periodicFill",
60 KOKKOS_LAMBDA(
int p0,
int p1) {
61 const long base =
static_cast<long>(p0) * sb +
static_cast<long>(p1) * sc;
62 for (
int gl = 0; gl < g; ++gl) {
63 f(base +
static_cast<long>(gl) * sa) = f(base +
static_cast<long>(gl +
N) * sa);
64 f(base +
static_cast<long>(g +
N + gl) * sa) = f(base +
static_cast<long>(g + gl) * sa);
89 const I3 e = b.e, o = b.o;
91 const bool per[3] = {px, py, pz};
92 const int gsz[3] = {gs.x, gs.y, gs.z};
93 const bool p0 = per[0], p1 = per[1], p2 = per[2];
94 const int q0 = gsz[0], q1 = gsz[1], q2 = gsz[2];
97 KOKKOS_LAMBDA(
int x,
int y,
int z) {
98 const int gx = x - g + o.x, gy = y - g + o.y, gz = z - g + o.z;
99 const int cx = p0 ? gx : (gx < 0 ? 0 : (gx >= q0 ? q0 - 1 : gx));
100 const int cy = p1 ? gy : (gy < 0 ? 0 : (gy >= q1 ? q1 - 1 : gy));
101 const int cz = p2 ? gz : (gz < 0 ? 0 : (gz >= q2 ? q2 - 1 : gz));
102 if (cx != gx || cy != gy || cz != gz)
103 f(L3(x, y, z, e)) = f(L3(cx - o.x + g, cy - o.y + g, cz - o.z + g, e));
116 Kokkos::parallel_for(
117 "vofscene::forEachExtended",
119 KOKKOS_LAMBDA(
int x,
int y,
int z) {
120 fn(L3(x, y, z, e), x - g + o.x, y - g + o.y, z - g + o.z);
127inline void initSphere(SField c,
Block b,
double h,
double cx,
double cy,
double cz,
double r,
130 b, KOKKOS_LAMBDA(
long i,
int gx,
int gy,
int gz) {
132 peclet::flow::vof::sphereCellFraction(cx, cy, cz, r, gx * h, gy * h, gz * h, h, levels);
137inline void initSlab(SField c,
Block b,
double h,
int axis,
double lo,
double hi) {
139 b, KOKKOS_LAMBDA(
long i,
int gx,
int gy,
int gz) {
140 const int gi[3] = {gx, gy, gz};
141 const double a = gi[axis] * h, bb = a + h;
142 const double cover = Kokkos::fmax(0.0, Kokkos::fmin(bb, hi) - Kokkos::fmax(a, lo));
151inline void initZalesak(SField c,
Block b,
double h,
double cx,
double cy,
double r,
double sw,
152 double stop,
int nsub = 64) {
153 const double w = 1.0 / nsub;
155 b, KOKKOS_LAMBDA(
long i,
int gx,
int gy,
int) {
156 const double x0 = gx * h, y0 = gy * h;
158 for (
int q = 0; q < nsub; ++q) {
159 const double y = y0 + (q + 0.5) * w * h;
160 for (
int p = 0; p < nsub; ++p) {
161 const double x = x0 + (p + 0.5) * w * h;
162 const double dx = x - cx, dy = y - cy;
163 const bool inCircle = dx * dx + dy * dy < r * r;
164 const bool inSlot = Kokkos::fabs(dx) < sw && y < stop;
165 if (inCircle && !inSlot)
169 c(i) =
static_cast<double>(in) / (
static_cast<double>(nsub) * nsub);
177 SField u = a.faceU(), v = a.faceV(), w = a.faceW();
179 b, KOKKOS_LAMBDA(
long i,
int,
int,
int) {
189 SField u = a.faceU(), v = a.faceV(), w = a.faceW();
191 b, KOKKOS_LAMBDA(
long i,
int gx,
int gy,
int) {
192 u(i) = -omega * ((gy + 0.5) * h - cy);
193 v(i) = omega * ((gx + 1.0) * h - cx);
207KOKKOS_INLINE_FUNCTION
double lvSin2(
double t) {
208 const double s = Kokkos::sin(3.14159265358979323846 * t);
212KOKKOS_INLINE_FUNCTION
double lvAy(
double x,
double y,
double z,
double phase) {
213 const double PI = 3.14159265358979323846;
214 return -(
lvSin2(x) *
lvSin2(z) / PI) * Kokkos::sin(2.0 * PI * y) * phase;
217KOKKOS_INLINE_FUNCTION
double lvAz(
double x,
double y,
double z,
double phase) {
218 const double PI = 3.14159265358979323846;
219 return (
lvSin2(x) *
lvSin2(y) / PI) * Kokkos::sin(2.0 * PI * z) * phase;
223 SField u = a.faceU(), v = a.faceV(), w = a.faceW();
224 const double invh = 1.0 / h;
226 b, KOKKOS_LAMBDA(
long i,
int gx,
int gy,
int gz) {
227 const double xn = gx * h, yn = gy * h, zn = gz * h;
228 const double yc = (gy + 0.5) * h, zc = (gz + 0.5) * h;
229 const double xp = (gx + 1) * h, yp = (gy + 1) * h, zp = (gz + 1) * h;
231 u(i) = (
lvAz(xp, yp, zc, phase) -
lvAz(xp, yn, zc, phase)) * invh -
232 (
lvAy(xp, yc, zp, phase) -
lvAy(xp, yc, zn, phase)) * invh;
234 v(i) = -(
lvAz(xp, yp, zc, phase) -
lvAz(xn, yp, zc, phase)) * invh;
236 w(i) = (
lvAy(xp, yc, zp, phase) -
lvAy(xn, yc, zp, phase)) * invh;
245 Kokkos::parallel_reduce(
248 KOKKOS_LAMBDA(
int x,
int y,
int z,
double& acc) {
249 const long i = L3(x, y, z, e);
250 acc += Kokkos::fabs(a(i) - b(i));
260 Kokkos::parallel_reduce(
263 KOKKOS_LAMBDA(
int x,
int y,
int z,
double& acc) {
264 const long i = L3(x, y, z, e);
265 acc = Kokkos::fmax(acc, Kokkos::fabs(a(i) - b(i)));
267 Kokkos::Max<double>(s));
272inline SField
copyOf(SField src,
const char* name) {
273 SField dst(name, src.extent(0));
274 Kokkos::deep_copy(dst, src);
flow — VoF rung V1: Weymouth & Yue (2010) directionally-split, exactly volume-conserving geometric ad...
Weymouth-Yue split advection of a colour field on an extended (inner + ghost) block.
long L3(int x, int y, int z, I3 e)
Kokkos::DefaultExecutionSpace SExec
Kokkos::View< double *, SMem > SField
double lInfDiff(SField a, SField b, I3 e, I3 n, int g)
max |a - b| over the inner region.
void fillLeVeque(WyAdvector &a, Block b, double h, double phase)
double l1Diff(SField a, SField b, I3 e, I3 n, int g)
sum |a - b| over the inner region (cell-fraction units).
void forEachExtended(Block b, F fn)
Visit every cell of the extended block with (local linear index, global cell index).
SField copyOf(SField src, const char *name)
void initZalesak(SField c, Block b, double h, double cx, double cy, double r, double sw, double stop, int nsub=64)
Zalesak's slotted disk in the (x,y) plane, uniform in z.
void periodicFill(SField f, I3 e, int g, bool px, bool py, bool pz)
Periodic wrap of a single-block extended field (serial reference path; the MPI path uses core's GridH...
void fillUniform(WyAdvector &a, Block b, double ux, double uy, double uz)
Uniform translation. Discrete divergence is EXACTLY zero (identical values differenced).
void initSphere(SField c, Block b, double h, double cx, double cy, double cz, double r, int levels=4)
Sphere of fluid (C = 1 inside), exact to ~5e-7 relative volume at R/h = 16 via the octree helper in p...
double lvAz(double x, double y, double z, double phase)
A_z of the LeVeque vector potential (lives on z-edges: node x, node y, centre z).
void clampFill(SField f, Block b, I3 gs, bool px, bool py, bool pz)
Zero-gradient (Neumann) fill of the ghost cells that lie OUTSIDE the global domain on a non-periodic ...
double lvSin2(double t)
The LeVeque 3D deformation field u = 2 sin^2(pi x) sin(2 pi y) sin(2 pi z) cos(pi t / T) v = - sin(2 ...
Block blockOf(const WyAdvector &a, I3 origin)
void fillRotation(WyAdvector &a, Block b, double h, double cx, double cy, double omega)
Solid-body rotation about (cx,cy) in the (x,y) plane, w = 0.
double lvAy(double x, double y, double z, double phase)
A_y of the LeVeque vector potential (lives on y-edges: node x, centre y, node z).
void initSlab(SField c, Block b, double h, int axis, double lo, double hi)
Slab zlo < x < zhi along axis axis, exact fractions (axis-aligned planes).
flow — thin shim: the container-free VoF PLIC geometric toolbox (rung V0) now live in core.
Where this block sits in the global grid: o is the global index of inner cell (0,0,...
I3 e
extended (inner + 2g) counts
I3 o
global index of the first inner cell
static constexpr double F