39#ifndef PECLET_FLOW_VOF_BLOCK_EXCHANGE_HPP
40#define PECLET_FLOW_VOF_BLOCK_EXCHANGE_HPP
46#include <Kokkos_Core.hpp>
91 return a.q.x < b.q.x + b.n.x && b.q.x < a.q.x + a.n.x && a.q.y < b.q.y + b.n.y &&
92 b.q.y < a.q.y + a.n.y && a.q.z < b.q.z + b.n.z && b.q.z < a.q.z + a.n.z;
102 const std::vector<VofBox>&
rankBox, std::vector<VofPiece>& out,
106 const int nx =
vofAxisRuns(box.lo[0], box.hi[0], gs.x, per[0],
rx, outside);
107 const int ny =
vofAxisRuns(box.lo[1], box.hi[1], gs.y, per[1],
ry, outside);
108 const int nz =
vofAxisRuns(box.lo[2], box.hi[2], gs.z, per[2],
rz, outside);
109 const int gsa[3] = {gs.x, gs.y, gs.z};
110 for (
int iz = 0;
iz < nz; ++
iz)
111 for (
int iy = 0;
iy < ny; ++
iy)
112 for (
int ix = 0;
ix < nx; ++
ix) {
120 const int base[3] = {
rx[
ix].loc0,
ry[
iy].loc0,
rz[
iz].loc0};
121 for (std::size_t r = 0; r <
rankBox.size(); ++r) {
124 for (
int d = 0; d < 3; ++d) {
128 own.lo[d] = -outside;
130 own.hi[d] =
gsa[d] + outside;
136 p.rank =
static_cast<int>(r);
138 for (
int d = 0; d < 3; ++d)
139 p.loc[d] = base[d] + (o.lo[d] - s.lo[d]);
158 void init(
I3 gs, std::array<bool, 3> per, std::vector<VofBox>
rankBox,
int rank) {
163 size_ =
static_cast<int>(rankBox_.size());
165 throw std::runtime_error(
"peclet::flow::vof::VofBlockExchange: rank out of range");
173 if (
rankBox.size() != rankBox_.size())
174 throw std::runtime_error(
175 "peclet::flow::vof::VofBlockExchange::setRankBoxes: rank count changed");
188#ifdef PECLET_FLOW_MPI
239 std::vector<Recv>
recvs;
240 std::vector<SField>
sendD(blocks.size());
241 std::vector<HostView>
sendH(blocks.size());
242 std::vector<VofMoveJob>
moves;
243#ifdef PECLET_FLOW_MPI
244 std::vector<MPI_Request>
reqs;
246 for (std::size_t bi = 0; bi < blocks.size(); ++bi) {
250 const bool master = (b.master == rank_);
252 for (
int c = 0; c < nc; ++c)
254 std::map<int, long>
counts;
255 for (
const auto& p : pieces_)
256 counts[p.rank] += p.cells();
258 for (
const auto& kv :
counts) {
259 if (kv.first == rank_)
265 r.dbuf =
buffer(nc * kv.second);
266 r.hbuf = Kokkos::create_mirror_view(r.dbuf);
267 recvs.push_back(std::move(r));
272 for (
const auto& p : pieces_)
273 if (p.rank == rank_) {
282 for (
const auto& p : pieces_)
286 sendH[bi] = Kokkos::create_mirror_view(
sendD[bi]);
292#ifdef PECLET_FLOW_MPI
295 for (
auto& r :
recvs) {
298 tagOf(blocks[r.bi].id, 0),
comm_, &
reqs.back());
299 gBytes_ +=
static_cast<long>(r.hbuf.extent(0)) * 8;
302 for (std::size_t bi = 0; bi < blocks.size(); ++bi) {
303 if (
sendH[bi].extent(0) == 0)
307 blocks[bi].master, tagOf(blocks[bi].
id, 0),
comm_, &
reqs.back());
308 gBytes_ +=
static_cast<long>(
sendH[bi].extent(0)) * 8;
315 for (
auto& r :
recvs) {
317 Kokkos::deep_copy(r.dbuf, r.hbuf);
321 for (
const auto& p : pieces_)
322 if (p.rank == r.from)
350 std::vector<Recv>
recvs;
351 std::vector<SField>
sendD;
352 std::vector<HostView>
sendH;
355#ifdef PECLET_FLOW_MPI
356 std::vector<MPI_Request>
reqs;
358 for (std::size_t bi = 0; bi < blocks.size(); ++bi) {
361 const bool master = (b.master == rank_);
362 std::map<int, long>
counts;
363 for (
const auto& p : pieces_)
364 counts[p.rank] += p.cells();
366 for (
const auto& kv :
counts) {
367 if (kv.first == rank_) {
369 for (
const auto& p : pieces_)
376 for (
const auto& p : pieces_)
377 if (p.rank == kv.first)
380 HostView h = Kokkos::create_mirror_view(d);
381 Kokkos::deep_copy(h, d);
384 sendTo.push_back(kv.first);
387 }
else if (
counts.count(rank_)) {
392 r.hbuf = Kokkos::create_mirror_view(r.dbuf);
393 recvs.push_back(std::move(r));
399#ifdef PECLET_FLOW_MPI
402 for (
auto& r :
recvs) {
405 tagOf(blocks[r.bi].id, 1),
comm_, &
reqs.back());
406 sBytes_ +=
static_cast<long>(r.hbuf.extent(0)) * 8;
409 for (std::size_t k = 0; k <
sendH.size(); ++k) {
413 sBytes_ +=
static_cast<long>(
sendH[k].extent(0)) * 8;
420 for (
auto& r :
recvs) {
422 Kokkos::deep_copy(r.dbuf, r.hbuf);
425 for (
const auto& p : pieces_)
444 std::vector<Job>
jobs;
445 for (
auto& b : blocks) {
446 if (b.master != rank_)
449 for (
int c = 0; c < 3; ++c)
451 for (
int d = 0; d < 3; ++d) {
452 j.lo[d] = b.box.lo[d];
455 j.be = b.advector().extent();
461 for (
int d = 0; d < 3; ++d)
470 for (
int k = 0; k < T.nj; ++k) {
471 for (
int c = 0; c < 3; ++c)
472 T.f[k][c] =
jobs[j0 + k].f[c];
473 for (
int d = 0; d < 3; ++d) {
474 T.lo[k][d] =
jobs[j0 + k].lo[d];
475 T.n[k][d] =
jobs[j0 + k].n[d];
477 T.be[k] =
jobs[j0 + k].be;
481 }
while (j0 <
jobs.size());
491 const I3 e = patch_.
e, n = patch_.
n, o = patch_.
o;
492 const int g = patch_.
g;
493 SField d0 = loc[0],
d1 = T.nc > 1 ? loc[1] : loc[0],
d2 = T.nc > 2 ? loc[2] : loc[0];
494 if constexpr (std::is_same_v<typename SField::memory_space, Kokkos::HostSpace>) {
501 const int nn[3] = {n.x, n.y, n.z},
oo[3] = {o.x, o.y, o.z};
502 std::vector<std::uint32_t> mk((std::size_t)n.x + n.y + n.z, 0u);
503 std::uint32_t*
md[3] = {mk.data(), mk.data() + n.x, mk.data() + n.x + n.y};
504 for (
int d = 0; d < 3; ++d)
506 for (
int k = 0; k < T.nj; ++k) {
507 int v =
xd +
oo[d] - T.lo[k][d];
509 v = ((v % T.L[d]) + T.L[d]) % T.L[d];
510 if (v >= 0 && v < T.n[k][d])
511 md[d][
xd] |= (1u << k);
513 const std::uint32_t *mx =
md[0], *my =
md[1], *mz =
md[2];
515 "vof::block::gather_local_sum",
C3{0, 0, 0},
C3{n.x, n.y, n.z},
517 const int gp[3] = {x + o.x, y + o.y, z + o.z};
518 const long i =
L3(x + g, y + g, z + g, e);
519 double acc[3] = {0.0, 0.0, 0.0};
522 acc[1] = T.nc > 1 ?
d1(i) : 0.0;
523 acc[2] = T.nc > 2 ?
d2(i) : 0.0;
525 const std::uint32_t m = mx[x] & my[y] & mz[z];
526 for (
int k = 0; k < T.nj; ++k) {
527 if (!((m >> k) & 1u))
530 for (
int d = 0; d < 3; ++d) {
531 int v =
gp[d] - T.lo[k][d];
533 v = ((v % T.L[d]) + T.L[d]) % T.L[d];
536 const long q =
L3(l[0] + T.gh, l[1] + T.gh, l[2] + T.gh, T.be[k]);
537 for (
int c = 0; c < T.nc; ++c)
538 acc[c] += T.f[k][c][q];
549 Kokkos::parallel_for(
552 const int gp[3] = {x + o.x, y + o.y, z + o.z};
553 const long i =
L3(x + g, y + g, z + g, e);
554 double acc[3] = {0.0, 0.0, 0.0};
557 acc[1] = T.nc > 1 ?
d1(i) : 0.0;
558 acc[2] = T.nc > 2 ?
d2(i) : 0.0;
560 for (
int k = 0; k < T.nj; ++k) {
563 for (
int d = 0; d < 3 &&
in; ++d) {
564 int v =
gp[d] - T.lo[k][d];
566 v = ((v % T.L[d]) + T.L[d]) % T.L[d];
567 in = v >= 0 && v < T.n[k][d];
572 const long q =
L3(l[0] + T.gh, l[1] + T.gh, l[2] + T.gh, T.be[k]);
573 for (
int c = 0; c < T.nc; ++c)
574 acc[c] += T.f[k][c][q];
586 const I3 e = patch_.
e, n = patch_.
n;
587 const int g = patch_.
g;
588 for (
int c = 0; c < nc; ++c) {
590 Kokkos::parallel_for(
591 "vof::block::zero_patch",
593 KOKKOS_LAMBDA(
int x,
int y,
int z) { f(
L3(x + g, y + g, z + g, e)) = 0.0; });
598 const I3 e = patch_.
e, o = patch_.
o;
599 const int g = patch_.
g;
600 const int lo0 = p.g.lo[0],
lo1 = p.g.lo[1],
lo2 = p.g.lo[2];
601 const int n0 = p.g.n(0),
n1 = p.g.n(1),
n2 = p.g.n(2);
602 const long base = off;
603 SField s0 = loc[0], s1 = nc > 1 ? loc[1] : loc[0], s2 = nc > 2 ? loc[2] : loc[0];
604 Kokkos::parallel_for(
605 "vof::block::pack_patch",
608 const long i =
L3(
lo0 + x - o.x + g,
lo1 + y - o.y + g,
lo2 + z - o.z + g, e);
609 const long k = base + x +
static_cast<long>(y) *
n0 +
static_cast<long>(z) *
n0 *
n1;
610 buf(nc * k + 0) = s0(i);
612 buf(nc * k + 1) = s1(i);
614 buf(nc * k + 2) = s2(i);
616 off +=
static_cast<long>(
n0) *
n1 *
n2;
621 const I3 be = b.advector().extent();
622 const int lo0 = p.g.lo[0],
lo1 = p.g.lo[1],
lo2 = p.g.lo[2];
623 const int n0 = p.g.n(0),
n1 = p.g.n(1),
n2 = p.g.n(2);
625 const long base = off;
629 for (
int c = 0; c < nc; ++c) {
632 Kokkos::parallel_for(
633 "vof::block::unpack_block",
636 const long k = base + x +
static_cast<long>(y) *
n0 +
static_cast<long>(z) *
n0 *
n1;
637 d(
L3(
q0 + x,
q1 + y,
q2 + z, be)) =
buf(nc * k + cc);
640 off +=
static_cast<long>(
n0) *
n1 *
n2;
646 const I3 e = patch_.
e, o = patch_.
o, be = b.advector().extent();
647 const int g = patch_.
g;
648 const int lo0 = p.g.lo[0],
lo1 = p.g.lo[1],
lo2 = p.g.lo[2];
649 const int n0 = p.g.n(0),
n1 = p.g.n(1),
n2 = p.g.n(2);
651 for (
int c = 0; c < nc; ++c) {
654 throw std::runtime_error(
"vof::block: movePiece is patch->block only");
655 Kokkos::parallel_for(
656 "vof::block::move_local",
659 dst(
L3(
q0 + x,
q1 + y,
q2 + z, be)) =
660 src(
L3(
lo0 + x - o.x + g,
lo1 + y - o.y + g,
lo2 + z - o.z + g, e));
668 std::vector<VofMoveJob>& out) {
669 const I3 o = patch_.
o;
670 const int g = patch_.
g;
671 for (
int c = 0; c < nc; ++c) {
673 J.src = loc[c].data();
676 J.be = b.advector().extent();
677 J.s =
I3{p.g.lo[0] - o.x + g, p.g.lo[1] - o.y + g, p.g.lo[2] - o.z + g};
679 J.n =
I3{p.g.n(0), p.g.n(1), p.g.n(2)};
688 template <
class Exec = SExec>
693 T.nj =
static_cast<int>(std::min<std::size_t>(
kVofBlockBatch,
mv.size() - j0));
694 for (
int k = 0; k < T.nj; ++k)
695 T.job[k] =
mv[j0 + k];
697 for (
int k = 0; k < T.nj; ++k)
698 for (
int l = 0; l < k; ++l)
702 "vof::block::move_local", T.nj,
703 [&](
const int k) { return static_cast<long>(T.job[k].n.y) * T.job[k].n.z; },
704 [=](
const int k,
const long r) {
705 const VofMoveJob& J = T.job[k];
706 const int y = static_cast<int>(r % J.n.y), z = static_cast<int>(r / J.n.y);
707 const double* src = J.src + L3(J.s.x, J.s.y + y, J.s.z + z, J.e);
708 double* dst = J.dst + L3(J.q.x, J.q.y + y, J.q.z + z, J.be);
710 for (int x = 0; x < J.n.x; ++x)
719 const I3 be = b.advector().extent();
720 const int n0 = p.g.n(0),
n1 = p.g.n(1),
n2 = p.g.n(2);
722 const long base = off;
723 for (
int c = 0; c < nc; ++c) {
726 Kokkos::parallel_for(
727 "vof::block::pack_block",
730 const long k = base + x +
static_cast<long>(y) *
n0 +
static_cast<long>(z) *
n0 *
n1;
731 buf(nc * k + cc) = src(
L3(
q0 + x,
q1 + y,
q2 + z, be));
734 off +=
static_cast<long>(
n0) *
n1 *
n2;
739 const I3 e = patch_.
e, o = patch_.
o, be = b.advector().extent();
740 const int g = patch_.
g;
741 const int lo0 = p.g.lo[0],
lo1 = p.g.lo[1],
lo2 = p.g.lo[2];
742 const int n0 = p.g.n(0),
n1 = p.g.n(1),
n2 = p.g.n(2);
744 for (
int c = 0; c < nc; ++c) {
747 Kokkos::parallel_for(
748 "vof::block::combine_block",
751 const double v = src(
L3(
q0 + x,
q1 + y,
q2 + z, be));
752 const long i =
L3(
lo0 + x - o.x + g,
lo1 + y - o.y + g,
lo2 + z - o.z + g, e);
764 const I3 e = patch_.
e, o = patch_.
o;
765 const int g = patch_.
g;
766 const int lo0 = p.g.lo[0],
lo1 = p.g.lo[1],
lo2 = p.g.lo[2];
767 const int n0 = p.g.n(0),
n1 = p.g.n(1),
n2 = p.g.n(2);
768 const long base = off;
769 for (
int c = 0; c < nc; ++c) {
771 const int cc = c,
opc = op;
772 Kokkos::parallel_for(
773 "vof::block::combine_buf",
776 const long k = base + x +
static_cast<long>(y) *
n0 +
static_cast<long>(z) *
n0 *
n1;
777 const double v =
buf(nc * k + cc);
778 const long i =
L3(
lo0 + x - o.x + g,
lo1 + y - o.y + g,
lo2 + z - o.z + g, e);
787 off +=
static_cast<long>(
n0) *
n1 *
n2;
794 return b.advector().colour();
801 if (ghost > patch_.
g)
802 throw std::runtime_error(
803 "peclet::flow::vof::VofBlockExchange: block ghost wider than the face-velocity patch");
808 SField loc[3] = {lu_, lv_, lw_};
845#ifdef PECLET_FLOW_MPI
849 std::vector<MPI_Request>
reqs;
850 std::vector<SField>
dbuf(blocks.size());
851 std::vector<HostView>
hbuf(blocks.size());
852 std::vector<std::vector<double>>
hAux(blocks.size());
853 for (std::size_t i = 0; i < blocks.size(); ++i) {
855 if (
from == to || (
from != rank_ && to != rank_))
857 const I3 e = blocks[i].advector().extent();
858 const long len =
static_cast<long>(e.x) * e.y * e.z;
860 hbuf[i] = Kokkos::create_mirror_view(
dbuf[i]);
863 Kokkos::deep_copy(
dbuf[i], blocks[i].advector().
colour());
864 Kokkos::deep_copy(
hbuf[i],
dbuf[i]);
865 blocks[i].serializeAux(
hAux[i].
data());
885 for (std::size_t i = 0; i < blocks.size(); ++i)
886 if (
oldMaster[i] != blocks[i].master && blocks[i].master == rank_) {
887 Kokkos::deep_copy(
dbuf[i],
hbuf[i]);
888 Kokkos::deep_copy(blocks[i].advector().
colour(),
dbuf[i]);
889 blocks[i].deserializeAux(
hAux[i].
data());
906 const std::size_t k =
static_cast<std::size_t
>(bufSeq_++);
907 if (bufPool_.size() <= k)
908 bufPool_.resize(k + 1);
909 if (bufPool_[k].extent(0) !=
static_cast<std::size_t
>(n))
910 bufPool_[k] =
SField(Kokkos::view_alloc(
"vof::block::buf", Kokkos::WithoutInitializing),
911 static_cast<std::size_t
>(n));
915 static int ghostOf(
const std::vector<VofBlock>& blocks) {
916 for (
const auto& b : blocks)
918 return b.advector().ghost();
931 auto hu = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), lu_);
932 auto hv = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), lv_);
933 auto hw = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), lw_);
935 std::vector<std::vector<double>>
sendBuf(blocks.size());
936 std::vector<HostView>
hbu(blocks.size()),
hbv(blocks.size()),
hbw(blocks.size());
940 std::vector<double>
buf;
942 std::vector<Recv>
recvs;
943#ifdef PECLET_FLOW_MPI
944 std::vector<MPI_Request>
reqs;
948 for (std::size_t bi = 0; bi < blocks.size(); ++bi) {
950 const VofBox eb = b.extended(ghost);
952 const bool master = (b.master == rank_);
954 hbu[bi] = Kokkos::create_mirror_view(b.advector().faceU());
955 hbv[bi] = Kokkos::create_mirror_view(b.advector().faceV());
956 hbw[bi] = Kokkos::create_mirror_view(b.advector().faceW());
962 std::map<int, long>
counts;
963 for (
const auto& p : pieces_)
964 counts[p.rank] += p.cells();
966 for (
const auto& kv :
counts) {
967 if (kv.first == rank_)
969 recvs.push_back(
Recv{bi, kv.first, std::vector<double>(3 * kv.second)});
972 if (
counts.count(rank_)) {
976 for (
const auto& p : pieces_) {
987 for (
const auto& p : pieces_) {
995#ifdef PECLET_FLOW_MPI
998 for (
auto& r :
recvs) {
1001 tagOf(blocks[r.bi].id, 0),
comm_, &
reqs.back());
1002 gBytes_ +=
static_cast<long>(r.buf.size()) * 8;
1005 for (std::size_t bi = 0; bi < blocks.size(); ++bi) {
1010 blocks[bi].master, tagOf(blocks[bi].
id, 0),
comm_, &
reqs.back());
1011 gBytes_ +=
static_cast<long>(
sendBuf[bi].size()) * 8;
1019 for (
auto& r :
recvs) {
1021 vofBuildPieces(b.extended(ghost), gs_, per_, rankBox_, pieces_, ghost);
1023 for (
const auto& p : pieces_) {
1024 if (p.rank != r.from)
1026 unpackBlock(p, r.buf, off,
hbu[r.bi],
hbv[r.bi],
hbw[r.bi], b, ghost);
1029 for (std::size_t bi = 0; bi < blocks.size(); ++bi) {
1030 if (blocks[bi].master != rank_)
1032 Kokkos::deep_copy(blocks[bi].advector().faceU(),
hbu[bi]);
1033 Kokkos::deep_copy(blocks[bi].advector().faceV(),
hbv[bi]);
1034 Kokkos::deep_copy(blocks[bi].advector().faceW(),
hbw[bi]);
1042 auto hc = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),
cLocal);
1044 const I3 e = patch_.
e, n = patch_.
n;
1045 const int g = patch_.
g;
1046 for (
int z = 0; z < n.z; ++z)
1047 for (
int y = 0; y < n.y; ++y)
1048 for (
int x = 0; x < n.x; ++x)
1049 hc(
L3(x + g, y + g, z + g, e)) = 0.0;
1054 std::vector<double>
buf;
1056 std::vector<Recv>
recvs;
1057 std::vector<std::vector<double>>
sendBuf;
1060#ifdef PECLET_FLOW_MPI
1061 std::vector<MPI_Request>
reqs;
1063 std::vector<HostView>
hbc(blocks.size());
1065 for (std::size_t bi = 0; bi < blocks.size(); ++bi) {
1068 const bool master = (b.master == rank_);
1070 hbc[bi] = Kokkos::create_mirror_view(b.advector().colour());
1071 Kokkos::deep_copy(
hbc[bi], b.advector().colour());
1073 std::map<int, long>
counts;
1074 for (
const auto& p : pieces_)
1075 counts[p.rank] += p.cells();
1077 for (
const auto& kv :
counts) {
1078 if (kv.first == rank_) {
1079 for (
const auto& p : pieces_)
1080 if (p.rank == rank_)
1081 maxBlockIntoPatch(p,
hbc[bi], b,
hc);
1084 std::vector<double>
sb(kv.second);
1086 for (
const auto& p : pieces_)
1087 if (p.rank == kv.first)
1088 packBlockColour(p,
hbc[bi], b,
sb, off);
1090 sendTo.push_back(kv.first);
1093 }
else if (
counts.count(rank_)) {
1094 recvs.push_back(
Recv{bi, b.master, std::vector<double>(
counts[rank_])});
1097#ifdef PECLET_FLOW_MPI
1100 for (
auto& r :
recvs) {
1103 tagOf(blocks[r.bi].id, 1),
comm_, &
reqs.back());
1104 sBytes_ +=
static_cast<long>(r.buf.size()) * 8;
1107 for (std::size_t k = 0; k <
sendBuf.size(); ++k) {
1111 sBytes_ +=
static_cast<long>(
sendBuf[k].size()) * 8;
1118 for (
auto& r :
recvs) {
1122 for (
const auto& p : pieces_)
1123 if (p.rank == rank_)
1124 maxBufIntoPatch(p, r.buf, off,
hc);
1131#ifdef PECLET_FLOW_MPI
1135 const int nb =
static_cast<int>(blocks.size());
1136 std::vector<int> mine(6 * nb, 0), all(6 * nb, 0);
1137 for (
int i = 0; i < nb; ++i)
1138 if (blocks[i].master == rank_)
1139 for (
int d = 0; d < 3; ++d) {
1140 mine[6 * i + d] = blocks[i].box.lo[d];
1141 mine[6 * i + 3 + d] = blocks[i].box.hi[d];
1146 for (
int i = 0; i < nb; ++i)
1147 for (
int d = 0; d < 3; ++d) {
1148 blocks[i].box.lo[d] = all[6 * i + d];
1149 blocks[i].box.hi[d] = all[6 * i + 3 + d];
1157 using HostView =
decltype(Kokkos::create_mirror_view(
SField()));
1159 static void zero(HostView v) {
1160 for (std::size_t i = 0; i < v.extent(0); ++i)
1163 static int tagOf(
long id,
int phase) {
return static_cast<int>((
id % 4096) * 4 +
phase) + 4096; }
1165#ifdef PECLET_FLOW_MPI
1166 void requireComm()
const {
1168 throw std::runtime_error(
"peclet::flow::vof::VofBlockExchange: no communicator set");
1173 long patchIdx(
int gx,
int gy,
int gz)
const {
1174 return L3(gx - patch_.
o.
x + patch_.
g, gy - patch_.
o.
y + patch_.
g, gz - patch_.
o.
z + patch_.
g,
1179 void packPatch(
const VofPiece& p,
const HV& hu,
const HV& hv,
const HV& hw,
1180 std::vector<double>& buf,
long& off)
const {
1181 for (
int z =
p.g.lo[2];
z <
p.g.hi[2]; ++
z)
1182 for (
int y =
p.g.lo[1];
y <
p.g.hi[1]; ++
y)
1183 for (
int x =
p.g.lo[0];
x <
p.g.hi[0]; ++
x) {
1184 const long i = patchIdx(x, y, z);
1185 buf[3 *
off + 0] = hu(i);
1186 buf[3 *
off + 1] = hv(i);
1187 buf[3 *
off + 2] = hw(i);
1192 template <
class HV,
class HB>
1193 void copyPatchToBlock(
const VofPiece& p,
const HV& hu,
const HV& hv,
const HV& hw, HB bu, HB bv,
1194 HB bw,
const VofBlock& b,
int ghost)
const {
1195 const I3 be =
b.advector().extent();
1196 for (
int z =
p.g.lo[2];
z <
p.g.hi[2]; ++
z)
1197 for (
int y =
p.g.lo[1];
y <
p.g.hi[1]; ++
y)
1198 for (
int x =
p.g.lo[0];
x <
p.g.hi[0]; ++
x) {
1199 const long i = patchIdx(x, y, z);
1202 const int lx =
p.loc[0] + (
x -
p.g.lo[0]);
1203 const int ly =
p.loc[1] + (
y -
p.g.lo[1]);
1204 const int lz =
p.loc[2] + (
z -
p.g.lo[2]);
1205 const long j =
L3(lx, ly, lz, be);
1214 void unpackBlock(
const VofPiece& p,
const std::vector<double>& buf,
long& off, HB bu, HB bv,
1215 HB bw,
const VofBlock& b,
int ghost)
const {
1216 const I3 be =
b.advector().extent();
1217 for (
int z =
p.g.lo[2];
z <
p.g.hi[2]; ++
z)
1218 for (
int y =
p.g.lo[1];
y <
p.g.hi[1]; ++
y)
1219 for (
int x =
p.g.lo[0];
x <
p.g.hi[0]; ++
x) {
1220 const int lx =
p.loc[0] + (
x -
p.g.lo[0]);
1221 const int ly =
p.loc[1] + (
y -
p.g.lo[1]);
1222 const int lz =
p.loc[2] + (
z -
p.g.lo[2]);
1223 const long j =
L3(lx, ly, lz, be);
1224 bu(j) = buf[3 *
off + 0];
1225 bv(j) = buf[3 *
off + 1];
1226 bw(j) = buf[3 *
off + 2];
1234 void packBlockColour(
const VofPiece& p,
const HB& bc,
const VofBlock& b, std::vector<double>& buf,
1236 const I3 be =
b.advector().extent();
1237 const int g =
b.advector().ghost();
1238 for (
int z =
p.g.lo[2];
z <
p.g.hi[2]; ++
z)
1239 for (
int y =
p.g.lo[1];
y <
p.g.hi[1]; ++
y)
1240 for (
int x =
p.g.lo[0];
x <
p.g.hi[0]; ++
x) {
1241 const int lx =
p.loc[0] + (
x -
p.g.lo[0]);
1242 const int ly =
p.loc[1] + (
y -
p.g.lo[1]);
1243 const int lz =
p.loc[2] + (
z -
p.g.lo[2]);
1244 buf[
off++] = bc(
L3(lx + g, ly + g, lz + g, be));
1248 template <
class HB,
class HC>
1249 void maxBlockIntoPatch(
const VofPiece& p,
const HB& bc,
const VofBlock& b, HC& hc)
const {
1250 const I3 be =
b.advector().extent();
1251 const int g =
b.advector().ghost();
1252 for (
int z =
p.g.lo[2];
z <
p.g.hi[2]; ++
z)
1253 for (
int y =
p.g.lo[1];
y <
p.g.hi[1]; ++
y)
1254 for (
int x =
p.g.lo[0];
x <
p.g.hi[0]; ++
x) {
1255 const int lx =
p.loc[0] + (
x -
p.g.lo[0]);
1256 const int ly =
p.loc[1] + (
y -
p.g.lo[1]);
1257 const int lz =
p.loc[2] + (
z -
p.g.lo[2]);
1258 const double v = bc(
L3(lx + g, ly + g, lz + g, be));
1259 double&
d = hc(patchIdx(x, y, z));
1266 void maxBufIntoPatch(
const VofPiece& p,
const std::vector<double>& buf,
long& off, HC& hc)
const {
1267 for (
int z =
p.g.lo[2];
z <
p.g.hi[2]; ++
z)
1268 for (
int y =
p.g.lo[1];
y <
p.g.hi[1]; ++
y)
1269 for (
int x =
p.g.lo[0];
x <
p.g.hi[0]; ++
x) {
1270 const double v = buf[
off++];
1271 double&
d = hc(patchIdx(x, y, z));
1278 std::array<bool, 3> per_{
true,
true,
true};
1279 std::vector<VofBox> rankBox_;
1280 int rank_ = 0, size_ = 1;
1283 mutable std::vector<VofPiece> pieces_;
1284 std::vector<SField> bufPool_;
1286 long gBytes_ = 0, sBytes_ = 0, gMsgs_ = 0, sMsgs_ = 0, mBytes_ = 0, mMsgs_ = 0;
1287#ifdef PECLET_FLOW_MPI
1288 MPI_Comm comm_ = MPI_COMM_NULL;
1289 bool hasComm_ =
false;
flow — VoF Part III rung W0: the per-bubble VoF BLOCK, a third container over the same L1 kernels (su...
The gather / scatter / table replication of the block container.
SField buffer(long n)
Reusable device buffer of exactly n doubles, handed out in REQUEST ORDER — two live messages of the s...
void packFromBlock(const VofPiece &p, int nc, SField(*blockView)(VofBlock &, int), VofBlock &b, int blockBase, SField buf, long &off)
static SField faceViewOf(VofBlock &b, int c)
long gatherMessages() const
Messages posted by the last gather / scatter on this rank (sends + receives).
void combineBlockIntoPatch(const VofPiece &p, int nc, SField(*blockView)(VofBlock &, int), VofBlock &b, int blockBase, SField *loc, int op)
static SField colourViewOf(VofBlock &b, int c)
void init(I3 gs, std::array< bool, 3 > per, std::vector< VofBox > rankBox, int rank)
void scatterImpl(std::vector< VofBlock > &blocks, int nc, SField *loc, SField(*blockView)(VofBlock &, int), int blockBase, int op, bool gatherLocal=false)
block -> patch, combined with op (0 = max, 1 = sum).
void zeroPatchInner(int nc, SField *loc)
void unpackToBlock(const VofPiece &p, int nc, SField buf, long &off, SField(*blockView)(VofBlock &, int), VofBlock &b, int blockBase)
void moveLocalPieces(const std::vector< VofMoveJob > &mv)
H-4(e), host: every collected movePiece copy in one launch per chunk of kVofBlockBatch (piece,...
static int ghostOf(const std::vector< VofBlock > &blocks)
void gatherFaceVelHost(std::vector< VofBlock > &blocks, int ghost)
long scatterMessages() const
void packFromPatch(const VofPiece &p, int nc, const SField *loc, SField buf, long &off)
void scatterForceSum(std::vector< VofBlock > &blocks, SField fx, SField fy, SField fz) override
SUM every master block's CSF face force into the caller's three face-force patches (TBFsolver's UNPAC...
long migrateBytes() const
long migrateMessages() const
void setPatch(Patch p, SField uf, SField vf, SField wf)
The local face velocity, in the ADVECTOR's high-face convention (i.e.
static SField forceViewOf(VofBlock &b, int c)
void movePiece(const VofPiece &p, int nc, const SField *loc, SField(*blockView)(VofBlock &, int), VofBlock &b, int blockBase, bool toBlock)
The master's OWN cells: patch <-> block with no buffer and no host traffic.
long scatterBytes() const override
void gatherImpl(std::vector< VofBlock > &blocks, int ghost, bool useExtended, int nc, const SField *loc, SField(*blockView)(VofBlock &, int), int blockBase, int outside=0)
patch -> block.
void gatherFaceVel(std::vector< VofBlock > &blocks, int ghost) override
Fill every MASTER block's faceU/V/W over its EXTENDED box, from the face velocity the ranks own.
void setRankBoxes(std::vector< VofBox > rankBox)
Re-bind the owned inner box of every rank WITHOUT disturbing the communicator or the local patch.
void scatterColourSum(std::vector< VofBlock > &blocks, SField sLocal) override
S = sum_k C_k (vof_overlap_design §5.6): the colour scatter with UNPACK_SUM.
void migrateColour(std::vector< VofBlock > &blocks, const std::vector< int > &oldMaster) override
Move a block's colour from its old master to its new one after a re-assignment (rung W1 item a).
long gatherBytes() const override
Bytes moved by the last gather / scatter on THIS rank (sent + received).
void scatterColourMax(std::vector< VofBlock > &blocks, SField cLocal) override
UNION the masters' inner colour into the caller's local colour patch: zero the inner region,...
void gatherLocalLaunch(const GatherTable &T, SField *loc)
void gatherColour(std::vector< VofBlock > &blocks, SField cLocal) override
Fill every MASTER block's INNER colour from the caller's colour patch (the mirror of scatterColourMax...
void syncTable(std::vector< VofBlock > &blocks) override
Replicate the (possibly re-centred) boxes so every rank's table agrees again.
void scatterColourMaxHost(std::vector< VofBlock > &blocks, SField cLocal)
void gatherLocalSum(std::vector< VofBlock > &blocks, int nc, SField *loc, SField(*blockView)(VofBlock &, int), int blockBase)
The local half of a gatherLocal UNPACK_SUM: every patch INNER cell written (so no zeroing pass is nee...
void appendMoveJobs(const VofPiece &p, int nc, const SField *loc, SField(*blockView)(VofBlock &, int), VofBlock &b, int blockBase, std::vector< VofMoveJob > &out)
H-4(e): the (piece, component) copies of movePiece for one piece, appended to out.
void combineBufIntoPatch(const VofPiece &p, int nc, SField buf, long &off, SField *loc, int op)
static constexpr int kAuxLen
The non-colour state a master carries between steps: the previous centroid (so a migrated block's rep...
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
bool vofMoveOverlap(const VofMoveJob &a, const VofMoveJob &b)
Debug check of H-4(e)'s premise: two jobs writing the same block array overlap.
constexpr int kVofBlockBatch
Jobs per launch; a container with more master blocks runs each stage in chunks.
int vofAxisRuns(int a, int b, int gs, bool periodic, VofRun out[5], int outside=0)
Decompose [a, b) on one axis into global runs.
void vofBuildPieces(const VofBox &box, I3 gs, const std::array< bool, 3 > &per, const std::vector< VofBox > &rankBox, std::vector< VofPiece > &out, int outside=0)
Build the pieces of one block box against every rank's owned box, in canonical order.
long L3(int x, int y, int z, I3 e)
void ccFor3(const char *name, C3 lo, C3 hi, F f)
Kokkos::DefaultExecutionSpace SExec
Kokkos::View< double *, SMem > SField
flow — the multidimensional iteration policies: iteration order follows storage.
Gather / scatter / table replication.
int lo[kVofBlockBatch][3]
const double * f[kVofBlockBatch][3]
This rank's own patch: the extended block the face velocity and the union colour live on.
I3 o
global index of inner cell (0,0,0)
Half-open global cell box [lo, hi).
static VofBox intersect(const VofBox &a, const VofBox &b)
Intersection in global coordinates (may be empty).
One (piece, component) copy of VofBlockExchange::movePiece – patch cells [s, s + n) to block cells [q...
I3 q
the piece's first cell in the patch and in the block array
I3 be
the patch's and the block array's extents
The job table of one move launch, by value.
VofMoveJob job[kVofBlockBatch]
One contiguous transfer: the global cells g of a block that rank r owns, and where they sit in the bl...
int loc[3]
block-local index (0-based within the block's box) of g.lo
VofBox g
the overlap, in global cell indices
One contiguous run of GLOBAL indices covered by a block's index range on one axis,...
static std::vector< double > colour(int m)