127static void cg(CCField x, CCConst b,
OpV AC,
OpV AW,
OpV AE,
OpV AS,
OpV AN,
OpV AB,
OpV AT,
C3 e,
128 Exch&& exchange,
const Reduce& red,
long gCells,
int iters) {
129 const std::size_t n = x.extent(0);
130 CCField r(
"r", n), p(
"p", n), Ap(
"Ap", n);
131 auto matvec = [&](CCField y, CCField v) {
133 applyCutcellOp(y, CCConst(v),
AC, AW, AE, AS, AN, AB, AT, e,
G);
136 Kokkos::deep_copy(x, 0.0);
137 Kokkos::deep_copy(r, b);
139 Kokkos::deep_copy(p, r);
140 double rr = red.
dot(CCConst(r), CCConst(r));
141 for (
int it = 0; it < iters; ++it) {
143 const double pAp = red.
dot(CCConst(p), CCConst(Ap));
146 const double alpha = rr / pAp;
147 axpy(x, alpha, CCConst(p));
148 axpy(r, -alpha, CCConst(Ap));
150 const double rrn = red.
dot(CCConst(r), CCConst(r));
151 aypx(p, rrn / rr, CCConst(r));
156int main(
int argc,
char** argv) {
157 MPI_Init(&argc, &argv);
158 Kokkos::initialize(argc, argv);
159 int fail = 0, size = 1, rank = 0;
161 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
162 MPI_Comm_size(MPI_COMM_WORLD, &size);
163 IVec<kDim> gs{24, 20, 16};
164 std::array<bool, kDim> periodic{
true,
true,
true};
165 const long gCells = (long)gs[0] * gs[1] * gs[2];
168 BlockDecomposer<kDim> dec(
static_cast<std::size_t
>(size), gs);
169 GridHaloTopology<kDim> halo;
170 halo.buildTopology(dec, rank,
G, periodic, MPI_COMM_WORLD);
171 const auto& idx = halo.indexer();
172 const Index n = idx.numCellsInclGhost();
173 const auto eg = idx.sizeInclGhost(), og = idx.originInclGhost();
174 const C3 e{(int)eg[0], (
int)eg[1], (int)eg[2]};
175 GridHalo<double> dev;
177 Reduce red{e, MPI_COMM_WORLD};
179 CCField ox(
"ox", n), oy(
"oy", n),
181 Kokkos::deep_copy(ox, 1.0);
182 Kokkos::deep_copy(oy, 1.0);
183 Kokkos::deep_copy(oz, 1.0);
184 OpV AC(
"AC", n), AW(
"AW", n), AE(
"AE", n), AS(
"AS", n), AN(
"AN", n), AB(
"AB", n), AT(
"AT", n);
185 peclet::flow::buildCutcellOp(
AC, AW, AE, AS, AN, AB, AT, CCConst(ox), CCConst(oy), CCConst(oz),
186 e,
G, 1.0, 1.0, 1.0);
188 CCField b(
"b", n), x(
"x", n);
189 auto hb = Kokkos::create_mirror_view(b);
190 for (Index c = 0; c < n; ++c)
192 idx.forEachInner([&](
const IVec<kDim>& l) {
193 hb(idx.localMdToLocal(l)) =
source(l[0] + og[0], l[1] + og[1], l[2] + og[2], gs);
195 Kokkos::deep_copy(b, hb);
197 x, CCConst(b),
AC, AW, AE, AS, AN, AB, AT, e, [&](CCField v) { dev.exchange(v); }, red,
199 auto hx = Kokkos::create_mirror_view(x);
200 Kokkos::deep_copy(hx, x);
204 const C3 ge{(int)gs[0] + 2 *
G, (
int)gs[1] + 2 *
G, (int)gs[2] + 2 *
G};
205 const Index gn = (Index)ge.x * ge.y * ge.z;
206 CCField gox(
"gox", gn), goy(
"goy", gn), goz(
"goz", gn);
207 Kokkos::deep_copy(gox, 1.0);
208 Kokkos::deep_copy(goy, 1.0);
209 Kokkos::deep_copy(goz, 1.0);
210 OpV gAC(
"gAC", gn), gAW(
"gAW", gn), gAE(
"gAE", gn), gAS(
"gAS", gn), gAN(
"gAN", gn),
211 gAB(
"gAB", gn), gAT(
"gAT", gn);
213 CCConst(goz), ge,
G, 1.0, 1.0, 1.0);
214 CCField gb(
"gb", gn), gx(
"gx", gn);
215 auto hgb = Kokkos::create_mirror_view(gb);
216 for (Index c = 0; c < gn; ++c)
218 for (
int z = 0; z < gs[2]; ++z)
219 for (
int y = 0; y < gs[1]; ++y)
220 for (
int xx = 0; xx < gs[0]; ++xx)
221 hgb((
long)(xx +
G) + (
long)(y +
G) * ge.x + (
long)(z +
G) * (
long)ge.x * ge.y) =
223 Kokkos::deep_copy(gb, hgb);
224 Reduce gred{ge, MPI_COMM_SELF};
226 auto serialFill = [&](CCField f) {
228 long st[3] = {1, ge.x, (long)ge.x * ge.y};
229 int dims[3] = {ge.x, ge.y, ge.z};
230 int N3[3] = {(int)gs[0], (
int)gs[1], (int)gs[2]};
231 for (
int a = 0; a < 3; ++a) {
232 const int bb = (a + 1) % 3, cc = (a + 2) % 3;
233 const long sa = st[a], sb = st[bb], sc = st[cc];
236 Kokkos::parallel_for(
238 KOKKOS_LAMBDA(
int p0,
int p1) {
239 const long base = (long)p0 * sb + (
long)p1 * sc;
240 for (
int gl = 0; gl <
G; ++gl) {
241 ff(base + (
long)gl * sa) = ff(base + (
long)(gl +
N) * sa);
242 ff(base + (
long)(
G +
N + gl) * sa) = ff(base + (
long)(
G + gl) * sa);
248 cg(gx, CCConst(gb), gAC, gAW, gAE, gAS, gAN, gAB, gAT, ge, serialFill, gred, gCells,
CGIT);
249 auto hgx = Kokkos::create_mirror_view(gx);
250 Kokkos::deep_copy(hgx, gx);
252 double maxdiff = 0.0;
253 idx.forEachInner([&](
const IVec<kDim>& l) {
254 const int gxk = l[0] + og[0], gyk = l[1] + og[1], gzk = l[2] + og[2];
255 const double a = hx(idx.localMdToLocal(l));
257 hgx((
long)(gxk +
G) + (
long)(gyk +
G) * ge.x + (
long)(gzk +
G) * (
long)ge.x * ge.y);
258 const double d = std::fabs(a - r);
262 if (maxdiff > 1e-11) {
264 std::fprintf(stderr,
"[rank %d] max|distributed - serial CG| = %.3e\n", rank, maxdiff);
268 MPI_Allreduce(&fail, &totalFail, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
271 std::printf(
"OK (np=%d): distributed cut-cell pressure CG == serial reference\n", size);
273 std::fprintf(stderr,
"FAILED (np=%d): %d ranks differ\n", size, totalFail);
277 return totalFail == 0 ? 0 : 1;