25#include <Kokkos_Core.hpp>
28#include "peclet/core/common/types.hpp"
29#include "peclet/core/common/view.hpp"
30#include "peclet/core/decomp/block_decomposer.hpp"
31#include "peclet/core/halo/grid_halo.hpp"
32#include "peclet/core/halo/grid_halo_topology.hpp"
37using peclet::core::Index;
38using peclet::core::IVec;
39using peclet::core::decomp::BlockDecomposer;
40using peclet::core::halo::GridHalo;
41using peclet::core::halo::GridHaloTopology;
48constexpr int kDim = 3;
55 std::fprintf(stderr, "CHECK failed: %s\n at %s:%d\n", #cond, __FILE__, __LINE__); \
60enum class Scene { UniformSphere, LeVequeWalls };
63void seedScene(Scene sc, WyAdvector& a,
Block b,
double h,
long s,
double dt,
double T) {
64 if (sc == Scene::UniformSphere) {
88void runScene(
const SceneSpec& sp,
int rank,
int size) {
89 const IVec<kDim>
gs =
sp.gs;
92 BlockDecomposer<kDim> dec(
static_cast<std::size_t
>(size), gs);
93 GridHaloTopology<kDim> topo;
94 topo.buildTopology(dec, rank,
G,
sp.periodic, MPI_COMM_WORLD);
95 GridHalo<double> halo;
97 const auto& idx = topo.indexer();
98 const auto inner = idx.sizeInner(), ogh = idx.originInclGhost();
99 const I3 origin{
static_cast<int>(ogh[0]) +
G,
static_cast<int>(ogh[1]) +
G,
100 static_cast<int>(ogh[2]) +
G};
102 const I3 gsi{
static_cast<int>(
gs[0]),
static_cast<int>(gs[1]),
static_cast<int>(
gs[2])};
105 adv.init(
static_cast<int>(inner[0]),
static_cast<int>(
inner[1]),
static_cast<int>(inner[2]),
sp.h,
108 const std::array<bool, 3> per{
sp.periodic[0],
sp.periodic[1],
sp.periodic[2]};
109 adv.exchange = [&halo, blk, gsi, per](
SField f) {
113 adv.globalMax = [](
double v) {
115 MPI_Allreduce(&v, &r, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
119 seedScene(
sp.scene, adv, blk,
sp.h, -1,
sp.dt,
sp.T);
121 double v0Loc = adv.diagnostics().sumC, v0 = 0.0;
122 MPI_Allreduce(&v0Loc, &v0, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
123 for (
long s = 0;
s <
sp.steps; ++
s) {
124 seedScene(
sp.scene, adv, blk,
sp.h, s,
sp.dt,
sp.T);
125 adv.advect(
sp.dt, s);
127 const auto dLoc = adv.diagnostics();
128 double v1Loc = dLoc.sumC, v1 = 0.0;
129 MPI_Allreduce(&v1Loc, &v1, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
133 ref.init(
static_cast<int>(gs[0]),
static_cast<int>(gs[1]),
static_cast<int>(gs[2]),
sp.h,
G);
135 const I3 eRef =
ref.extent();
136 ref.exchange = [eRef, rblk, gsi, per](
SField f) {
140 seedScene(
sp.scene, ref, rblk,
sp.h, -1,
sp.dt,
sp.T);
142 for (
long s = 0;
s <
sp.steps; ++
s) {
143 seedScene(
sp.scene, ref, rblk,
sp.h, s,
sp.dt,
sp.T);
144 ref.advect(
sp.dt, s);
148 auto hLoc = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), adv.colour());
149 auto hRef = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),
ref.colour());
150 long diff = 0, ghostAdjacent = 0;
152 for (
int z = 0; z < static_cast<int>(inner[2]); ++
z)
153 for (
int y = 0; y < static_cast<int>(inner[1]); ++
y)
154 for (
int x = 0; x < static_cast<int>(inner[0]); ++
x) {
155 const double a = hLoc(
L3(x +
G, y +
G, z +
G, adv.extent()));
156 const double b = hRef(
L3(x + origin.x +
G, y + origin.y +
G, z + origin.z +
G, eRef));
157 if (std::memcmp(&a, &b,
sizeof(
double)) != 0) {
159 worst = std::fmax(worst, std::fabs(a - b));
160 const bool edge =
x == 0 ||
y == 0 ||
z == 0 ||
x ==
static_cast<int>(
inner[0]) - 1 ||
161 y ==
static_cast<int>(inner[1]) - 1 ||
162 z ==
static_cast<int>(
inner[2]) - 1;
167 long diffAll = 0, edgeAll = 0;
168 MPI_Allreduce(&diff, &diffAll, 1, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
169 MPI_Allreduce(&ghostAdjacent, &edgeAll, 1, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
170 double worstAll = 0.0;
171 MPI_Allreduce(&worst, &worstAll, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
174 std::printf(
" [%s] %dx%dx%d, %ld steps, np=%d, block %dx%dx%d:\n",
sp.name,
175 static_cast<int>(gs[0]),
static_cast<int>(gs[1]),
static_cast<int>(gs[2]),
sp.steps,
176 size,
static_cast<int>(inner[0]),
static_cast<int>(inner[1]),
177 static_cast<int>(inner[2]));
179 " bitwise diffs vs whole-grid run: %ld (of which ghost-adjacent %ld)"
181 diffAll, edgeAll, worstAll);
182 std::printf(
" global volume drift %.3e C[%.3e, %.6f] wisps(rank0) %ld\n",
183 std::fabs(v1 - v0) / v0, dLoc.minC, dLoc.maxC, dLoc.wisps);
186 CHECK(std::fabs(v1 - v0) / v0 < 1e-13);
191int main(
int argc,
char** argv) {
192 MPI_Init(&argc, &argv);
193 Kokkos::initialize(argc, argv);
195 int rank = 0, size = 1;
196 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
197 MPI_Comm_size(MPI_COMM_WORLD, &size);
199 std::printf(
"VoF rung V1 (WO-E) - distributed Weymouth-Yue, backend: %s, np = %d\n",
200 peclet::flow::SExec::name(), size);
203 runScene(SceneSpec{Scene::UniformSphere,
204 IVec<kDim>{32, 24, 20},
212 "periodic / uniform translation"},
217 runScene(SceneSpec{Scene::LeVequeWalls,
218 IVec<kDim>{24, 24, 24},
223 {
false,
false,
false},
224 "walls / LeVeque deformation"},
228 runScene(SceneSpec{Scene::LeVequeWalls,
229 IVec<kDim>{24, 24, 24},
235 "mixed periodic/wall / LeVeque"},
239 MPI_Allreduce(&
failures, &total, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
242 std::printf(
"%s (%d failure%s)\n",
failures ?
"FAILED" :
"PASSED",
failures,
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::View< double *, SMem > SField
void fillLeVeque(WyAdvector &a, Block b, double h, double phase)
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...
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 ...
Block blockOf(const WyAdvector &a, I3 origin)
Where this block sits in the global grid: o is the global index of inner cell (0,0,...
static constexpr int kDim