90 BL_PROFILE(
"Operator::Fsmooth()");
92 amrex::Box domain(m_geom[amrlev][mglev].growPeriodicDomain(1));
93 domain.convert(amrex::IntVect::TheNodeVector());
95 int ncomp = b.nComp();
96 const bool relax_ghost_rows = relaxCoarseFineGhostRows();
97 int nghost = relax_ghost_rows ? 2 : 0;
100 amrex::MultiFab Ax(x.boxArray(), x.DistributionMap(), ncomp, nghost);
101 amrex::MultiFab Dx(x.boxArray(), x.DistributionMap(), ncomp, nghost);
102 amrex::MultiFab Rx(x.boxArray(), x.DistributionMap(), ncomp, nghost);
104 if (!m_diagonal_computed)
Util::Abort(
INFO,
"Operator::Diagonal() must be called before using Fsmooth");
108 for (
int ctr = 0; ctr < 2; ctr++)
110 Fapply(amrlev, mglev, Ax, x);
112 amrex::MultiFab::Copy(Dx, x, 0, 0, ncomp, nghost);
113 amrex::MultiFab::Multiply(Dx, *m_diag[amrlev][mglev], 0, 0, ncomp, nghost);
115 amrex::MultiFab::Copy(Rx, Ax, 0, 0, ncomp, nghost);
116 amrex::MultiFab::Subtract(Rx, Dx, 0, 0, ncomp, nghost);
118 for (MFIter mfi(x,
false); mfi.isValid(); ++mfi)
120 Box bx = mfi.grownnodaltilebox();
122 const auto xfab = x.array(mfi);
123 const auto bfab = b.const_array(mfi);
124 const auto Rxfab = Rx.const_array(mfi);
125 const auto diagfab = (*m_diag[amrlev][mglev]).const_array(mfi);
127 if (!relax_ghost_rows)
129 const Box cbx = mfi.nodaltilebox() & domain;
130 for (
int n = 0; n < ncomp; ++n)
132 amrex::LoopConcurrentOnCpu(cbx, [&] (
int i,
int j,
int k)
134 xfab(i,j,k,n) = (1. - m_omega) * xfab(i,j,k, n)
135 + m_omega * (bfab(i,j,k, n) - Rxfab(i,j,k, n))
143 for (
int n = 0; n < ncomp; n++)
146 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k)
150 if (!domain.contains(i,j,k))
154 else if ( !bx.strictly_contains(i,j,k))
156 xfab(i, j, k, n) = 0.0;
161 xfab(i,j,k,n) = (1. - omega) * xfab(i,j,k, n) + omega * (bfab(i,j,k, n) - Rxfab(i,j,k, n)) / diagfab(i,j,k,n);
166 amrex::Geometry geom = m_geom[amrlev][mglev];
167 x.setMultiGhost(
true);
168 x.FillBoundary(geom.periodicity());
169 nodalSync(amrlev, mglev, x);
281 BL_PROFILE(
"Operator::restriction()");
283 applyBC(amrlev, cmglev - 1, fine, BCMode::Homogeneous, StateMode::Solution);
285 amrex::Box cdomain = m_geom[amrlev][cmglev].growPeriodicDomain(1);
286 cdomain = cdomain.convert(amrex::IntVect::TheNodeVector());
288 bool need_parallel_copy = !amrex::isMFIterSafe(crse, fine);
290 if (need_parallel_copy) {
291 const BoxArray& ba = amrex::coarsen(fine.boxArray(), 2);
292 cfine.define(ba, fine.DistributionMap(), fine.nComp(), fine.nGrow());
295 MultiFab* pcrse = (need_parallel_copy) ? &cfine : &crse;
297 for (MFIter mfi(*pcrse, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
299 const Box& bx = mfi.grownnodaltilebox(-1,1) & cdomain;
301 amrex::Array4<const amrex::Real>
const& fdata = fine.array(mfi);
302 amrex::Array4<amrex::Real>
const& cdata = pcrse->array(mfi);
304 const Dim3 lo = amrex::lbound(bx), hi = amrex::ubound(bx);
307 for (
int n = 0; n < crse.nComp(); n++)
311 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int I,
int J,
int K) {
312 int i = 2 * I, j = 2 * J, k = 2 * K;
314 if ((I == lo.x || I == hi.x) &&
315 (J == lo.y || J == hi.y) &&
316 (K == lo.z || K == hi.z))
318 cdata(I, J, K, n) = fdata(i, j, k, n);
320 else if ((J == lo.y || J == hi.y) &&
321 (K == lo.z || K == hi.z))
323 cdata(I, J, K, n) = 0.25 * fdata(i - 1, j, k, n) + 0.5 * fdata(i, j, k, n) + 0.25 * fdata(i + 1, j, k, n);
325 else if ((K == lo.z || K == hi.z) &&
326 (I == lo.x || I == hi.x))
328 cdata(I, J, K, n) = 0.25 * fdata(i, j - 1, k, n) + 0.5 * fdata(i, j, k, n) + 0.25 * fdata(i, j + 1, k, n);
330 else if ((I == lo.x || I == hi.x) &&
331 (J == lo.y || J == hi.y))
333 cdata(I, J, K, n) = 0.25 * fdata(i, j, k - 1, n) + 0.5 * fdata(i, j, k, n) + 0.25 * fdata(i, j, k + 1, n);
335 else if (I == lo.x || I == hi.x)
338 (+fdata(i, j - 1, k - 1, n) + 2.0 * fdata(i, j, k - 1, n) + fdata(i, j + 1, k - 1, n)
339 + 2.0 * fdata(i, j - 1, k, n) + 4.0 * fdata(i, j, k, n) + 2.0 * fdata(i, j + 1, k, n)
340 + fdata(i, j - 1, k + 1, n) + 2.0 * fdata(i, j, k + 1, n) + fdata(i, j + 1, k + 1, n)) / 16.0;
342 else if (J == lo.y || J == hi.y)
345 (+fdata(i - 1, j, k - 1, n) + 2.0 * fdata(i - 1, j, k, n) + fdata(i - 1, j, k + 1, n)
346 + 2.0 * fdata(i, j, k - 1, n) + 4.0 * fdata(i, j, k, n) + 2.0 * fdata(i, j, k + 1, n)
347 + fdata(i + 1, j, k - 1, n) + 2.0 * fdata(i + 1, j, k, n) + fdata(i + 1, j, k + 1, n)) / 16.0;
349 else if (K == lo.z || K == hi.z)
352 (+fdata(i - 1, j - 1, k, n) + 2.0 * fdata(i, j - 1, k, n) + fdata(i + 1, j - 1, k, n)
353 + 2.0 * fdata(i - 1, j, k, n) + 4.0 * fdata(i, j, k, n) + 2.0 * fdata(i + 1, j, k, n)
354 + fdata(i - 1, j + 1, k, n) + 2.0 * fdata(i, j + 1, k, n) + fdata(i + 1, j + 1, k, n)) / 16.0;
358 (fdata(i - 1, j - 1, k - 1, n) + fdata(i - 1, j - 1, k + 1, n) + fdata(i - 1, j + 1, k - 1, n) + fdata(i - 1, j + 1, k + 1, n) +
359 fdata(i + 1, j - 1, k - 1, n) + fdata(i + 1, j - 1, k + 1, n) + fdata(i + 1, j + 1, k - 1, n) + fdata(i + 1, j + 1, k + 1, n)) / 64.0
361 (fdata(i, j - 1, k - 1, n) + fdata(i, j - 1, k + 1, n) + fdata(i, j + 1, k - 1, n) + fdata(i, j + 1, k + 1, n) +
362 fdata(i - 1, j, k - 1, n) + fdata(i + 1, j, k - 1, n) + fdata(i - 1, j, k + 1, n) + fdata(i + 1, j, k + 1, n) +
363 fdata(i - 1, j - 1, k, n) + fdata(i - 1, j + 1, k, n) + fdata(i + 1, j - 1, k, n) + fdata(i + 1, j + 1, k, n)) / 32.0
365 (fdata(i - 1, j, k, n) + fdata(i, j - 1, k, n) + fdata(i, j, k - 1, n) +
366 fdata(i + 1, j, k, n) + fdata(i, j + 1, k, n) + fdata(i, j, k + 1, n)) / 16.0
368 fdata(i, j, k, n) / 8.0;
373 if (need_parallel_copy) {
374 crse.ParallelCopy(cfine);
377 crse.setMultiGhost(
true);
378 crse.FillBoundary(Geom(amrlev,cmglev).periodicity());
379 nodalSync(amrlev, cmglev, crse);
384 BL_PROFILE(
"Operator::interpolation()");
385 amrex::Box fdomain = m_geom[amrlev][fmglev].growPeriodicDomain(2);
386 fdomain.convert(amrex::IntVect::TheNodeVector());
388 bool need_parallel_copy = !amrex::isMFIterSafe(crse, fine);
390 const MultiFab* cmf = &crse;
391 if (need_parallel_copy) {
392 const BoxArray& ba = amrex::coarsen(fine.boxArray(), 2);
393 cfine.define(ba, fine.DistributionMap(), crse.nComp(), crse.nGrow());
394 cfine.ParallelCopy(crse);
398 for (MFIter mfi(fine,
false); mfi.isValid(); ++mfi)
400 Box fine_bx = mfi.validbox() & fdomain;
402 const Box& course_bx = amrex::coarsen(fine_bx, 2);
403 const Box& tmpbx = amrex::refine(course_bx, 2);
405 tmpfab.resize(tmpbx, fine.nComp());
406 tmpfab.setVal<amrex::RunOn::Device>(0.0);
407 const amrex::FArrayBox& crsefab = (*cmf)[mfi];
409 amrex::Array4<const amrex::Real>
const& cdata = crsefab.const_array();
410 amrex::Array4<amrex::Real>
const& fdata = tmpfab.array();
412 for (
int n = 0; n < crse.nComp(); n++)
416 amrex::ParallelFor(fine_bx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) {
418 int I = i / 2, J = j / 2, K = k / 2;
420 if (i % 2 == 0 && j % 2 == 0 && k % 2 == 0)
421 fdata(i, j, k, n) = cdata(I, J, K, n);
422 else if (j % 2 == 0 && k % 2 == 0)
423 fdata(i, j, k, n) = 0.5 * (cdata(I, J, K, n) + cdata(I + 1, J, K, n));
424 else if (k % 2 == 0 && i % 2 == 0)
425 fdata(i, j, k, n) = 0.5 * (cdata(I, J, K, n) + cdata(I, J + 1, K, n));
426 else if (i % 2 == 0 && j % 2 == 0)
427 fdata(i, j, k, n) = 0.5 * (cdata(I, J, K, n) + cdata(I, J, K + 1, n));
429 fdata(i, j, k, n) = 0.25 * (cdata(I, J, K, n) + cdata(I, J + 1, K, n) +
430 cdata(I, J, K + 1, n) + cdata(I, J + 1, K + 1, n));
432 fdata(i, j, k, n) = 0.25 * (cdata(I, J, K, n) + cdata(I, J, K + 1, n) +
433 cdata(I + 1, J, K, n) + cdata(I + 1, J, K + 1, n));
435 fdata(i, j, k, n) = 0.25 * (cdata(I, J, K, n) + cdata(I + 1, J, K, n) +
436 cdata(I, J + 1, K, n) + cdata(I + 1, J + 1, K, n));
438 fdata(i, j, k, n) = 0.125 * (cdata(I, J, K, n) +
439 cdata(I + 1, J, K, n) + cdata(I, J + 1, K, n) + cdata(I, J, K + 1, n) +
440 cdata(I, J + 1, K + 1, n) + cdata(I + 1, J, K + 1, n) + cdata(I + 1, J + 1, K, n) +
441 cdata(I + 1, J + 1, K + 1, n));
445 fine[mfi].plus<amrex::RunOn::Device>(tmpfab, fine_bx, fine_bx, 0, 0, fine.nComp());
448 fine.setMultiGhost(
true);
449 fine.FillBoundary(Geom(amrlev,fmglev).periodicity());
450 nodalSync(amrlev, fmglev, fine);
468 const MultiFab& crse, IntVect
const& nghost)
const
470 BL_PROFILE(
"Operator::interpolationAmr()");
471 if (!useQuadraticAmrInterpolation())
473 amrex::MLNodeLinOp::interpolationAmr(famrlev, fine, crse, nghost);
477 const int ncomp = getNComp();
479 for (MFIter mfi(fine,
false); mfi.isValid(); ++mfi)
481 Box fbx = mfi.tilebox();
482 const Box valid = mfi.validbox();
484 const Dim3 vlo = amrex::lbound(valid), vhi = amrex::ubound(valid);
485 Array4<Real>
const& ffab = fine.array(mfi);
486 Array4<Real const>
const& cfab = crse.const_array(mfi);
488 amrex::LoopConcurrentOnCpu(fbx, ncomp,
489 [=] (
int i,
int j,
int k,
int n)
493 int nc[3] = {1, 1, 1};
494 cw[0][0] = cw[1][0] = cw[2][0] = 1.0;
496 const int fi[3] = {i, j, k};
497 const int flo[3] = {vlo.x, vlo.y, vlo.z};
498 const int fhi[3] = {vhi.x, vhi.y, vhi.z};
499 for (
int d = 0; d < AMREX_SPACEDIM; ++d)
501 const int q = fi[d] >= 0 ? fi[d] / 2 : (fi[d] - 1) / 2;
506 else if (fi[d] < flo[d])
509 ci[d][0] = q; cw[d][0] = 3.0 / 8.0;
510 ci[d][1] = q + 1; cw[d][1] = 3.0 / 4.0;
511 ci[d][2] = q + 2; cw[d][2] = -1.0 / 8.0;
513 else if (fi[d] > fhi[d])
516 ci[d][0] = q - 1; cw[d][0] = -1.0 / 8.0;
517 ci[d][1] = q; cw[d][1] = 3.0 / 4.0;
518 ci[d][2] = q + 1; cw[d][2] = 3.0 / 8.0;
523 ci[d][0] = q; cw[d][0] = 0.5;
524 ci[d][1] = q + 1; cw[d][1] = 0.5;
529 for (
int a = 0; a < nc[0]; ++a)
530 for (
int b = 0; b < nc[1]; ++b)
531 for (
int c = 0; c < nc[2]; ++c)
532 value += cw[0][a] * cw[1][b] * cw[2][c]
533 * cfab(ci[0][a], ci[1][b], ci[2][c], n);
534 ffab(i, j, k, n) = value;
616 MultiFab& res,
const MultiFab& ,
const MultiFab& ,
617 MultiFab& fine_res, MultiFab& ,
const MultiFab& )
const
619 BL_PROFILE(
"Operator::Elastic::reflux()");
621 int ncomp = AMREX_SPACEDIM;
623 amrex::Box cdomain(m_geom[crse_amrlev][0].growPeriodicDomain(2));
624 cdomain.convert(amrex::IntVect::TheNodeVector());
626 const Geometry& cgeom = m_geom[crse_amrlev][0];
628 const BoxArray& fba = fine_res.boxArray();
629 const DistributionMapping& fdm = fine_res.DistributionMap();
631 MultiFab fine_res_for_coarse(amrex::coarsen(fba, 2), fdm, ncomp, 2);
632 fine_res_for_coarse.ParallelCopy(res, 0, 0, ncomp, 0, 0, cgeom.periodicity());
634 applyBC(crse_amrlev + 1, 0, fine_res, BCMode::Inhomogeneous, StateMode::Solution);
638 const int coarse_fine_node = 1;
639 const int fine_fine_node = 2;
641 amrex::iMultiFab nodemask(amrex::coarsen(fba, 2), fdm, 1, 2);
642 nodemask.ParallelCopy(*m_nd_fine_mask[crse_amrlev], 0, 0, 1, 0, 0, cgeom.periodicity());
644 for (MFIter mfi(fine_res_for_coarse,
false); mfi.isValid(); ++mfi)
646 const Box& bx = mfi.grownnodaltilebox(-1,1) & cdomain;
648 amrex::Array4<const int>
const& nmask = nodemask.array(mfi);
651 amrex::Array4<amrex::Real>
const& cdata = fine_res_for_coarse.array(mfi);
652 amrex::Array4<const amrex::Real>
const& fdata = fine_res.array(mfi);
654 const Dim3 lo = amrex::lbound(bx), hi = amrex::ubound(bx);
656 for (
int n = 0; n < fine_res.nComp(); n++)
660 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(
int I,
int J,
int K) {
661 int i = I * 2, j = J * 2, k = K * 2;
663 if (nmask(I, J, K) == fine_fine_node || nmask(I, J, K) == coarse_fine_node)
665 if ((I == lo.x || I == hi.x) &&
666 (J == lo.y || J == hi.y) &&
667 (K == lo.z || K == hi.z))
668 cdata(I, J, K, n) = fdata(i, j, k, n);
669 else if ((J == lo.y || J == hi.y) &&
670 (K == lo.z || K == hi.z))
671 cdata(I, J, K, n) = 0.25 * fdata(i - 1, j, k, n) + 0.5 * fdata(i, j, k, n) + 0.25 * fdata(i + 1, j, k, n);
672 else if ((K == lo.z || K == hi.z) &&
673 (I == lo.x || I == hi.x))
674 cdata(I, J, K, n) = 0.25 * fdata(i, j - 1, k, n) + 0.5 * fdata(i, j, k, n) + 0.25 * fdata(i, j + 1, k, n);
675 else if ((I == lo.x || I == hi.x) &&
676 (J == lo.y || J == hi.y))
677 cdata(I, J, K, n) = 0.25 * fdata(i, j, k - 1, n) + 0.5 * fdata(i, j, k, n) + 0.25 * fdata(i, j, k + 1, n);
678 else if (I == lo.x || I == hi.x)
680 (+fdata(i, j - 1, k - 1, n) + 2.0 * fdata(i, j, k - 1, n) + fdata(i, j + 1, k - 1, n)
681 + 2.0 * fdata(i, j - 1, k, n) + 4.0 * fdata(i, j, k, n) + 2.0 * fdata(i, j + 1, k, n)
682 + fdata(i, j - 1, k + 1, n) + 2.0 * fdata(i, j, k + 1, n) + fdata(i, j + 1, k + 1, n)) / 16.0;
683 else if (J == lo.y || J == hi.y)
685 (+fdata(i - 1, j, k - 1, n) + 2.0 * fdata(i - 1, j, k, n) + fdata(i - 1, j, k + 1, n)
686 + 2.0 * fdata(i, j, k - 1, n) + 4.0 * fdata(i, j, k, n) + 2.0 * fdata(i, j, k + 1, n)
687 + fdata(i + 1, j, k - 1, n) + 2.0 * fdata(i + 1, j, k, n) + fdata(i + 1, j, k + 1, n)) / 16.0;
688 else if (K == lo.z || K == hi.z)
690 (+fdata(i - 1, j - 1, k, n) + 2.0 * fdata(i, j - 1, k, n) + fdata(i + 1, j - 1, k, n)
691 + 2.0 * fdata(i - 1, j, k, n) + 4.0 * fdata(i, j, k, n) + 2.0 * fdata(i + 1, j, k, n)
692 + fdata(i - 1, j + 1, k, n) + 2.0 * fdata(i, j + 1, k, n) + fdata(i + 1, j + 1, k, n)) / 16.0;
695 (fdata(i - 1, j - 1, k - 1, n) + fdata(i - 1, j - 1, k + 1, n) + fdata(i - 1, j + 1, k - 1, n) + fdata(i - 1, j + 1, k + 1, n) +
696 fdata(i + 1, j - 1, k - 1, n) + fdata(i + 1, j - 1, k + 1, n) + fdata(i + 1, j + 1, k - 1, n) + fdata(i + 1, j + 1, k + 1, n)) / 64.0
698 (fdata(i, j - 1, k - 1, n) + fdata(i, j - 1, k + 1, n) + fdata(i, j + 1, k - 1, n) + fdata(i, j + 1, k + 1, n) +
699 fdata(i - 1, j, k - 1, n) + fdata(i + 1, j, k - 1, n) + fdata(i - 1, j, k + 1, n) + fdata(i + 1, j, k + 1, n) +
700 fdata(i - 1, j - 1, k, n) + fdata(i - 1, j + 1, k, n) + fdata(i + 1, j - 1, k, n) + fdata(i + 1, j + 1, k, n)) / 32.0
702 (fdata(i - 1, j, k, n) + fdata(i, j - 1, k, n) + fdata(i, j, k - 1, n) +
703 fdata(i + 1, j, k, n) + fdata(i, j + 1, k, n) + fdata(i, j, k + 1, n)) / 16.0
705 fdata(i, j, k, n) / 8.0;
714 res.ParallelCopy(fine_res_for_coarse, 0, 0, ncomp, 0, 0, cgeom.periodicity());
717 res.setMultiGhost(
true);
718 res.FillBoundaryAndSync(Geom(crse_amrlev).periodicity());
719 nodalSync(crse_amrlev, 0, res);