8#ifndef PECLET_FLOW_FLOW_IBM_MPI_HPP
9#define PECLET_FLOW_FLOW_IBM_MPI_HPP
17 MPI_Comm_size(comm, &size);
23 initMpi(CutcellMG::decomposition(
static_cast<std::size_t
>(size), gnx, gny, gnz, decompLevels_,
40 if (geometryBuilt_ && !distributed_)
41 throw std::runtime_error(
42 "init_mpi: call BEFORE the geometry (set_solid / set_pressure_geometry / "
43 "set_solid_from_scene) -- the geometry builds the pressure and velocity multigrids for the "
44 "partition in force when it runs, so a geometry built first gives every rank an "
45 "independent, block-periodic pressure solve (a wrong answer at np > 1, with no error)");
49 const auto&
gs = dec.globalSize();
54 MPI_Comm_rank(comm, &rank);
55 std::array<bool, 3> per{
true,
true,
true};
56 velHalo_ = std::make_shared<GridHaloTopology<3>>();
57 velHalo_->buildTopology(dec, rank,
G, per, comm);
58 velDev_ = std::make_shared<GridHalo<double>>();
59 velDev_->setLabel(
"velocity g2");
60 velDev_->init(*velHalo_);
65 velDevF_ = std::make_shared<GridHalo<MReal>>();
66 velDevF_->init(*velHalo_);
67 long minExt = std::numeric_limits<long>::max();
68 for (
const auto& s : dec.sizes())
69 for (
int k = 0;
k < 3; ++
k)
70 minExt = std::min(minExt, (
long)
s[
k]);
71 caMomentum_ = (caMode_ &
kCaMomentum) && minExt >= 4;
72 for (
bool& d : momStencilDirty_)
74 dec_ = std::make_shared<peclet::core::decomp::BlockDecomposer<3>>(dec);
75 const auto oig = velHalo_->indexer().originInclGhost();
76 og_ = {(
int)oig[0] +
G, (
int)oig[1] +
G, (
int)oig[2] +
G};
88 if (!distributed_ || !dec_)
91 MPI_Comm_rank(comm_, &rank);
92 const auto ob = dec_->block(rank),
nb = newDec.block(rank);
93 const int oex = (
int)ob.size[0] + 2 *
G, oey = (
int)ob.size[1] + 2 *
G,
94 oez = (
int)ob.size[2] + 2 *
G;
95 const int nex = (
int)
nb.size[0] + 2 *
G, ney = (
int)
nb.size[1] + 2 *
G,
96 nez = (
int)
nb.size[2] + 2 *
G;
99 const auto names = fields_.names();
100 std::vector<std::vector<double>> oldHost(
names.size()), newHost(
names.size());
101 for (std::size_t k = 0;
k <
names.size(); ++
k) {
102 CCField f = fields_.at(names[k]).data;
103 auto h = Kokkos::create_mirror_view(f);
104 Kokkos::deep_copy(h, f);
105 oldHost[
k].assign(
h.data(),
h.data() + (std::size_t)oex * oey * oez);
106 newHost[
k].assign((std::size_t)nex * ney * nez, 0.0);
109 std::vector<const double*>
op(
names.size());
110 std::vector<double*> np(
names.size());
111 for (std::size_t k = 0;
k <
names.size(); ++
k) {
112 op[
k] = oldHost[
k].data();
113 np[
k] = newHost[
k].data();
121 MPI_Allreduce(&warmLocal, &warmAll, 1, MPI_INT, MPI_MIN, comm_);
122 std::vector<double> eigOld[2], eigNew[2];
125 const int o1x = (
int)ob.size[0] + 2, o1y = (
int)ob.size[1] + 2;
126 for (
int v = 0;
v < 2; ++
v) {
127 auto h = Kokkos::create_mirror_view(src[v]);
128 Kokkos::deep_copy(h, src[v]);
129 eigOld[
v].assign((std::size_t)oex * oey * oez, 0.0);
130 eigNew[
v].assign((std::size_t)nex * ney * nez, 0.0);
131 for (
int z = 0;
z < (
int)ob.size[2]; ++
z)
132 for (
int y = 0;
y < (
int)ob.size[1]; ++
y)
133 for (
int x = 0;
x < (
int)ob.size[0]; ++
x)
134 eigOld[v][(std::size_t)(
x +
G) + (std::size_t)(
y +
G) * oex +
135 (std::size_t)(
z +
G) * oex * oey] =
136 h((std::size_t)(
x + 1) + (std::size_t)(
y + 1) * o1x +
137 (std::size_t)(
z + 1) * o1x * o1y);
138 op.push_back(eigOld[v].data());
139 np.push_back(eigNew[v].data());
142 peclet::core::decomp::redistributeGridFields<double>(*dec_, newDec, rank,
G, op, np, comm_);
151 initMpi(newDec, comm_);
153 auto scatterPadded = [&](
const std::string& name,
const std::vector<double>& src) {
155 auto h = Kokkos::create_mirror_view(f);
156 std::memcpy(
h.data(), src.data(),
sizeof(
double) * (std::size_t)nex * ney * nez);
157 Kokkos::deep_copy(f, h);
160 for (std::size_t k = 0;
k <
names.size(); ++
k)
161 scatterPadded(names[k], newHost[k]);
169 const bool keepBfpBounds = bfpChebSet_;
171 bfpChebSet_ = keepBfpBounds;
173 for (std::size_t k = 0;
k <
names.size(); ++
k)
174 if (names[k] !=
"sdf")
175 scatterPadded(names[k], newHost[k]);
179 const int n1x = (
int)
nb.size[0] + 2, n1y = (
int)
nb.size[1] + 2, n1z = (
int)
nb.size[2] + 2;
181 for (
int v = 0;
v < 2; ++
v) {
182 dst[
v] =
CCField(v == 0 ?
"ev_vmax" :
"ev_vmin", (std::size_t)n1x * n1y * n1z);
183 auto h = Kokkos::create_mirror_view(dst[v]);
184 Kokkos::deep_copy(h, 0.0);
185 for (
int z = 0;
z < (
int)
nb.size[2]; ++
z)
186 for (
int y = 0;
y < (
int)
nb.size[1]; ++
y)
187 for (
int x = 0;
x < (
int)
nb.size[0]; ++
x)
188 h((std::size_t)(
x + 1) + (std::size_t)(
y + 1) * n1x +
189 (std::size_t)(
z + 1) * n1x * n1y) =
190 eigNew[
v][(std::size_t)(x +
G) + (std::size_t)(y +
G) * nex +
191 (std::size_t)(z +
G) * nex * ney];
192 Kokkos::deep_copy(dst[v], h);
203 for (std::size_t k = 0;
k <
names.size(); ++
k)
205 for (
auto& sc : scalars_)
216 if (epsPrev_.extent(0) == n_ && epsField_.extent(0) == n_)
217 Kokkos::deep_copy(epsPrev_, epsField_);
234 int size = 1,
rank = 0;
235 MPI_Comm_size(comm_, &size);
236 MPI_Comm_rank(comm_, &rank);
246 const auto c = peclet::core::decomp::chooseAlignedWeighted(
247 (std::size_t)size, peclet::core::IVec<3>{gnx_, gny_, gnz_},
w);
250 "[mg] rebalanceByWeights: aligned weighted ORB a = %d (align %d), weight imbalance "
252 c.a, 1 <<
c.a, (
double)
c.imbalance);
262 return mg_.builtPlan();
267void Solver<Grid>::resizeForBlock() {
268 reallocOwnedFields();
269 rebindFieldAliases();
270 resizeBlockScratch();
271 for (
int f = 0;
f < 6; ++
f)
276void Solver<Grid>::reallocOwnedFields() {
277 for (
const auto& nm : fields_.
names()) {
278 auto& rec = fields_.at(nm);
279 if (!rec.ownStorage || rec.data.extent(0) == n_)
286void Solver<Grid>::rebindFieldAliases() {
287 auto bind = [
this](
CCField&
f,
const std::string& nm) {
289 f = fields_.at(nm).data;
292 bind(kappaField_,
"kappa");
293 bind(kappaBranch_,
"kappa_branch");
294 bind(rhoField_,
"rho");
295 bind(Pb_,
"p_balanced");
296 bind(muField_,
"mu");
297 bind(epsField_,
"eps");
298 bind(dragBeta_,
"drag_beta");
299 bind(pcMdot_,
"mdot");
300 bind(pcSrc_,
"pc_source");
301 bind(pcUser_,
"div_source");
302 bind(pcSink_,
"div_sink");
303 static const char*
fn[3] = {
"force_x",
"force_y",
"force_z"};
304 for (
int c = 0;
c < 3; ++
c)
305 bind(cellForce_[c], fn[c]);
306 for (
auto& sc : scalars_) {
308 if (
sc.cut &&
sc.cut->solid.extent(0) > 0)
309 bind(
sc.cut->solid,
sc.name +
"_solid");
311 for (
auto& cl : closures_) {
312 if (fields_.has(cl.outName))
313 cl.out = fields_.at(cl.outName).data;
314 if (fields_.has(cl.in0Name))
315 cl.in0 =
CCConst(fields_.at(cl.in0Name).data);
316 if (!cl.in1Name.empty() && fields_.has(cl.in1Name))
317 cl.in1 =
CCConst(fields_.at(cl.in1Name).data);
322void Solver<Grid>::resizeIfAllocated(
CCField& f,
const char* label, std::size_t n) {
323 if (
f.extent(0) != 0 &&
f.extent(0) != n)
328void Solver<Grid>::resizeBlockScratch() {
329 const std::size_t
n = n_, n1 = n1_;
331 resizeIfAllocated(velRes_,
"velRes", n);
332 resizeIfAllocated(zp1_,
"zp1", n1);
333 resizeIfAllocated(vmgTheta_,
"vmgTheta", n);
334 resizeIfAllocated(vmgClean_,
"vmgClean", n);
335 for (
int c = 0;
c < 3; ++
c) {
336 resizeIfAllocated(uStar_[c],
"uStar", n);
337 resizeIfAllocated(advRhs_[c],
"advRhs", n);
338 resizeIfAllocated(uBc_[c],
"uBc", n);
339 resizeIfAllocated(uwCell_[c],
"uwCell", n);
340 resizeIfAllocated(uwAdv_[c],
"uwAdv", n);
341 resizeIfAllocated(faceAcc_[c],
"faceAcc", n);
343 resizeIfAllocated(pb1_,
"pb1",
348 resizeIfAllocated(oxb_,
"oxb", n);
349 resizeIfAllocated(oyb_,
"oyb", n);
350 resizeIfAllocated(ozb_,
"ozb", n);
351 resizeIfAllocated(sdfGp_,
"peclet::flow::sdfGp", n);
352 resizeIfAllocated(gpRh_,
"gpRh", n1);
353 resizeIfAllocated(gpT_,
"gpT", n1);
354 resizeIfAllocated(gpZ2_,
"gpZ2", n1);
355 resizeIfAllocated(gpX2_,
"gpXg2", n);
357 resizeIfAllocated(vofCs_,
"vofCs", n);
358 resizeIfAllocated(vofSolidG2_,
"vofSolidG2", n);
359 for (
int c = 0;
c < 3; ++
c) {
360 resizeIfAllocated(uAdv_[c],
"uAdv", n);
361 resizeIfAllocated(vofDynVel_[c],
"vofDynVel", n);
362 resizeIfAllocated(csfBlkF_[c],
"vof::blockcsf", n);
365 resizeIfAllocated(pcArea_,
"pc_area", n);
366 for (
int c = 0;
c < 3; ++
c) {
367 resizeIfAllocated(pcNrm_[c],
"pc_nrm", n);
368 resizeIfAllocated(pcGn_[c],
"pc_gn", n);
370 resizeIfAllocated(pcDep_,
"pc_dep", n);
371 resizeIfAllocated(pcTgt_,
"pc_tgt", n);
372 resizeIfAllocated(pcCnew_,
"pc_cnew", n);
373 resizeIfAllocated(pcDefic_,
"pc_defic", n);
374 resizeIfAllocated(pcKcell_,
"pc_k", n);
375 resizeIfAllocated(pcRcp_,
"pc_rcp", n);
376 resizeIfAllocated(pcClsPrev_,
"pc_cls_prev", n);
377 resizeIfAllocated(pcCarrySrc_,
"pc_carry_src", n);
378 resizeIfAllocated(pcMdotFit_,
"pc_mdot_fit", n);
379 resizeIfAllocated(pcKappa_,
"pc_kappa", n);
380 resizeIfAllocated(pcAreaCg2_,
"pc_area_cascade", n);
381 resizeIfAllocated(pcTgam_,
"pc_tgam", n);
382 resizeIfAllocated(pcGphi_,
"pc_gphi", n);
384 pcMaskFresh_ =
false;
386 for (
auto& sc : scalars_) {
387 resizeIfAllocated(
sc.cOld,
"scalar_old", n);
388 resizeIfAllocated(
sc.b,
"scalar_b", n);
389 resizeIfAllocated(
sc.AC,
"scalar_AC", n);
390 resizeIfAllocated(
sc.AW,
"scalar_AW", n);
391 resizeIfAllocated(
sc.AE,
"scalar_AE", n);
392 resizeIfAllocated(
sc.AS,
"scalar_AS", n);
393 resizeIfAllocated(
sc.AN,
"scalar_AN", n);
394 resizeIfAllocated(
sc.AB,
"scalar_AB", n);
395 resizeIfAllocated(
sc.AT,
"scalar_AT", n);
396 resizeIfAllocated(
sc.dmask,
"scalar_dmask", n);
397 resizeIfAllocated(
sc.dval,
"scalar_dval", n);
398 resizeIfAllocated(
sc.gfmB,
"scalar_gfmb", n);
399 sc.stencilBuilt =
false;
405 if (pcEnergy_ && !pcTName_.empty() &&
hasScalar(pcTName_)) {
411 resizeIfAllocated(rho1_,
"rho1", n1);
412 resizeIfAllocated(cx1_,
"cx1", n1);
413 resizeIfAllocated(cy1_,
"cy1", n1);
414 resizeIfAllocated(cz1_,
"cz1", n1);
415 resizeIfAllocated(eps1_,
"eps1", n1);
416 resizeIfAllocated(beta1_,
"beta1", n1);
417 resizeIfAllocated(depsdt_,
"depsdt", n);
418 resizeIfAllocated(divAdv_,
"divAdv", n);
419 resizeIfAllocated(epsRho_,
"epsRho", n);
420 resizeIfAllocated(epsPrev_,
"epsPrev", n);
421 for (
int c = 0;
c < 3; ++
c)
422 for (
int k = 0;
k < 3; ++
k)
423 if (tEx_[c][k].extent(0) != 0 && tEx_[c][k].extent(0) != (std::size_t)nx_ * ny_ * nz_) {
425 hasExactCross_ =
false;
CCField eigenWarmMax() const
bool eigenWarmReady() const
CCField eigenWarmMin() const
void setEigenWarm(CCField vmax, CCField vmin)
void setSolid(const std::vector< double > &sdfInner, bool cutcellPressure)
Host entry point: upload the inner SDF once and delegate.
ScalarField & scalarField(const std::string &name)
void fillGhosts(CCField f)
void seedFaceFieldFromCells()
Solver(int nx, int ny, int nz)
void resampleBcProfile(int face)
void allocateBlock(int nx, int ny, int nz)
bool hasScalar(const std::string &name) const
std::vector< double > gatherInner(CCField fld)
Kokkos::View< double *, CCMem > CCField
Kokkos::View< const double *, CCMem > CCConst