135static void cg(CCField x, CCConst b,
OpV AC,
OpV AW,
OpV AE,
OpV AS,
OpV AN,
OpV AB,
OpV AT,
C3 e,
136 Exch&& exchange,
const Reduce& red,
long gCells,
int iters) {
137 const std::size_t n = x.extent(0);
138 CCField r(
"r", n), p(
"p", n), Ap(
"Ap", n);
139 auto matvec = [&](CCField y, CCField v) {
141 applyCutcellOp(y, CCConst(v),
AC, AW, AE, AS, AN, AB, AT, e,
G);
144 Kokkos::deep_copy(x, 0.0);
145 Kokkos::deep_copy(r, b);
147 Kokkos::deep_copy(p, r);
148 double rr = red.
dot(CCConst(r), CCConst(r));
149 for (
int it = 0; it < iters; ++it) {
151 const double pAp = red.
dot(CCConst(p), CCConst(Ap));
154 const double alpha = rr / pAp;
155 axpy(x, alpha, CCConst(p));
156 axpy(r, -alpha, CCConst(Ap));
158 const double rrn = red.
dot(CCConst(r), CCConst(r));
159 aypx(p, rrn / rr, CCConst(r));
164int main(
int argc,
char** argv) {
165 MPI_Init(&argc, &argv);
166 Kokkos::initialize(argc, argv);
167 int fail = 0, size = 1, rank = 0;
169 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
170 MPI_Comm_size(MPI_COMM_WORLD, &size);
171 IVec<kDim> gs{24, 20, 16};
172 std::array<bool, kDim> periodic{
true,
true,
true};
173 const long gCells = (long)gs[0] * gs[1] * gs[2];
176 BlockDecomposer<kDim> dec(
static_cast<std::size_t
>(size), gs);
177 GridHaloTopology<kDim> halo;
178 halo.buildTopology(dec, rank,
G, periodic, MPI_COMM_WORLD);
179 const auto& idx = halo.indexer();
180 const Index n = idx.numCellsInclGhost();
181 const auto eg = idx.sizeInclGhost(), og = idx.originInclGhost();
182 const C3 e{(int)eg[0], (
int)eg[1], (int)eg[2]};
183 GridHalo<double> dev;
185 Reduce red{e, MPI_COMM_WORLD};
187 CCField ox(
"ox", n), oy(
"oy", n),
189 Kokkos::deep_copy(ox, 1.0);
190 Kokkos::deep_copy(oy, 1.0);
191 Kokkos::deep_copy(oz, 1.0);
192 OpV AC(
"AC", n), AW(
"AW", n), AE(
"AE", n), AS(
"AS", n), AN(
"AN", n), AB(
"AB", n), AT(
"AT", n);
193 peclet::flow::buildCutcellOp(
AC, AW, AE, AS, AN, AB, AT, CCConst(ox), CCConst(oy), CCConst(oz),
194 e,
G, 1.0, 1.0, 1.0);
196 CCField b(
"b", n), x(
"x", n);
197 auto hb = Kokkos::create_mirror_view(b);
198 for (Index c = 0; c < n; ++c)
200 idx.forEachInner([&](
const IVec<kDim>& l) {
201 hb(idx.localMdToLocal(l)) =
source(l[0] + og[0], l[1] + og[1], l[2] + og[2], gs);
203 Kokkos::deep_copy(b, hb);
205 x, CCConst(b),
AC, AW, AE, AS, AN, AB, AT, e, [&](CCField v) { dev.exchange(v); }, red,
207 auto hx = Kokkos::create_mirror_view(x);
208 Kokkos::deep_copy(hx, x);
212 const C3 ge{(int)gs[0] + 2 *
G, (
int)gs[1] + 2 *
G, (int)gs[2] + 2 *
G};
213 const Index gn = (Index)ge.
x * ge.y * ge.z;
214 CCField gox(
"gox", gn), goy(
"goy", gn), goz(
"goz", gn);
215 Kokkos::deep_copy(gox, 1.0);
216 Kokkos::deep_copy(goy, 1.0);
217 Kokkos::deep_copy(goz, 1.0);
218 OpV gAC(
"gAC", gn), gAW(
"gAW", gn), gAE(
"gAE", gn), gAS(
"gAS", gn), gAN(
"gAN", gn),
219 gAB(
"gAB", gn), gAT(
"gAT", gn);
221 CCConst(goz), ge,
G, 1.0, 1.0, 1.0);
222 CCField gb(
"gb", gn), gx(
"gx", gn);
223 auto hgb = Kokkos::create_mirror_view(gb);
224 for (Index c = 0; c < gn; ++c)
226 for (
int z = 0; z < gs[2]; ++z)
227 for (
int y = 0; y < gs[1]; ++y)
228 for (
int xx = 0; xx < gs[0]; ++xx)
229 hgb((
long)(xx +
G) + (
long)(y +
G) * ge.x + (
long)(z +
G) * (
long)ge.x * ge.y) =
231 Kokkos::deep_copy(gb, hgb);
232 Reduce gred{ge, MPI_COMM_SELF};
234 auto serialFill = [&](CCField f) {
236 long st[3] = {1, ge.x, (long)ge.x * ge.y};
237 int dims[3] = {ge.x, ge.y, ge.z};
238 int N3[3] = {(int)gs[0], (
int)gs[1], (int)gs[2]};
239 for (
int a = 0; a < 3; ++a) {
240 const int bb = (a + 1) % 3, cc = (a + 2) % 3;
241 const long sa = st[a], sb = st[bb], sc = st[cc];
244 Kokkos::parallel_for(
246 Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<2>>(sp, {0, 0}, {dims[bb], dims[cc]}),
247 KOKKOS_LAMBDA(
int p0,
int p1) {
248 const long base = (long)p0 * sb + (
long)p1 * sc;
249 for (
int gl = 0; gl <
G; ++gl) {
250 ff(base + (
long)gl * sa) = ff(base + (
long)(gl +
N) * sa);
251 ff(base + (
long)(
G +
N + gl) * sa) = ff(base + (
long)(
G + gl) * sa);
257 cg(gx, CCConst(gb), gAC, gAW, gAE, gAS, gAN, gAB, gAT, ge, serialFill, gred, gCells,
CGIT);
258 auto hgx = Kokkos::create_mirror_view(gx);
259 Kokkos::deep_copy(hgx, gx);
261 double maxdiff = 0.0;
262 idx.forEachInner([&](
const IVec<kDim>& l) {
263 const int gxk = l[0] + og[0], gyk = l[1] + og[1], gzk = l[2] + og[2];
264 const double a = hx(idx.localMdToLocal(l));
266 hgx((
long)(gxk +
G) + (
long)(gyk +
G) * ge.x + (
long)(gzk +
G) * (
long)ge.x * ge.y);
267 const double d = std::fabs(a - r);
271 if (maxdiff > 1e-11) {
273 std::fprintf(stderr,
"[rank %d] max|distributed - serial CG| = %.3e\n", rank, maxdiff);
277 MPI_Allreduce(&fail, &totalFail, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
280 std::printf(
"OK (np=%d): distributed cut-cell pressure CG == serial reference\n", size);
282 std::fprintf(stderr,
"FAILED (np=%d): %d ranks differ\n", size, totalFail);
286 return totalFail == 0 ? 0 : 1;