42#include <Kokkos_Core.hpp>
46#include "peclet/core/common/types.hpp"
47#include "peclet/core/decomp/block_decomposer.hpp"
49using peclet::core::IVec;
50using peclet::core::decomp::BlockDecomposer;
54static constexpr int NX = 24,
NY = 24,
NZ = 48;
57static constexpr double RB = 4.5,
GRAV = 2.0e-3;
58static const double CX[2] = {
NX / 2.0 + 0.13,
NX / 2.0 + 0.13};
59static const double CY[2] = {
NY / 2.0 - 0.21,
NY / 2.0 - 0.21};
60static const double CZ[2] = {14.0 + 0.31, 30.0 + 0.31};
63static double bubbleAt(
int b,
int x,
int y,
int z) {
66 for (
int j = 0; j < NS; ++j)
67 for (
int i = 0; i < NS; ++i) {
68 const double px = x + (i + 0.5) / NS -
CX[b], py = y + (j + 0.5) / NS -
CY[b];
69 const double r2 =
RB *
RB - px * px - py * py;
72 const double h = std::sqrt(r2);
73 const double lo = std::fmax(
CZ[b] - h, (
double)z), hi = std::fmin(
CZ[b] + h, (
double)z + 1);
77 return acc / (NS * NS);
88 const bool blocks = (
cfg == 1),
pc = (
cfg == 2);
99 std::vector<double> c((std::size_t)
lnx *
lny *
lnz, 0.0), t(c.size(), 0.0);
100 for (
int z = 0; z <
lnz; ++z)
101 for (
int y = 0; y <
lny; ++y)
102 for (
int x = 0; x <
lnx; ++x) {
104 std::fmax(
bubbleAt(0, x + ox, y + oy, z + oz),
bubbleAt(1, x + ox, y + oy, z + oz));
105 const std::size_t i = (std::size_t)x + (std::size_t)y *
lnx + (std::size_t)z *
lnx *
lny;
107 t[i] = 0.5 + 0.25 * std::sin(0.3 * (x + ox)) * std::cos(0.2 * (z + oz));
124 std::vector<std::array<int, 6>>
boxes;
125 for (
int b = 0; b < 2; ++b) {
126 std::array<int, 6> q;
127 const double c3[3] = {
CX[b],
CY[b],
CZ[b]};
128 for (
int d = 0; d < 3; ++d) {
129 q[d] = (int)std::floor(c3[d] -
RB) - 1;
130 q[3 + d] = (int)std::ceil(c3[d] +
RB) + 1;
145static std::vector<double>
gatherGlobal(
const std::vector<double>&
local,
int ox,
int oy,
int oz,
146 int lnx,
int lny,
int lnz,
int rank,
int size) {
147 std::vector<double>
global;
150 for (
int r = 0; r < size; ++r) {
154 for (
int z = 0; z <
lnz; ++z)
155 for (
int y = 0; y <
lny; ++y)
156 std::memcpy(&
global[(std::size_t)ox + (std::size_t)(y + oy) *
NX +
157 (std::size_t)(z + oz) *
NX *
NY],
159 (std::size_t)
lnx *
sizeof(
double));
165 }
else if (rank == 0) {
170 for (
int z = 0; z <
meta[5]; ++z)
171 for (
int y = 0; y <
meta[4]; ++y)
172 std::memcpy(&
global[(std::size_t)
meta[0] + (std::size_t)(y +
meta[1]) *
NX +
173 (std::size_t)(z +
meta[2]) *
NX *
NY],
175 (std::size_t)
meta[3] *
sizeof(
double));
183static double maxDiff(
const std::vector<double>& a,
const std::vector<double>& b) {
185 for (std::size_t i = 0; i < b.size(); ++i) {
186 const double d = std::fabs(a[i] - b[i]);
192static long countBitDiff(
const std::vector<double>& a,
const std::vector<double>& b) {
194 for (std::size_t i = 0; i < b.size(); ++i)
202 Kokkos::initialize(
argc, argv);
205 int rank = 0, size = 1;
208 const int STEPS = (
argc > 1) ? std::atoi(argv[1]) : 12;
214 auto D1 = peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(size),
NX,
NY,
NZ);
215 std::vector<peclet::core::Real> w(
GCELLS, 1.0);
216 for (
int z = 0; z <
NZ; ++z)
217 for (
int y = 0; y <
NY; ++y)
218 for (
int x = 0; x <
NX; ++x)
220 w[(std::size_t)x + (std::size_t)y *
NX + (std::size_t)z *
NX *
NY] = 24.0;
223 auto blk =
D1.block(rank);
224 const int ox = (int)blk.origin[0], oy = (
int)blk.origin[1], oz = (int)blk.origin[2];
225 const int lnx = (int)blk.size[0],
lny = (
int)blk.size[1],
lnz = (int)blk.size[2];
229 for (
int r = 0; r < size; ++r) {
230 const auto a =
D1.block(r), b =
D2.block(r);
231 for (
int d = 0; d < 3; ++d)
232 if (a.origin[d] != b.origin[d] || a.size[d] != b.size[d])
237 "VOF REDISTRIBUTE MPI np=%d grid %dx%dx%d block %dx%dx%d partition moves: %s\n", size,
240 const auto a =
D1.block(r), b =
D2.block(r);
241 std::printf(
" rank %d: %ldx%ldx%ld @ (%ld,%ld,%ld) -> %ldx%ldx%ld @ (%ld,%ld,%ld)\n",
242 r, (
long)a.size[0], (
long)a.size[1], (
long)a.size[2], (
long)a.origin[0],
243 (
long)a.origin[1], (
long)a.origin[2], (
long)b.size[0], (
long)b.size[1],
244 (
long)b.size[2], (
long)b.origin[0], (
long)b.origin[1], (
long)b.origin[2]);
247 if (size > 1 && !
moved) {
249 std::printf(
" FAIL - the weighted ORB coincides with the default one; nothing is gated\n");
253 static const char*
CFGNAME[3] = {
"VoF + closures + scalar",
254 "VoF + closures + scalar + the BLOCK container",
255 "VoF + scalar + PHASE CHANGE (consistent energy)"};
257 const bool blocks = (
cfg == 1);
259 std::printf(
" --- configuration: %s\n",
CFGNAME[
cfg]);
263 for (
int k = 0; k <
MOVE_AT; ++k)
267 const char* fn[6] = {
"C",
"u",
"v",
"w",
"P",
"T"};
268 std::vector<double>
pre[6],
post[6];
269 auto snap = [&](std::vector<double>* out,
int px,
int py,
int pz,
int qx,
int qy,
int qz) {
271 for (
int c = 0; c < 3; ++c)
277 std::vector<double>
volPre;
280 std::vector<double> l(st.size(), 0.0);
281 volPre.assign(st.size(), 0.0);
282 for (std::size_t i = 0; i < st.size(); ++i)
287 sd.rebalanceByWeights(w);
289 const auto nb =
D2.block(rank);
290 const int nox = (int)nb.origin[0],
noy = (
int)nb.origin[1],
noz = (int)nb.origin[2];
291 const int nlx = (int)nb.size[0],
nly = (
int)nb.size[1],
nlz = (int)nb.size[2];
294 std::printf(
" R1 across the move (must be bitwise):");
295 for (
int i = 0; i < 6; ++i) {
305 std::vector<double> l(st.size(), 0.0),
volPost(st.size(), 0.0);
306 for (std::size_t i = 0; i < st.size(); ++i)
311 for (std::size_t i = 0; i <
volPost.size(); ++i)
313 std::printf(
" R3 marker volumes across the move: %zu markers, max|dV| = %.3e\n",
315 if (!(dm <= 1e-12 * std::fmax(1.0,
volPre.empty() ? 1.0 :
volPre[0])))
323 std::vector<double> g[6];
334 for (
int k = 0; k <
STEPS; ++k)
336 std::vector<double> gc[6];
338 for (
int c = 0; c < 3; ++c)
346 for (
int k = 0; k <
STEPS; ++k)
348 std::vector<double> r[6] = {ref.getVof(), ref.getVelocity(0), ref.getVelocity(1),
349 ref.getVelocity(2), ref.getPressure(), ref.getField(
"T")};
351 " R2 vs the single-rank reference after %d steps"
352 " [rebalanced | never-rebalanced control]:\n ",
354 for (
int i = 0; i < 6; ++i) {
359 const double bound = std::fmax(1e-13, 4.0 *
dc);
360 std::printf(
" d%s %.2e|%.2e", fn[i], d,
dc);
376 ?
"OK (np=%d): a VoF (+block) run survives a MOVING rebalance bit-exactly\n"
377 :
"FAILED (np=%d)\n",
void enableVofBlocksFromField(const std::vector< std::array< int, 6 > > &boxes)
void setDomainBc(int face, int type, double vx, double vy, double vz)
std::vector< double > getField(const std::string &name)
void addScalar(const std::string &name, double D, int scheme, int iters, bool cutcell=false)
std::vector< double > getVof()
void setPropertyModel(const std::string &target, ClosureKind kind, const std::string &in0, const std::string &in1, const std::vector< double > ¶ms)
void setSurfaceTension(double sigma)
void setPressureChebyshev(bool on, int maxit, double rtol)
double capillaryDt()
The Brackbill capillary limit in the CALLER's time unit.
void setVof(const std::vector< double > &c)
void setPhaseChangeThermal(const std::string &tname, double Tsat, double kg, double kl, double Rint)
P1: compute mdot each step from the registered scalar tname by the one-sided pure-cell weighted least...
void setPressureLevels(int levels)
void setPressureGeometry(const std::vector< double > &sdfInner)
void setField(const std::string &name, const std::vector< double > &v)
std::vector< double > getVelocity(int c)
void enablePhaseChange(double rhoG, double rhoL, double hlv)
Turn on phase change.
void setMu(double m)
Dynamic viscosity, in the caller's units.
void setPhaseChangeEnergy(double rcpGas, double rcpLiquid)
Turn on the CONSISTENT energy transport (VOF_PLAN §9 item 6) for the scalar set_phase_change_thermal ...
void setRho(double r)
Fluid density, in the caller's units.
std::vector< vof::VofBlockStats > vofBlockStats() const
std::vector< double > getPressure()
flow — host-facing Kokkos IBM Navier-Stokes solver (drop-in flow-style API).
static constexpr int STEPS
static constexpr double GRAV
static constexpr double MU_G
static constexpr double SIGMA
static double maxDiff(const std::vector< double > &a, const std::vector< double > &b)
static std::vector< double > gatherGlobal(const std::vector< double > &local, int ox, int oy, int oz, int lnx, int lny, int lnz, int rank, int size)
static const double CY[2]
static constexpr double RHO_G
static constexpr double RB
static const double CZ[2]
static void configure(IbmSolver &s, int ox, int oy, int oz, int lnx, int lny, int lnz, int cfg)
static double bubbleAt(int b, int x, int y, int z)
static constexpr double RHO_L
static constexpr double MU_L
static constexpr std::size_t GCELLS
static const double CX[2]
static long countBitDiff(const std::vector< double > &a, const std::vector< double > &b)