30static std::vector<double>
packingSdf(
double rfrac = 0.18) {
31 const double R = rfrac *
N;
32 std::vector<double> sdf((std::size_t)
N *
N *
N);
33 const double cs[2] = {0.25 *
N, 0.75 *
N};
34 for (
int z = 0; z <
N; ++z)
35 for (
int y = 0; y <
N; ++y)
36 for (
int x = 0; x <
N; ++x) {
40 for (
double sz : cs) {
41 auto wrap = [](
double d) {
return d -
N * std::round(d /
N); };
42 const double dx = wrap(x - sx), dy = wrap(y - sy), dz = wrap(z - sz);
43 best = std::min(best, std::sqrt(dx * dx + dy * dy + dz * dz) - R);
45 sdf[(std::size_t)x + (std::size_t)y *
N + (std::size_t)z *
N *
N] = best;
79static void configure(IbmSolver& s,
const Config& c,
const std::vector<double>& lsdf,
int ox,
80 int oy,
int oz,
int lnx,
int lny,
int lnz) {
84 s.setBodyForce(
F, 0, 0);
85 s.setAdvection(
false);
86 s.setVelocityIterations(60);
87 s.setPressureLevels(4);
88 s.setPressurePcg(
true, 200, 1e-9);
89 s.setSolid(lsdf,
true);
91 s.setPropertyMode(
true,
true);
92 s.setField(
"mu",
blockOf(
muAt, ox, oy, oz, lnx, lny, lnz));
93 s.exchangeField(
"mu");
96 s.setDensityMode(
true);
97 s.setField(
"rho",
blockOf(
rhoAt, ox, oy, oz, lnx, lny, lnz));
98 s.exchangeField(
"rho");
101 s.setPorousContinuity(
true);
102 s.setField(
"eps",
blockOf(
epsAt, ox, oy, oz, lnx, lny, lnz));
103 s.exchangeField(
"eps");
106 s.addScalar(
"c", 0.05, 1, 40);
108 s.exchangeField(
"c");
115 s.addScalar(
"c", 0.1, 1, 40);
118 s.setScalarBc(
"c", 0, 2, 1.0);
119 s.setScalarBc(
"c", 1, 2, 0.0);
120 s.exchangeField(
"c");
126static std::vector<double>
gatherGlobal(
const std::vector<double>& local,
int ox,
int oy,
int oz,
127 int lnx,
int lny,
int lnz,
int rank,
int size) {
128 std::vector<double> global;
130 global.assign((std::size_t)
N *
N *
N, 0.0);
131 for (
int r = 0; r < size; ++r) {
132 int meta[6] = {ox, oy, oz, lnx, lny, lnz};
135 for (
int z = 0; z < lnz; ++z)
136 for (
int y = 0; y < lny; ++y)
137 std::memcpy(&global[(std::size_t)ox + (std::size_t)(y + oy) *
N +
138 (std::size_t)(z + oz) *
N *
N],
139 &local[(std::size_t)y * lnx + (std::size_t)z * lnx * lny],
140 (std::size_t)lnx *
sizeof(
double));
144 MPI_Send(meta, 6, MPI_INT, 0, 100 + r, MPI_COMM_WORLD);
145 MPI_Send(local.data(), (
int)local.size(), MPI_DOUBLE, 0, 200 + r, MPI_COMM_WORLD);
146 }
else if (rank == 0) {
147 MPI_Recv(meta, 6, MPI_INT, r, 100 + r, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
148 std::vector<double> buf((std::size_t)meta[3] * meta[4] * meta[5]);
149 MPI_Recv(buf.data(), (
int)buf.size(), MPI_DOUBLE, r, 200 + r, MPI_COMM_WORLD,
151 for (
int z = 0; z < meta[5]; ++z)
152 for (
int y = 0; y < meta[4]; ++y)
153 std::memcpy(&global[(std::size_t)meta[0] + (std::size_t)(y + meta[1]) *
N +
154 (std::size_t)(z + meta[2]) *
N *
N],
155 &buf[(std::size_t)y * meta[3] + (std::size_t)z * meta[3] * meta[4]],
156 (std::size_t)meta[3] *
sizeof(
double));
163static double relErr(
const std::vector<double>& a,
const std::vector<double>& b) {
164 double md = 0, mb = 0;
165 for (std::size_t i = 0; i < b.size(); ++i) {
166 md = std::max(md, std::fabs(a[i] - b[i]));
167 mb = std::max(mb, std::fabs(b[i]));
169 return md / (mb + 1e-300);
172int main(
int argc,
char** argv) {
173 MPI_Init(&argc, &argv);
174 Kokkos::initialize(argc, argv);
177 int rank = 0, size = 1;
178 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
179 MPI_Comm_size(MPI_COMM_WORLD, &size);
180 const std::vector<double> gsdf =
packingSdf();
182 peclet::core::decomp::BlockDecomposer<3> dec(
static_cast<std::size_t
>(size), IVec<3>{
N,
N,
N});
183 auto blk = dec.block(rank);
184 const int ox = (int)blk.origin[0], oy = (
int)blk.origin[1], oz = (int)blk.origin[2];
185 const int lnx = (int)blk.size[0], lny = (
int)blk.size[1], lnz = (int)blk.size[2];
186 std::vector<double> lsdf((std::size_t)lnx * lny * lnz);
187 for (
int z = 0; z < lnz; ++z)
188 for (
int y = 0; y < lny; ++y)
189 for (
int x = 0; x < lnx; ++x)
190 lsdf[(std::size_t)x + (std::size_t)y * lnx + (std::size_t)z * lnx * lny] =
191 gsdf[(std::size_t)(x + ox) + (std::size_t)(y + oy) *
N +
192 (std::size_t)(z + oz) *
N *
N];
194 const Config configs[] = {{
"varmu",
true,
false,
false,
false,
false},
195 {
"varrho",
false,
true,
false,
false,
false},
196 {
"porous",
false,
false,
true,
false,
false},
197 {
"scalar",
false,
false,
false,
true,
false},
198 {
"scalarbc",
false,
false,
false,
false,
true}};
200 for (
const Config& c : configs) {
202 IbmSolver sd(lnx, lny, lnz);
203 sd.initMpi(
N,
N,
N, MPI_COMM_WORLD);
204 configure(sd, c, lsdf, ox, oy, oz, lnx, lny, lnz);
205 for (
int it = 0; it <
STEPS; ++it)
207 auto gu =
gatherGlobal(sd.getVelocity(0), ox, oy, oz, lnx, lny, lnz, rank, size);
208 std::vector<double> gc;
209 if (c.scalar || c.scalarBc)
210 gc =
gatherGlobal(sd.getField(
"c"), ox, oy, oz, lnx, lny, lnz, rank, size);
213 double eu = -1, ec = -1;
215 IbmSolver ref(
N,
N,
N);
217 for (
int it = 0; it <
STEPS; ++it)
219 eu =
relErr(gu, ref.getVelocity(0));
220 const bool hasC = c.scalar || c.scalarBc;
222 ec =
relErr(gc, ref.getField(
"c"));
223 const double tol = (size == 1) ? 1e-12 : 5e-5;
224 const bool ok = eu <= tol && (!hasC || ec <= tol);
225 std::printf(
" [%-8s np=%d] u rel=%.3e%s tol=%.0e %s\n", c.name, size, eu,
226 hasC ? (std::string(
" c rel=") + std::to_string(ec)).c_str() :
"", tol,
231 MPI_Bcast(&fail, 1, MPI_INT, 0, MPI_COMM_WORLD);
234 std::printf(
"MULTIPHYSICS MPI (np=%d): %s\n", size, fail ?
"FAIL" :
"PASS");
static std::vector< double > blockOf(Fn f, int ox, int oy, int oz, int lnx, int lny, int lnz)
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 void configure(IbmSolver &s, const Config &c, const std::vector< double > &lsdf, int ox, int oy, int oz, int lnx, int lny, int lnz)