1#ifndef AMREX_ML_LINOP_H_
2#define AMREX_ML_LINOP_H_
3#include <AMReX_Config.H>
5#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
10#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
124template <
typename T>
class MLMGT;
125template <
typename T>
class MLCGSolverT;
126template <
typename T>
class MLPoissonT;
127template <
typename T>
class MLABecLaplacianT;
128template <
typename T>
class GMRESMLMGT;
137template <
typename MF>
142 template <
typename T>
friend class MLMGT;
181 bool eb_limit_coarsening =
true);
183 [[nodiscard]]
virtual std::string
name ()
const {
return std::string(
"Unspecified"); }
259 template <
typename AMF>
260 requires (!std::same_as<MF,AMF>)
264 template <
typename AMF>
265 requires (!std::same_as<MF,AMF>)
291 const MF* =
nullptr) = 0;
293 template <MultiFabLike AMF>
294 requires (!std::same_as<MF,AMF>)
296 const AMF* robinbc_a =
nullptr,
297 const AMF* robinbc_b =
nullptr,
298 const AMF* robinbc_f =
nullptr);
350 RT eps_rel,
RT eps_abs,
int maxiter)
357 [[nodiscard]]
virtual int getNComp ()
const {
return 1; }
359 [[nodiscard]]
virtual int getNGrow (
int = 0,
int = 0)
const {
return 0; }
398 amrex::Abort(
"MLLinOpT::interpAssign: Must be implemented for FMG cycle");
413 amrex::Abort(
"MLLinOpT::interpolationAmr: Must be implemented for composite solves across multiple AMR levels");
426 const MF& fine_sol,
const MF& fine_rhs)
429 amrex::Abort(
"MLLinOpT::averageDownSolutionRHS: Must be implemented for composite solves across multiple AMR levels");
443 virtual void apply (
int amrlev,
int mglev, MF& out, MF& in,
BCMode bc_mode,
456 virtual void smooth (
int amrlev,
int mglev, MF& sol,
const MF& rhs,
457 bool skip_fillboundary,
int niter)
const = 0;
466 virtual void normalize (
int amrlev,
int mglev, MF& mf)
const {
480 const MF* crse_bcdata=
nullptr) = 0;
504 BCMode bc_mode,
const MF* crse_bcdata=
nullptr) = 0;
518 MF& res,
const MF& crse_sol,
const MF& crse_rhs,
519 MF& fine_res, MF& fine_sol,
const MF& fine_rhs)
const
523 amrex::Abort(
"MLLinOpT::reflux: Must be implemented for composite solves across multiple AMR levels");
538 amrex::Abort(
"AMReX_MLLinOp::compFlux::How did we get here?");
553 amrex::Abort(
"AMReX_MLLinOp::compGrad::How did we get here?");
614 [[nodiscard]]
virtual bool scaleRHS (
int amrlev, MF* rhs)
const {
628 MF
const& rhs)
const {
669 amrex::Warning(
"This function might need to be implemented for GMRES to work with this LinOp.");
673 [[nodiscard]]
virtual bool isSingular (
int amrlev)
const = 0;
686 virtual RT xdoty (
int amrlev,
int mglev,
const MF&
x,
const MF&
y,
bool local)
const = 0;
712 virtual std::unique_ptr<MLLinOpT<MF>>
makeNLinOp (
int grid_size)
const
715 amrex::Abort(
"MLLinOp::makeNLinOp: NSolve not supported");
730 amrex::Abort(
"MLLinOp::getFluxes: How did we get here?");
741 amrex::Abort(
"MLLinOp::getFluxes: How did we get here?");
754 amrex::Abort(
"MLLinOp::getEBFluxes: How did we get here?");
762 [[nodiscard]]
virtual std::unique_ptr<MLAlgMG>
makeAlgMG (
int mglev)
const {
764 amrex::Abort(
"MLLinOp::makeAlgMG: not supported by this operator");
789#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
797 amrex::Abort(
"MLLinOp::makeHypre: How did we get here?");
806 [[nodiscard]]
virtual std::unique_ptr<HypreNodeLap> makeHypreNodeLap(
808 const std::string& options_namespace)
const
811 amrex::Abort(
"MLLinOp::makeHypreNodeLap: How did we get here?");
816#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
820 [[nodiscard]]
virtual std::unique_ptr<PETScABecLap> makePETSc ()
const {
821 amrex::Abort(
"MLLinOp::makePETSc: How did we get here?");
857 [[nodiscard]]
virtual RT normInf (
int amrlev, MF
const& mf,
bool local)
const = 0;
869 amrex::Abort(
"MLLinOpT::avgDownResAmr: Must be implemented for composite solves across multiple AMR levels");
897 [[nodiscard]]
bool isMFIterSafe (
int amrlev,
int mglev1,
int mglev2)
const;
911 [[nodiscard]]
const Geometry&
Geom (
int amr_lev,
int mglev=0) const noexcept {
return m_geom[amr_lev][mglev]; }
965 struct CommContainer {
967 CommContainer (
MPI_Comm m) noexcept : comm(m) {}
968 CommContainer (
const CommContainer&) =
delete;
969 CommContainer (CommContainer&&) =
delete;
970 void operator= (
const CommContainer&) =
delete;
971 void operator= (CommContainer&&) =
delete;
974 if (comm != MPI_COMM_NULL) { MPI_Comm_free(&comm); }
1050 [[nodiscard]]
virtual MF
make (
int amrlev,
int mglev,
IntVect const& ng)
const;
1053 [[nodiscard]]
virtual MF
make (
int amrlev,
int mglev,
IntVect const& ng,
1054 MFInfo const& mf_info)
const;
1063 MFInfo const& mf_info)
const;
1070 MFInfo const& mf_info)
const;
1072 [[nodiscard]]
virtual std::unique_ptr<FabFactory<FAB> >
makeFactory (
int ,
int )
const {
1073 return std::make_unique<DefaultFabFactory<FAB>>();
1084 defineCoarseMGLevels();
1091 template <
typename T>
1095 return Array4<T>(a.dataPtr(), {a.begin[1],a.begin[2],0}, {a.end[1],a.end[2],1}, a.nComp());
1097 return Array4<T>(a.dataPtr(), {a.begin[0],a.begin[2],0}, {a.end[0],a.end[2],1}, a.nComp());
1099 return Array4<T>(a.dataPtr(), {a.begin[0],a.begin[1],0}, {a.end[0],a.end[1],1}, a.nComp());
1105 template <
typename T>
1106 [[nodiscard]] T
get_d0 (T
const& dx, T
const& dy, T
const&)
const noexcept
1115 template <
typename T>
1116 [[nodiscard]] T
get_d1 (T
const&, T
const& dy, T
const& dz)
const noexcept
1132 void defineCoarseMGLevels ();
1135 int ratio,
int strategy);
1138 virtual void checkPoint (std::string
const& )
const {
1142 Vector<std::unique_ptr<MF>> levelbc_raii;
1143 Vector<std::unique_ptr<MF>> robin_a_raii;
1144 Vector<std::unique_ptr<MF>> robin_b_raii;
1145 Vector<std::unique_ptr<MF>> robin_f_raii;
1148template <
typename MF>
1155 [[maybe_unused]]
bool eb_limit_coarsening)
1164 if (info.con_grid_size <= 0) { info.con_grid_size =
AMREX_D_PICK(32, 16, 8); }
1174 if (!a_factory.empty() && eb_limit_coarsening) {
1177 info.max_coarsening_level = std::min(info.max_coarsening_level,
1178 f->maxCoarseningLevel());
1182 m_mg_deferred = supportsAnisotropicCoarsening();
1184 defineGrids(a_geom, a_grids, a_dmap, a_factory);
1188template <
typename MF>
1198 if ( ! a_factory.empty() ) {
1200 if (ebf && !(ebf->isAllRegular())) {
1201 mg_domain_min_width = 4;
1206 m_num_amr_levels = 0;
1207 for (
int amrlev = 0; amrlev < std::ssize(a_geom); amrlev++) {
1208 if (!a_grids[amrlev].empty()) {
1213 m_amr_ref_ratio.resize(m_num_amr_levels);
1214 m_num_mg_levels.resize(m_num_amr_levels);
1220 m_domain_covered.clear();
1221 mg_coarsen_ratio_vec.clear();
1223 m_geom.resize(m_num_amr_levels);
1224 m_grids.resize(m_num_amr_levels);
1225 m_dmap.resize(m_num_amr_levels);
1226 m_factory.resize(m_num_amr_levels);
1230 const RealBox& rb = a_geom[0].ProbDomain();
1231 const int coord = a_geom[0].Coord();
1232 const Array<int,AMREX_SPACEDIM>& is_per = a_geom[0].isPeriodic();
1234 IntVect mg_coarsen_ratio_v(mg_coarsen_ratio);
1235 if (hasHiddenDimension()) {
1237 "Hidden direction only supported for 3d");
1238 mg_coarsen_ratio_v[info.hidden_direction] = 1;
1242 for (
int amrlev = m_num_amr_levels-1; amrlev > 0; --amrlev)
1244 m_num_mg_levels[amrlev] = 1;
1245 m_geom[amrlev].push_back(a_geom[amrlev]);
1246 m_grids[amrlev].push_back(a_grids[amrlev]);
1247 m_dmap[amrlev].push_back(a_dmap[amrlev]);
1248 if (amrlev < std::ssize(a_factory)) {
1249 m_factory[amrlev].emplace_back(a_factory[amrlev]->clone());
1251 m_factory[amrlev].push_back(std::make_unique<DefaultFabFactory<FAB>>());
1254 IntVect rr = mg_coarsen_ratio_v;
1255 const Box& dom = a_geom[amrlev].Domain();
1256 for (
int i = 0; i < 2; ++i)
1258 if (!dom.coarsenable(rr)) {
amrex::Abort(
"MLLinOp: Uncoarsenable domain"); }
1261 if (cdom == a_geom[amrlev-1].Domain()) {
break; }
1263 ++(m_num_mg_levels[amrlev]);
1265 m_geom[amrlev].emplace_back(cdom, rb, coord, is_per);
1267 m_grids[amrlev].push_back(a_grids[amrlev]);
1269 m_grids[amrlev].back().coarsen(rr);
1271 m_dmap[amrlev].push_back(a_dmap[amrlev]);
1273 rr *= mg_coarsen_ratio_v;
1276#if (AMREX_SPACEDIM > 1)
1277 if (hasHiddenDimension()) {
1278 m_amr_ref_ratio[amrlev-1] = rr[(info.hidden_direction+1) % AMREX_SPACEDIM];
1282 m_amr_ref_ratio[amrlev-1] = rr[0];
1287 m_num_mg_levels[0] = 1;
1288 m_geom[0].push_back(a_geom[0]);
1289 m_grids[0].push_back(a_grids[0]);
1290 m_dmap[0].push_back(a_dmap[0]);
1291 if (!a_factory.empty()) {
1292 m_factory[0].emplace_back(a_factory[0]->clone());
1294 m_factory[0].push_back(std::make_unique<DefaultFabFactory<FAB>>());
1297 m_domain_covered.resize(m_num_amr_levels,
false);
1298 auto npts0 = m_grids[0][0].numPts();
1299 m_domain_covered[0] = (npts0 == compactify(m_geom[0][0].Domain()).numPts());
1300 for (
int amrlev = 1; amrlev < m_num_amr_levels; ++amrlev)
1302 if (!m_domain_covered[amrlev-1]) {
break; }
1303 m_domain_covered[amrlev] = (m_grids[amrlev][0].numPts() ==
1304 compactify(m_geom[amrlev][0].Domain()).numPts());
1307 if (m_mg_deferred) {
1309 m_bottom_comm = m_default_comm;
1310 m_do_agglomeration =
false;
1311 m_do_consolidation =
false;
1313 defineCoarseMGLevels();
1316 for (
int amrlev = 1; amrlev < m_num_amr_levels; ++amrlev)
1318 for (
int mglev = 1; mglev < m_num_mg_levels[amrlev]; ++mglev)
1320 m_factory[amrlev].emplace_back(makeFactory(amrlev,mglev));
1324 for (
int amrlev = 1; amrlev < m_num_amr_levels; ++amrlev)
1327 "MLLinOp: grids not coarsenable between AMR levels");
1331template <
typename MF>
1333MLLinOpT<MF>::defineCoarseMGLevels ()
1335 BL_PROFILE(
"MLLinOp::defineCoarseMGLevels()");
1337 AMREX_ASSERT(m_grids[0].size() == 1 && mg_coarsen_ratio_vec.empty());
1340 Geometry
const geom0 = m_geom[0][0];
1341 BoxArray
const ba0 = m_grids[0][0];
1342 DistributionMapping
const dm0 = m_dmap[0][0];
1344 const RealBox& rb = geom0.ProbDomain();
1345 const int coord = geom0.Coord();
1346 const Array<int,AMREX_SPACEDIM>& is_per = geom0.isPeriodic();
1347 auto const npts0 = ba0.numPts();
1349 IntVect mg_coarsen_ratio_v(mg_coarsen_ratio);
1350 IntVect mg_box_min_width_v(mg_box_min_width);
1351 IntVect mg_domain_min_width_v(mg_domain_min_width);
1352 if (hasHiddenDimension()) {
1353 mg_coarsen_ratio_v[info.hidden_direction] = 1;
1354 mg_box_min_width_v[info.hidden_direction] = 0;
1355 mg_domain_min_width_v[info.hidden_direction] = 0;
1359 bool aggable =
false;
1361 if (ba0.size() > 1 && info.do_agglomeration)
1363 if (m_domain_covered[0])
1365 aggbox = geom0.Domain();
1366 if (hasHiddenDimension()) {
1367 aggbox.
makeSlab(hiddenDirection(), ba0[0].smallEnd(hiddenDirection()));
1373 aggbox = ba0.minimalBox();
1374 aggable = (aggbox.numPts() == npts0);
1380 int agg_lev = 0, con_lev = 0;
1383 && (info.semicoarsening_direction == -1 ||
1384 info.semicoarsening_direction == info.hidden_direction))
1385 && info.semicoarsening_direction >= -1
1386 && info.semicoarsening_direction < AMREX_SPACEDIM );
1390 bool const aniso_coarsening = supportsAnisotropicCoarsening() && !hasHiddenDimension()
1391 && !(info.do_semicoarsening && info.semicoarsening_direction != -1);
1392 auto const dx0 = anisotropicCoarseningCellSize(geom0);
1395 IntVect rr = mg_coarsen_ratio_v;
1396 if (aniso_coarsening) {
1397 Real dxmin = std::numeric_limits<Real>::max();
1398 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1399 dxmin = std::min(dxmin, dx0[idim]*
Real(accum[idim]));
1401 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1402 if (dx0[idim]*
Real(accum[idim]) >=
Real(1.5)*dxmin) { rr[idim] = 1; }
1408 if (info.do_agglomeration && aggable)
1410 Box dbx = geom0.Domain();
1412 Real const nbxs =
static_cast<Real>(ba0.size());
1414 *info.agg_grid_size,
1415 *info.agg_grid_size);
1416 Vector<Box> domainboxes{dbx};
1417 Vector<Box> boundboxes{bbx};
1418 Vector<int> agg_flag{
false};
1419 Vector<IntVect> accum_coarsen_ratio{
IntVect(1)};
1422 for (
int lev = 0; lev < info.max_coarsening_level; ++lev)
1424 IntVect const rr_base = base_ratio(accum_coarsen_ratio.back());
1426 bool const do_semicoarsening_level = info.do_semicoarsening
1427 && numsclevs < info.max_semicoarsening_level;
1428 if (do_semicoarsening_level
1429 && info.semicoarsening_direction != -1)
1431 rr_level[info.semicoarsening_direction] = 1;
1434 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1436 rr_dir[idim] = rr_level[idim];
1438 bool const fit_ba0 = mg_odd_coarsening && lev == 0;
1439 is_coarsenable[idim] = dbx.coarsenable(rr_dir, mg_domain_min_width_v)
1440 && bbx.coarsenable(rr_dir, mg_box_min_width_v)
1441 && (!fit_ba0 || ba0.coarsenable(rr_dir, mg_box_min_width_v));
1442 for (
int r : {3, 5}) {
1443 if (is_coarsenable[idim] || !mg_odd_coarsening || rr_level[idim] != 2) {
1447 if (dbx.coarsenable(rr_dir, mg_domain_min_width_v)
1448 && bbx.coarsenable(rr_dir, mg_box_min_width_v)
1449 && (!fit_ba0 || ba0.coarsenable(rr_dir, mg_box_min_width_v)))
1451 is_coarsenable[idim] =
true;
1455 if (!is_coarsenable[idim] && do_semicoarsening_level
1456 && info.semicoarsening_direction == -1)
1458 is_coarsenable[idim] =
true;
1462 if (mg_independent_coarsening) {
1465 Real hmin = std::numeric_limits<Real>::max();
1466 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1467 if (is_coarsenable[idim] && rr_level[idim] > 1) {
1468 hmin = std::min(hmin, dx0[idim]*
Real(accum_coarsen_ratio.back()[idim]));
1471 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1472 if (!is_coarsenable[idim] || dx0[idim]*
Real(accum_coarsen_ratio.back()[idim]) >=
Real(1.5)*hmin) {
1473 is_coarsenable[idim] =
true;
1481 if (do_semicoarsening_level && info.semicoarsening_direction == -1) {
1483 int n_ones =
AMREX_D_TERM(
static_cast<int>(rr_level[0] == 1),
1484 +
static_cast<int>(rr_level[1] == 1),
1485 +
static_cast<int>(rr_level[2] == 1));
1486 if (n_ones > 1 && !aniso_coarsening) {
break; }
1488 bool semi_level =
false;
1489 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1490 semi_level = semi_level || (rr_level[idim] == 1 && rr_base[idim] != 1);
1496 accum_coarsen_ratio.push_back(accum_coarsen_ratio.back()*rr_level);
1497 domainboxes.push_back(dbx.coarsen(rr_level));
1498 boundboxes.push_back(bbx.coarsen(rr_level));
1499 bool to_agg = (bbx.d_numPts() / nbxs)
1500 <
Real(0.999)*
static_cast<Real>(threshold_npts);
1501 agg_flag.push_back(to_agg);
1504 for (
int lev = 1, nlevs =
static_cast<int>(domainboxes.size()); lev < nlevs; ++lev) {
1505 if (!agged && !agg_flag[lev] &&
1506 ba0.coarsenable(accum_coarsen_ratio[lev], mg_box_min_width_v))
1508 m_grids[0].push_back(
amrex::coarsen(ba0, accum_coarsen_ratio[lev]));
1509 m_dmap[0].push_back(dm0);
1511 IntVect cr = domainboxes[lev-1].length() / domainboxes[lev].length();
1512 if (!agged && lev > 1 && !m_grids[0].back().coarsenable(cr)) {
1515 m_grids[0].pop_back();
1516 m_dmap[0].pop_back();
1517 m_geom[0].pop_back();
1519 cr = domainboxes[lev-1].length() / domainboxes[lev].length();
1521 if (!m_grids[0].back().coarsenable(cr)) {
1524 m_grids[0].emplace_back(boundboxes[lev]);
1526 if (cell_box.numPts() > threshold_npts) {
1527 IntVect max_grid_size(info.agg_grid_size);
1528 if (info.do_semicoarsening && info.max_semicoarsening_level >= lev
1529 && info.semicoarsening_direction != -1)
1532 AMREX_D_TERM(
int mgs_0 = (max_grid_size[0]+blen[0]-1) / blen[0];,
1533 int mgs_1 = (max_grid_size[1]+blen[1]-1) / blen[1];,
1534 int mgs_2 = (max_grid_size[2]+blen[2]-1) / blen[2]);
1535 max_grid_size[info.semicoarsening_direction]
1538 if (mg_agg_no_split_direction >= 0 &&
1539 mg_agg_no_split_direction < AMREX_SPACEDIM)
1541 int const d = mg_agg_no_split_direction;
1542 max_grid_size[d] = std::max(max_grid_size[d], cell_box.length(d));
1546 IntVect const rn = (lev+1 < nlevs)
1547 ? domainboxes[lev].
length() / domainboxes[lev+1].length() :
IntVect(1);
1548 BoxArray& cba = m_grids[0].back();
1550 cba.maxSize((max_grid_size+rn-1)/rn);
1553 m_dmap[0].push_back(DistributionMapping());
1559 m_geom[0].emplace_back(domainboxes[lev],rb,coord,is_per);
1564 Long consolidation_threshold = 0;
1565 Real avg_npts = 0.0;
1566 if (info.do_consolidation) {
1569 *info.con_grid_size,
1570 *info.con_grid_size);
1573 Box const& dom0 = geom0.Domain();
1576 for (
int lev = 0; lev < info.max_coarsening_level; ++lev)
1578 IntVect const rr_base = base_ratio(rr_vec);
1580 bool do_semicoarsening_level = info.do_semicoarsening
1581 && numsclevs < info.max_semicoarsening_level;
1582 if (do_semicoarsening_level
1583 && info.semicoarsening_direction != -1)
1585 rr_level[info.semicoarsening_direction] = 1;
1588 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1590 rr_dir[idim] = rr_vec[idim] * rr_level[idim];
1591 is_coarsenable[idim] = dom0.coarsenable(rr_dir, mg_domain_min_width_v)
1592 && ba0.coarsenable(rr_dir, mg_box_min_width_v);
1593 for (
int r : {3, 5}) {
1594 if (is_coarsenable[idim] || !mg_odd_coarsening || rr_level[idim] != 2) {
1597 rr_dir[idim] = rr_vec[idim] * r;
1598 if (dom0.coarsenable(rr_dir, mg_domain_min_width_v)
1599 && ba0.coarsenable(rr_dir, mg_box_min_width_v))
1601 is_coarsenable[idim] =
true;
1605 if (!is_coarsenable[idim] && do_semicoarsening_level
1606 && info.semicoarsening_direction == -1)
1608 is_coarsenable[idim] =
true;
1612 if (mg_independent_coarsening) {
1615 Real hmin = std::numeric_limits<Real>::max();
1616 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1617 if (is_coarsenable[idim] && rr_level[idim] > 1) {
1618 hmin = std::min(hmin, dx0[idim]*
Real(rr_vec[idim]));
1621 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1622 if (!is_coarsenable[idim] || dx0[idim]*
Real(rr_vec[idim]) >=
Real(1.5)*hmin) {
1623 is_coarsenable[idim] =
true;
1631 if (do_semicoarsening_level && info.semicoarsening_direction == -1) {
1633 int n_ones =
AMREX_D_TERM(
static_cast<int>(rr_level[0] == 1),
1634 +
static_cast<int>(rr_level[1] == 1),
1635 +
static_cast<int>(rr_level[2] == 1));
1636 if (n_ones > 1 && !aniso_coarsening) {
break; }
1638 bool semi_level =
false;
1639 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1640 semi_level = semi_level || (rr_level[idim] == 1 && rr_base[idim] != 1);
1647 m_geom[0].emplace_back(
amrex::coarsen(dom0, rr_vec), rb, coord, is_per);
1650 if (info.do_consolidation)
1652 if (avg_npts/
static_cast<Real>(
AMREX_D_TERM(rr_vec[0], *rr_vec[1], *rr_vec[2]))
1653 <
Real(0.999)*
static_cast<Real>(consolidation_threshold))
1656 con_lev = m_dmap[0].size();
1657 m_dmap[0].push_back(DistributionMapping());
1661 m_dmap[0].push_back(m_dmap[0].back());
1666 m_dmap[0].push_back(dm0);
1671 m_num_mg_levels[0] = m_grids[0].size();
1673 for (
int mglev = 0; mglev < m_num_mg_levels[0] - 1; mglev++){
1674 const Box& fine_domain = m_geom[0][mglev].Domain();
1675 const Box& crse_domain = m_geom[0][mglev+1].Domain();
1676 mg_coarsen_ratio_vec.push_back(fine_domain.length()/crse_domain.length());
1679 for (
int amrlev = 0; amrlev < m_num_amr_levels; ++amrlev) {
1680 if (AMRRefRatio(amrlev) == 4 && mg_coarsen_ratio_vec.empty()) {
1681 mg_coarsen_ratio_vec.push_back(
IntVect(2));
1687 makeAgglomeratedDMap(m_grids[0], m_dmap[0]);
1691 makeConsolidatedDMap(m_grids[0], m_dmap[0], info.con_ratio, info.con_strategy);
1696 m_bottom_comm = makeSubCommunicator(m_dmap[0].back());
1700 m_bottom_comm = m_default_comm;
1703 m_do_agglomeration = agged;
1704 m_do_consolidation = coned;
1708 Print() <<
"MLLinOp::defineGrids(): agglomerated AMR level 0 starting at MG level "
1709 << agg_lev <<
" of " << m_num_mg_levels[0] <<
"\n";
1711 Print() <<
"MLLinOp::defineGrids(): consolidated AMR level 0 starting at MG level "
1712 << con_lev <<
" of " << m_num_mg_levels[0]
1713 <<
" (ratio = " << info.con_ratio <<
")" <<
"\n";
1715 Print() <<
"MLLinOp::defineGrids(): no agglomeration or consolidation of AMR level 0\n";
1719 for (
int mglev = 1; mglev < m_num_mg_levels[0]; ++mglev)
1721 m_factory[0].emplace_back(makeFactory(0,mglev));
1725template <
typename MF>
1729 if (m_mg_deferred && !m_mg_built) {
1737template <
typename MF>
1741 m_needs_coarse_data_for_bc = !m_domain_covered[0];
1743 levelbc_raii.resize(m_num_amr_levels);
1744 robin_a_raii.resize(m_num_amr_levels);
1745 robin_b_raii.resize(m_num_amr_levels);
1746 robin_f_raii.resize(m_num_amr_levels);
1749template <
typename MF>
1754 const int ncomp = getNComp();
1759template <
typename MF>
1764 const int ncomp = getNComp();
1766 "MLLinOp::setDomainBC: wrong size");
1769 m_lobc_orig = m_lobc;
1770 m_hibc_orig = m_hibc;
1771 for (
int icomp = 0; icomp < ncomp; ++icomp) {
1772 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1773 if (m_geom[0][0].isPeriodic(idim)) {
1775 m_hibc[icomp][idim] == BCType::Periodic);
1778 m_hibc[icomp][idim] != BCType::Periodic);
1795 if (hasHiddenDimension()) {
1796 const int hd = hiddenDirection();
1797 for (
int n = 0; n < ncomp; ++n) {
1803 if (hasInhomogNeumannBC() && !supportInhomogNeumannBC()) {
1804 amrex::Abort(
"Inhomogeneous Neumann BC not supported");
1806 if (hasRobinBC() && !supportRobinBC()) {
1811template <
typename MF>
1815 int ncomp = m_lobc_orig.size();
1816 for (
int n = 0; n < ncomp; ++n) {
1817 for (
int idim = 0; idim <AMREX_SPACEDIM; ++idim) {
1818 if (m_lobc_orig[n][idim] == bct || m_hibc_orig[n][idim] == bct) {
1826template <
typename MF>
1830 return hasBC(BCType::inhomogNeumann);
1833template <
typename MF>
1837 return hasBC(BCType::Robin);
1840template <
typename MF>
1844#if (AMREX_SPACEDIM == 3)
1845 if (info.hasHiddenDimension()) {
1847 const auto& hi = b.bigEnd();
1848 if (info.hidden_direction == 0) {
1850 }
else if (info.hidden_direction == 1) {
1862template <
typename MF>
1870 for (
int i = 1, N=
static_cast<int>(ba.
size()); i < N; ++i)
1880 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1882 for (
int ibox : sfc[iproc]) {
1886 dm[i].define(std::move(pmap));
1891template <
typename MF>
1893MLLinOpT<MF>::makeConsolidatedDMap (
const Vector<BoxArray>& ba,
1894 Vector<DistributionMapping>& dm,
1895 int ratio,
int strategy)
1897 BL_PROFILE(
"MLLinOp::makeConsolidatedDMap()");
1901 for (
int i = 1, N=
static_cast<int>(ba.size()); i < N; ++i)
1908 const auto& pmap_fine = dm[i-1].ProcessorMap();
1909 Vector<int> pmap(pmap_fine.size());
1911 if (strategy == 1) {
1912 for (
auto&
x: pmap) {
1915 }
else if (strategy == 2) {
1916 int nprocs_con =
static_cast<int>(std::ceil(
static_cast<Real>(nprocs)
1917 /
static_cast<Real>(factor)));
1918 for (
auto&
x: pmap) {
1919 auto d = std::div(
x,nprocs_con);
1922 }
else if (strategy == 3) {
1923 if (factor == ratio) {
1925 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1926 for (
int ibox : sfc[iproc]) {
1931 for (
auto&
x: pmap) {
1937 dm[i].define(std::move(pmap));
1939 Vector<int> pmap_g(pmap.size());
1941 dm[i].define(std::move(pmap_g));
1947template <
typename MF>
1949MLLinOpT<MF>::makeSubCommunicator (
const DistributionMapping& dm)
1951 BL_PROFILE(
"MLLinOp::makeSubCommunicator()");
1955 Vector<int> newgrp_ranks = dm.ProcessorMap();
1956 std::ranges::sort(newgrp_ranks);
1957 auto last = std::unique(newgrp_ranks.begin(), newgrp_ranks.end());
1958 newgrp_ranks.erase(last, newgrp_ranks.end());
1962 MPI_Comm_group(m_default_comm, &defgrp);
1964 MPI_Group_incl(defgrp,
static_cast<int>(newgrp_ranks.size()), newgrp_ranks.data(), &newgrp);
1966 Vector<int> local_newgrp_ranks(newgrp_ranks.size());
1968 newgrp_ranks.data(),
static_cast<int>(newgrp_ranks.size()));
1969 MPI_Group_incl(defgrp,
static_cast<int>(local_newgrp_ranks.size()), local_newgrp_ranks.data(), &newgrp);
1972 MPI_Comm_create(m_default_comm, newgrp, &newcomm);
1974 m_raii_comm = std::make_unique<CommContainer>(newcomm);
1976 MPI_Group_free(&defgrp);
1977 MPI_Group_free(&newgrp);
1982 return m_default_comm;
1986template <
typename MF>
1991 m_domain_bloc_lo = lo_bcloc;
1992 m_domain_bloc_hi = hi_bcloc;
1995template <
typename MF>
2000 setCoarseFineBC(
crse,
IntVect(crse_ratio), bc_type);
2003template <
typename MF>
2008 m_coarse_data_for_bc =
crse;
2009 m_coarse_data_crse_ratio = crse_ratio;
2010 m_coarse_fine_bc_type = bc_type;
2013template <
typename MF>
2014template <
typename AMF>
2015requires (!std::same_as<MF,AMF>)
2020 setCoarseFineBC(
crse,
IntVect(crse_ratio), bc_type);
2023template <
typename MF>
2024template <
typename AMF>
2025requires (!std::same_as<MF,AMF>)
2031 m_coarse_data_for_bc_raii = MF(
crse->boxArray(),
crse->DistributionMap(),
2033 m_coarse_data_for_bc_raii.LocalCopy(*
crse, 0, 0,
crse->nComp(),
2035 m_coarse_data_for_bc = &m_coarse_data_for_bc_raii;
2037 m_coarse_data_for_bc =
nullptr;
2039 m_coarse_data_crse_ratio = crse_ratio;
2040 m_coarse_fine_bc_type = bc_type;
2043template <
typename MF>
2048 mf.
resize(m_num_amr_levels);
2049 for (
int alev = 0; alev < m_num_amr_levels; ++alev) {
2050 mf[alev].resize(m_num_mg_levels[alev]);
2051 for (
int mlev = 0; mlev < m_num_mg_levels[alev]; ++mlev) {
2052 mf[alev][mlev] = make(alev, mlev, ng);
2057template <
typename MF>
2061 return make(amrlev, mglev, ng,
MFInfo());
2064template <
typename MF>
2068 if constexpr (IsMultiFabLike_v<MF>) {
2070 m_dmap[amrlev][mglev], getNComp(), ng, mf_info,
2071 *m_factory[amrlev][mglev]);
2079template <
typename MF>
2083 if constexpr (IsMultiFabLike_v<MF>) {
2087 amrex::Abort(
"MLLinOpT::makeAlias: how did we get here?");
2092template <
typename MF>
2096 return makeCoarseMG(amrlev, mglev, ng,
MFInfo());
2099template <
typename MF>
2102 MFInfo const& mf_info)
const
2104 if constexpr (IsMultiFabLike_v<MF>) {
2105 BoxArray cba = m_grids[amrlev][mglev];
2106 IntVect ratio = (amrlev > 0) ?
IntVect(2) : mg_coarsen_ratio_vec[mglev];
2107 if (hasHiddenDimension()) { ratio[hiddenDirection()] = 1; }
2110 return MF(cba, m_dmap[amrlev][mglev], getNComp(), ng, mf_info);
2113 amrex::Abort(
"MLLinOpT::makeCoarseMG: how did we get here?");
2118template <
typename MF>
2122 return makeCoarseAmr(famrlev, ng,
MFInfo());
2125template <
typename MF>
2129 if constexpr (IsMultiFabLike_v<MF>) {
2130 BoxArray cba = m_grids[famrlev][0];
2131 IntVect ratio(AMRRefRatioVect(famrlev-1));
2134 return MF(cba, m_dmap[famrlev][0], getNComp(), ng, mf_info);
2137 amrex::Abort(
"MLLinOpT::makeCoarseAmr: how did we get here?");
2142template <
typename MF>
2146 if (new_size <= 0 || new_size >= m_num_mg_levels[0]) {
return; }
2148 m_num_mg_levels[0] = new_size;
2150 m_geom[0].resize(new_size);
2151 m_grids[0].resize(new_size);
2152 m_dmap[0].resize(new_size);
2153 m_factory[0].resize(new_size);
2155 if (m_bottom_comm != m_default_comm) {
2156 m_bottom_comm = makeSubCommunicator(m_dmap[0].back());
2160template <
typename MF>
2166 const int ncomp = this->getNComp();
2168 if (!fres.isAllRegular()) {
2169 if constexpr (std::is_same<MF,MultiFab>()) {
2171 mg_coarsen_ratio_vec[clev-1]);
2173 amrex::Abort(
"EB_average_down only works with MultiFab");
2181 amrex::Abort(
"For non-FabArray, MLLinOpT<MF>::avgDownResMG should be overridden.");
2185template <
typename MF>
2189 return m_dmap[amrlev][mglev1] == m_dmap[amrlev][mglev2]
2193template <
typename MF>
2194template <MultiFabLike AMF>
2195requires (!std::same_as<MF,AMF>)
2198 const AMF* robinbc_a,
const AMF* robinbc_b,
2199 const AMF* robinbc_f)
2201 const int ncomp = this->getNComp();
2203 levelbc_raii[amrlev] = std::make_unique<MF>(levelbcdata->boxArray(),
2204 levelbcdata->DistributionMap(),
2205 ncomp, levelbcdata->nGrowVect());
2206 levelbc_raii[amrlev]->LocalCopy(*levelbcdata, 0, 0, ncomp,
2207 levelbcdata->nGrowVect());
2209 levelbc_raii[amrlev].reset();
2213 robin_a_raii[amrlev] = std::make_unique<MF>(robinbc_a->boxArray(),
2214 robinbc_a->DistributionMap(),
2215 ncomp, robinbc_a->nGrowVect());
2216 robin_a_raii[amrlev]->LocalCopy(*robinbc_a, 0, 0, ncomp,
2217 robinbc_a->nGrowVect());
2219 robin_a_raii[amrlev].reset();
2223 robin_b_raii[amrlev] = std::make_unique<MF>(robinbc_b->boxArray(),
2224 robinbc_b->DistributionMap(),
2225 ncomp, robinbc_b->nGrowVect());
2226 robin_b_raii[amrlev]->LocalCopy(*robinbc_b, 0, 0, ncomp,
2227 robinbc_b->nGrowVect());
2229 robin_b_raii[amrlev].reset();
2233 robin_f_raii[amrlev] = std::make_unique<MF>(robinbc_f->boxArray(),
2234 robinbc_f->DistributionMap(),
2235 ncomp, robinbc_f->nGrowVect());
2236 robin_f_raii[amrlev]->LocalCopy(*robinbc_f, 0, 0, ncomp,
2237 robinbc_f->nGrowVect());
2239 robin_f_raii[amrlev].reset();
2242 this->setLevelBC(amrlev, levelbc_raii[amrlev].
get(), robin_a_raii[amrlev].
get(),
2243 robin_b_raii[amrlev].
get(), robin_f_raii[amrlev].
get());
2246template <
typename MF>
2251 return xdoty(0,0,*
x[0],*
y[0],
false);
2254template <
typename MF>
2259 auto r = xdoty(0,0,*
x[0],*
x[0],
false);
2260 return std::sqrt(r);
Type-erased container that supports move-only types.
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#define BL_ASSERT(EX)
Definition AMReX_BLassert.H:39
#define AMREX_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:37
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
Infrastructure for storing per-face boundary data in FabSets.
Type trait that exposes the FAB and value types of MultiFab-like containers.
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1139
Array4< Real > fine
Definition AMReX_InterpFaceRegister.cpp:90
Array4< Real const > crse
Definition AMReX_InterpFaceRegister.cpp:92
GpuArray< MultiArray4< Real const >, 3 > s
Definition AMReX_MLEBNodeFDLaplacian.cpp:214
#define AMREX_D_TERM(a, b, c)
Definition AMReX_SPACE.H:172
#define AMREX_D_PICK(a, b, c)
Definition AMReX_SPACE.H:173
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
Reference-counted collection of Boxes.
Definition AMReX_BoxArray.H:681
static bool SameRefs(const BoxArray &lhs, const BoxArray &rhs)
whether two BoxArrays share the same data
Definition AMReX_BoxArray.H:1251
BoxArray & coarsen(int refinement_ratio)
Coarsen each Box in the BoxArray by refinement_ratio.
Definition AMReX_BoxArray.cpp:685
BoxArray & convert(IndexType typ)
Set the IndexType of the BoxArray.
Definition AMReX_BoxArray.cpp:829
__host__ __device__ BoxND & makeSlab(int direction, int slab_index) noexcept
Collapse the box to a single slab at coordinate slab_index along direction.
Definition AMReX_Box.H:860
__host__ __device__ const IntVectND< dim > & smallEnd() const &noexcept
Return the inclusive lower bound of the box.
Definition AMReX_Box.H:124
GpuArray< Real, 3 > CellSizeArray() const noexcept
Returns the cell sizes as a GpuArray for use on host or device.
Definition AMReX_CoordSys.H:85
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
static DistributionMapping makeSFC(const MultiFab &weight, bool sort=true)
Build an SFC map weighted by the sum of component 0 over each valid box of weight; sort enables load-...
Definition AMReX_DistributionMapping.cpp:1770
Definition AMReX_EBFabFactory.H:32
Abstract factory interface for creating, aliasing, and destroying FAB objects.
Definition AMReX_FabFactory.H:73
Solve using GMRES with multigrid as preconditioner.
Definition AMReX_GMRES_MLMG.H:28
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:85
Interface
HYPRE interface modes supported.
Definition AMReX_Hypre.H:70
__host__ static __device__ constexpr std::size_t size() noexcept
Definition AMReX_IntVect.H:846
__host__ __device__ constexpr IntVectND< new_dim > resize(int fill_extra=0) const noexcept
Returns a new IntVectND of size new_dim by either shrinking or expanding this IntVectND.
Definition AMReX_IntVect.H:889
Definition AMReX_MLABecLaplacian.H:22
CG-family solvers (BiCGStab or CG) for use as the bottom solver in MLMG.
Definition AMReX_MLCGSolver.H:21
Abstract base class for multilevel linear operators used by MLMG and the bottom solvers.
Definition AMReX_MLLinOp.H:139
virtual void copyNSolveSolution(MF &dst, MF const &src) const
Copy an NSolve solution from src to dst.
Definition AMReX_MLLinOp.H:837
const MF * m_coarse_data_for_bc
Definition AMReX_MLLinOp.H:988
bool mg_odd_coarsening
Definition AMReX_MLLinOp.H:927
virtual void postSolve(Vector< MF * > const &sol) const
Optional hook invoked after the main solve completes.
Definition AMReX_MLLinOp.H:846
Vector< Vector< std::unique_ptr< FabFactory< FAB > > > > m_factory
Definition AMReX_MLLinOp.H:959
virtual bool scaleRHS(int amrlev, MF *rhs) const
Optionally scale the RHS to fix solvability.
Definition AMReX_MLLinOp.H:614
bool m_mg_deferred
MG levels of AMR level 0 built at first solve.
Definition AMReX_MLLinOp.H:938
virtual void avgDownResMG(int clev, MF &cres, MF const &fres) const
Average residuals from fine to coarse MG levels (FMG helper).
Definition AMReX_MLLinOp.H:2162
int NAMRLevels() const noexcept
Return the number of AMR levels.
Definition AMReX_MLLinOp.H:900
bool m_do_consolidation
Definition AMReX_MLLinOp.H:950
bool isCellCentered() const noexcept
Definition AMReX_MLLinOp.H:1042
IntVect m_ixtype
Definition AMReX_MLLinOp.H:947
void setVerbose(int v) noexcept
Set verbosity.
Definition AMReX_MLLinOp.H:305
bool isMFIterSafe(int amrlev, int mglev1, int mglev2) const
Check whether mixing MFIter loops for different MG levels is safe.
Definition AMReX_MLLinOp.H:2187
RealVect m_coarse_bc_loc
Definition AMReX_MLLinOp.H:987
virtual bool needsUpdate() const
Does it need update if it's reused?
Definition AMReX_MLLinOp.H:362
virtual void interpolation(int amrlev, int fmglev, MF &fine, const MF &crse) const =0
Add interpolated coarse MG level data to fine MG level data.
virtual void setLevelBC(int, const MF *, const MF *=nullptr, const MF *=nullptr, const MF *=nullptr)=0
Set boundary conditions for given level. For cell-centered solves only.
virtual MF make(int amrlev, int mglev, IntVect const &ng) const
Definition AMReX_MLLinOp.H:2059
virtual void applyOverset(int amrlev, MF &rhs) const
Overset-only hook for zeroing regions covered by masks.
Definition AMReX_MLLinOp.H:603
FabFactory< FAB > const * Factory(int amr_lev, int mglev=0) const noexcept
Definition AMReX_MLLinOp.H:1006
void setDomainBC(const Vector< Array< BCType, 3 > > &lobc, const Vector< Array< BCType, 3 > > &hibc)
Boundary of the whole domain.
Definition AMReX_MLLinOp.H:1761
Array< Real, 3 > m_domain_bloc_hi
Definition AMReX_MLLinOp.H:982
T get_d0(T const &dx, T const &dy, T const &) const noexcept
Definition AMReX_MLLinOp.H:1106
MPI_Comm BottomCommunicator() const noexcept
Definition AMReX_MLLinOp.H:1033
void setEnforceSingularSolvable(bool o) noexcept
Control whether the solver should try to make singular problems solvable.
Definition AMReX_MLLinOp.H:328
MPI_Comm Communicator() const noexcept
Definition AMReX_MLLinOp.H:1034
void setPrintIndentation(std::string s)
Prefix printed messages (e.g., to indent per level).
Definition AMReX_MLLinOp.H:312
int mg_domain_min_width
Definition AMReX_MLLinOp.H:925
void setMaxOrder(int o) noexcept
Set order of interpolation at coarse/fine boundary.
Definition AMReX_MLLinOp.H:319
virtual void compGrad(int amrlev, const Array< MF *, 3 > &grad, MF &sol, Location loc) const
Compute gradients of the solution.
Definition AMReX_MLLinOp.H:549
virtual void interpAssign(int amrlev, int fmglev, MF &fine, MF &crse) const
Overwrite fine MG level data with interpolated coarse data.
Definition AMReX_MLLinOp.H:395
virtual std::string name() const
Definition AMReX_MLLinOp.H:183
GpuArray< BCType, 3 > LoBC(int icomp=0) const noexcept
Definition AMReX_MLLinOp.H:1010
virtual void getEBFluxes(const Vector< MF * > &a_flux, const Vector< MF * > &a_sol) const
Extract embedded-boundary fluxes.
Definition AMReX_MLLinOp.H:751
bool doAgglomeration() const noexcept
Definition AMReX_MLLinOp.H:1038
virtual bool supportCustomBottomSolver() const
Does this operator provide its own bottom solver (BottomSolver::custom)?
Definition AMReX_MLLinOp.H:336
virtual MF makeCoarseAmr(int famrlev, IntVect const &ng, MFInfo const &mf_info) const
As above, with caller-selected allocation metadata for temporary storage.
Definition AMReX_MLLinOp.H:2127
MF m_coarse_data_for_bc_raii
Definition AMReX_MLLinOp.H:989
MLLinOpT< MF > & operator=(const MLLinOpT< MF > &)=delete
int mg_box_min_width
Definition AMReX_MLLinOp.H:924
std::unique_ptr< CommContainer > m_raii_comm
Definition AMReX_MLLinOp.H:979
bool m_do_semicoarsening
Definition AMReX_MLLinOp.H:952
bool hasRobinBC() const noexcept
Definition AMReX_MLLinOp.H:1835
virtual std::unique_ptr< MLLinOpT< MF > > makeNLinOp(int grid_size) const
Create the NSolve counterpart of this operator with the requested grid size.
Definition AMReX_MLLinOp.H:712
Vector< Array< BCType, 3 > > m_hibc
Definition AMReX_MLLinOp.H:915
virtual void resizeMultiGrid(int new_size)
Definition AMReX_MLLinOp.H:2144
Vector< Vector< BoxArray > > m_grids
Definition AMReX_MLLinOp.H:957
virtual MF makeCoarseAmr(int famrlev, IntVect const &ng) const
Allocate an MF on the next coarser AMR level (famrlev-1) with grow cells ng.
Definition AMReX_MLLinOp.H:2120
bool m_do_agglomeration
Definition AMReX_MLLinOp.H:949
virtual MF makeAlias(MF const &mf) const
Definition AMReX_MLLinOp.H:2081
Array4< T > compactify(Array4< T > const &a) const noexcept
Definition AMReX_MLLinOp.H:1092
static constexpr int mg_coarsen_ratio
Definition AMReX_MLLinOp.H:923
virtual void solutionResidual(int amrlev, MF &resid, MF &x, const MF &b, const MF *crse_bcdata=nullptr)=0
Compute residual for solution.
int getMaxOrder() const noexcept
Get order of interpolation at coarse/fine boundary.
Definition AMReX_MLLinOp.H:321
virtual int getNComp() const
Return number of components.
Definition AMReX_MLLinOp.H:357
void setCoarseFineBCLocation(const RealVect &cloc) noexcept
Definition AMReX_MLLinOp.H:1036
Vector< int > m_amr_ref_ratio
Definition AMReX_MLLinOp.H:942
MPI_Comm m_default_comm
Definition AMReX_MLLinOp.H:962
virtual void unapplyMetricTerm(int amrlev, int mglev, MF &rhs) const
Remove metric scaling previously applied via applyMetricTerm().
Definition AMReX_MLLinOp.H:573
virtual void setDirichletNodesToZero(int amrlev, int mglev, MF &mf) const
Optional hook for masking out Dirichlet nodes or cells prior to GMRES solves; the default is a no-op ...
Definition AMReX_MLLinOp.H:665
bool isBottomActive() const noexcept
Definition AMReX_MLLinOp.H:1031
virtual void applyInhomogNeumannTerm(int amrlev, MF &rhs) const
Add extra terms introduced when treating inhomogeneous Neumann BC as homogeneous.
Definition AMReX_MLLinOp.H:593
virtual BottomSolver getDefaultBottomSolver() const
Definition AMReX_MLLinOp.H:333
virtual void prepareForFluxes(int amrlev, const MF *crse_bcdata=nullptr)
Ensure BC caches are populated before flux extraction.
Definition AMReX_MLLinOp.H:488
typename FabDataType< MF >::fab_type FAB
Definition AMReX_MLLinOp.H:149
virtual RT normInf(int amrlev, MF const &mf, bool local) const =0
Infinity norm helper used by residual reductions.
Vector< int > m_num_mg_levels
Definition AMReX_MLLinOp.H:944
bool hasBC(BCType bct) const noexcept
Definition AMReX_MLLinOp.H:1813
Vector< Vector< DistributionMapping > > m_dmap
Definition AMReX_MLLinOp.H:958
int verbose
Definition AMReX_MLLinOp.H:932
virtual MF make(int amrlev, int mglev, IntVect const &ng, MFInfo const &mf_info) const
As above, with caller-selected allocation metadata for temporary storage.
Definition AMReX_MLLinOp.H:2066
IntVect m_coarse_data_crse_ratio
Definition AMReX_MLLinOp.H:986
virtual void correctionResidual(int amrlev, int mglev, MF &resid, MF &x, const MF &b, BCMode bc_mode, const MF *crse_bcdata=nullptr)=0
Compute residual for the residual-correction form, resid = b - L(x)
virtual void customBottomSolve(MLMGT< MF > *mlmg, MF &x, const MF &b, RT eps_rel, RT eps_abs, int maxiter)
Bottom solve provided by the operator itself.
Definition AMReX_MLLinOp.H:349
const Vector< int > & AMRRefRatio() const noexcept
Return AMR refinement ratios.
Definition AMReX_MLLinOp.H:994
MLLinOpT(MLLinOpT< MF > &&)=delete
Vector< Array< BCType, 3 > > m_hibc_orig
Definition AMReX_MLLinOp.H:919
virtual void unimposeNeumannBC(int amrlev, MF &rhs) const
Undo Neumann contributions stored on the RHS.
Definition AMReX_MLLinOp.H:583
void setCoarseFineBC(const MF *crse, int crse_ratio, LinOpBCType bc_type=LinOpBCType::Dirichlet) noexcept
Set coarse/fine boundary conditions. For cell-centered solves only.
Definition AMReX_MLLinOp.H:1997
virtual void apply(int amrlev, int mglev, MF &out, MF &in, BCMode bc_mode, StateMode s_mode, const MLMGBndryT< MF > *bndry=nullptr) const =0
Apply the linear operator, out = L(in)
int mg_agg_no_split_direction
Definition AMReX_MLLinOp.H:926
std::string print_ident
Definition AMReX_MLLinOp.H:933
bool needsCoarseDataForBC() const noexcept
Needs coarse data for bc?
Definition AMReX_MLLinOp.H:230
typename FabDataType< MF >::value_type RT
Definition AMReX_MLLinOp.H:150
virtual void update()
Update for reuse.
Definition AMReX_MLLinOp.H:364
Vector< Array< BCType, 3 > > m_lobc_orig
Definition AMReX_MLLinOp.H:918
bool m_precond_mode
Definition AMReX_MLLinOp.H:991
virtual std::unique_ptr< FabFactory< FAB > > makeFactory(int, int) const
Definition AMReX_MLLinOp.H:1072
bool hasHiddenDimension() const noexcept
Definition AMReX_MLLinOp.H:1087
virtual bool isBottomSingular() const =0
Is the bottom of the multigrid hierarchy singular?
virtual void reflux(int crse_amrlev, MF &res, const MF &crse_sol, const MF &crse_rhs, MF &fine_res, MF &fine_sol, const MF &fine_rhs) const
Reflux at AMR coarse/fine boundary.
Definition AMReX_MLLinOp.H:517
virtual IntVect getNGrowVectRestriction() const
Definition AMReX_MLLinOp.H:1044
virtual std::unique_ptr< MLAlgMG > makeAlgMG(int mglev) const
Build the algebraic system of MG level mglev of AMR level 0 for the AlgMG solver. Operators that hypr...
Definition AMReX_MLLinOp.H:762
virtual bool supportsAnisotropicCoarsening() const
True if the operator supports MG levels coarsened in any subset of directions. Then MLMG coarsens str...
Definition AMReX_MLLinOp.H:779
virtual void compFlux(int amrlev, const Array< MF *, 3 > &fluxes, MF &sol, Location loc) const
Compute fluxes.
Definition AMReX_MLLinOp.H:534
virtual RT dotProductPrecond(Vector< MF const * > const &x, Vector< MF const * > const &y) const
Dot product over the composite AMR hierarchy, excluding cells covered by finer levels....
Definition AMReX_MLLinOp.H:2248
virtual MF makeCoarseMG(int amrlev, int mglev, IntVect const &ng) const
Allocate an MF on the next coarser MG level (mglev+1) with grow cells ng.
Definition AMReX_MLLinOp.H:2094
const Geometry & Geom(int amr_lev, int mglev=0) const noexcept
Geometry accessor for (amr_lev,mglev).
Definition AMReX_MLLinOp.H:911
virtual void endPrecondBC()
Called when the operator stops being used as a preconditioner.
Definition AMReX_MLLinOp.H:888
int hiddenDirection() const noexcept
Definition AMReX_MLLinOp.H:1088
void setDomainBCLoc(const Array< Real, 3 > &lo_bcloc, const Array< Real, 3 > &hi_bcloc) noexcept
Set location offsets for the physical domain boundaries.
Definition AMReX_MLLinOp.H:1988
Vector< Array< BCType, 3 > > m_lobc
Definition AMReX_MLLinOp.H:914
Vector< int > m_domain_covered
Definition AMReX_MLLinOp.H:960
void prepareMGHierarchy()
Build the deferred MG levels of AMR level 0 once. See supportsAnisotropicCoarsening.
Definition AMReX_MLLinOp.H:1727
const MLLinOpT< MF > * m_parent
Definition AMReX_MLLinOp.H:945
bool doSemicoarsening() const noexcept
Definition AMReX_MLLinOp.H:1040
virtual bool supportNSolve() const
Whether this operator supports NSolve.
Definition AMReX_MLLinOp.H:829
virtual bool supportRobinBC() const noexcept
Definition AMReX_MLLinOp.H:1025
virtual void normalize(int amrlev, int mglev, MF &mf) const
Divide mf by the diagonal component of the operator. Used by the bottom solvers.
Definition AMReX_MLLinOp.H:466
virtual void avgDownResAmr(int clev, MF &cres, MF const &fres) const
Definition AMReX_MLLinOp.H:866
Vector< Vector< Geometry > > m_geom
first Vector is for amr level and second is mg level
Definition AMReX_MLLinOp.H:956
virtual RT norm2Precond(Vector< MF const * > const &x) const
L2 norm over the composite AMR hierarchy, excluding cells covered by finer levels....
Definition AMReX_MLLinOp.H:2256
MLLinOpT(const MLLinOpT< MF > &)=delete
virtual void averageDownAndSync(Vector< MF > &sol) const =0
Average the solution hierarchy down (fine to coarse) and synchronize interfaces.
void setCoarseFineBC(const MF *crse, IntVect const &crse_ratio, LinOpBCType bc_type=LinOpBCType::Dirichlet) noexcept
Definition AMReX_MLLinOp.H:2005
virtual void getFluxes(const Vector< MF * > &a_flux, const Vector< MF * > &a_sol) const
Extract fluxes when the operator stores them in single MultiFabs per level.
Definition AMReX_MLLinOp.H:738
Box compactify(Box const &b) const noexcept
Definition AMReX_MLLinOp.H:1842
bool m_needs_coarse_data_for_bc
Definition AMReX_MLLinOp.H:984
virtual void fixSolvabilityByOffset(int amrlev, int mglev, MF &rhs, Vector< RT > const &offset) const
Subtract previously computed offsets from the RHS.
Definition AMReX_MLLinOp.H:641
GpuArray< BCType, 3 > HiBC(int icomp=0) const noexcept
Definition AMReX_MLLinOp.H:1015
int maxorder
Definition AMReX_MLLinOp.H:935
void define(const Vector< Geometry > &a_geom, const Vector< BoxArray > &a_grids, const Vector< DistributionMapping > &a_dmap, const LPInfo &a_info, const Vector< FabFactory< FAB > const * > &a_factory, bool eb_limit_coarsening=true)
Initialize the operator hierarchy on a set of AMR levels.
Definition AMReX_MLLinOp.H:1150
Vector< IntVect > mg_coarsen_ratio_vec
Definition AMReX_MLLinOp.H:953
virtual MF makeCoarseMG(int amrlev, int mglev, IntVect const &ng, MFInfo const &mf_info) const
As above, with caller-selected allocation metadata for temporary storage.
Definition AMReX_MLLinOp.H:2101
MF MFType
Definition AMReX_MLLinOp.H:148
virtual void preparePrecond()
Prepare auxiliary data used when the operator acts as a preconditioner.
Definition AMReX_MLLinOp.H:655
virtual ~MLLinOpT()=default
virtual void averageDownSolutionRHS(int camrlev, MF &crse_sol, MF &crse_rhs, const MF &fine_sol, const MF &fine_rhs)
Average-down data from fine AMR level to coarse AMR level.
Definition AMReX_MLLinOp.H:425
LPInfo info
Definition AMReX_MLLinOp.H:930
int NMGLevels(int amrlev) const noexcept
Return the number of MG levels at given AMR level.
Definition AMReX_MLLinOp.H:908
virtual Vector< RT > getSolvabilityOffset(int amrlev, int mglev, MF const &rhs) const
Compute offsets used to enforce solvability (per component).
Definition AMReX_MLLinOp.H:627
T get_d1(T const &, T const &dy, T const &dz) const noexcept
Definition AMReX_MLLinOp.H:1116
bool enforceSingularSolvable
Definition AMReX_MLLinOp.H:937
virtual RT xdoty(int amrlev, int mglev, const MF &x, const MF &y, bool local) const =0
Dot-product helper used by bottom solvers.
virtual void interpolationAmr(int famrlev, MF &fine, const MF &crse, IntVect const &nghost) const
Interpolation between AMR levels.
Definition AMReX_MLLinOp.H:409
bool doConsolidation() const noexcept
Definition AMReX_MLLinOp.H:1039
virtual bool supportInhomogNeumannBC() const noexcept
Definition AMReX_MLLinOp.H:1026
LinOpBCType m_coarse_fine_bc_type
Definition AMReX_MLLinOp.H:985
Array< Real, 3 > m_domain_bloc_lo
Definition AMReX_MLLinOp.H:981
virtual bool supportsAlgMG() const
True if makeAlgMG is implemented for this operator.
Definition AMReX_MLLinOp.H:769
bool m_mg_built
Definition AMReX_MLLinOp.H:939
virtual void buildMGHierarchy()
Build the MG levels of AMR level 0 below the finest one.
Definition AMReX_MLLinOp.H:1082
virtual bool isSingular(int amrlev) const =0
Is it singular on AMR level amrlev?
int AMRRefRatio(int amr_lev) const noexcept
Return AMR refinement ratio at given AMR level.
Definition AMReX_MLLinOp.H:997
MPI_Comm m_bottom_comm
Definition AMReX_MLLinOp.H:963
virtual void restriction(int amrlev, int cmglev, MF &crse, MF &fine) const =0
Restriction onto coarse MG level.
virtual void getFluxes(const Vector< Array< MF *, 3 > > &a_flux, const Vector< MF * > &a_sol, Location a_loc) const
Extract per-direction fluxes for each AMR level.
Definition AMReX_MLLinOp.H:726
virtual void beginPrecondBC()
Called when the operator starts being used as a preconditioner.
Definition AMReX_MLLinOp.H:884
virtual void applyMetricTerm(int amrlev, int mglev, MF &rhs) const
Apply metric scaling to the RHS on (amrlev,mglev).
Definition AMReX_MLLinOp.H:563
bool mg_independent_coarsening
Definition AMReX_MLLinOp.H:928
bool getEnforceSingularSolvable() const noexcept
Definition AMReX_MLLinOp.H:331
virtual void prepareForSolve()=0
Finalize coefficients, masks, and BC data before iterative solves.
IntVect AMRRefRatioVect(int amr_lev) const noexcept
Return AMR refinement ratio as IntVect (1 in hidden direction)
Definition AMReX_MLLinOp.H:1000
virtual void smooth(int amrlev, int mglev, MF &sol, const MF &rhs, bool skip_fillboundary, int niter) const =0
Smooth.
virtual GpuArray< Real, 3 > anisotropicCoarseningCellSize(Geometry const &geom) const
Cell size used to pick the directions to coarsen when supportsAnisotropicCoarsening() is true....
Definition AMReX_MLLinOp.H:787
virtual void make(Vector< Vector< MF > > &mf, IntVect const &ng) const
Definition AMReX_MLLinOp.H:2045
bool hasInhomogNeumannBC() const noexcept
Definition AMReX_MLLinOp.H:1828
void setDomainBC(const Array< BCType, 3 > &lobc, const Array< BCType, 3 > &hibc) noexcept
Boundary of the whole domain.
Definition AMReX_MLLinOp.H:1751
virtual int getNGrow(int=0, int=0) const
Definition AMReX_MLLinOp.H:359
int m_num_amr_levels
Definition AMReX_MLLinOp.H:941
Boundary helper for MLMG that manages coarse/fine and physical BC metadata.
Definition AMReX_MLMGBndry.H:20
Definition AMReX_MLMG.H:39
Cell-centered Laplacian operator \nabla^2 \phi.
Definition AMReX_MLPoisson.H:32
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
Long size() const noexcept
Definition AMReX_Vector.H:54
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:80
amrex_long Long
Definition AMReX_INT.H:30
__host__ __device__ Dim3 length(Array4< T > const &a) noexcept
Return the spatial extents of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1379
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a copy of b converted to the nodal flags typ.
Definition AMReX_Box.H:1630
__host__ __device__ BoxND< dim > coarsen(const BoxND< dim > &b, int ref_ratio) noexcept
Return a copy of b coarsened by the isotropic ratio ref_ratio.
Definition AMReX_Box.H:1469
__host__ __device__ BoxND< dim > enclosedCells(const BoxND< dim > &b, int dir) noexcept
Return a BoxND with CELL based coordinates in direction dir that is enclosed by b.
Definition AMReX_Box.H:1664
std::array< T, N > Array
Definition AMReX_Array.H:31
bool notInLaunchRegion() noexcept
Definition AMReX_GpuControl.H:89
void push(MPI_Comm c)
Definition AMReX_ParallelContext.H:105
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
void pop()
Note that it's the user's responsibility to free the MPI_Comm.
Definition AMReX_ParallelContext.H:111
int local_to_global_rank(int rank) noexcept
translate between local rank and global rank
Definition AMReX_ParallelContext.H:98
int global_to_local_rank(int rank) noexcept
Definition AMReX_ParallelContext.H:101
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
MPI_Comm Communicator() noexcept
Definition AMReX_ParallelDescriptor.H:223
int MPI_Comm
Definition AMReX_ccse-mpi.H:51
int MPI_Group
Definition AMReX_ccse-mpi.H:52
static constexpr int MPI_COMM_NULL
Definition AMReX_ccse-mpi.H:59
__host__ __device__ T hmin(T const &v)
Definition AMReX_SIMD.H:168
Definition AMReX_Amr.cpp:50
@ make_alias
Definition AMReX_MakeType.H:7
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:273
void average_down(const MultiFab &S_fine, MultiFab &S_crse, const Geometry &fgeom, const Geometry &cgeom, int scomp, int ncomp, int rr)
Definition AMReX_MultiFabUtil.cpp:359
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:35
LinOpBCType
Definition AMReX_LO_BCTYPES.H:27
void EB_average_down(const MultiFab &S_fine, MultiFab &S_crse, const MultiFab &vol_fine, const MultiFab &vfrac_fine, int scomp, int ncomp, const IntVect &ratio)
Volume-weighted average-down from fine to coarse using EB volume fractions.
Definition AMReX_EBMultiFabUtil.cpp:336
BottomSolver
Definition AMReX_MLLinOp.H:42
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
std::unique_ptr< Hypre > makeHypre(const BoxArray &grids, const DistributionMapping &dmap, const Geometry &geom, MPI_Comm comm_, Hypre::Interface interface, const iMultiFab *overset_mask)
Factory that instantiates the requested HYPRE interface.
Definition AMReX_Hypre.cpp:12
void Warning(const std::string &msg)
Print a warning message to the diagnostic stream and keep running.
Definition AMReX.cpp:250
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:244
__host__ __device__ constexpr int get(IntVectND< dim > const &iv) noexcept
Get I'th element of IntVectND<dim>
Definition AMReX_IntVect.H:1360
A multidimensional array accessor.
Definition AMReX_Array4.H:289
Type trait specialized for MultiFab-like types and their containers.
Definition AMReX_FabDataType.H:16
Fixed-size array that can be used on GPU.
Definition AMReX_Array.H:52
Definition AMReX_TypeTraits.H:27
Configuration knobs for multilevel linear operators (grid agglomeration, metrics, etc....
Definition AMReX_MLLinOp.H:53
LPInfo & setConsolidationRatio(int x) noexcept
Set the refinement ratio x between consolidated levels.
Definition AMReX_MLLinOp.H:79
int con_strategy
Definition AMReX_MLLinOp.H:60
bool do_semicoarsening
Definition AMReX_MLLinOp.H:56
bool has_metric_term
Definition AMReX_MLLinOp.H:61
LPInfo & setConsolidationGridSize(int x) noexcept
Override the consolidation grid cutoff x (cells per MPI task) used to trigger grouping.
Definition AMReX_MLLinOp.H:77
int max_semicoarsening_level
Definition AMReX_MLLinOp.H:63
bool hasHiddenDimension() const noexcept
True if a hidden dimension was configured via setHiddenDirection().
Definition AMReX_MLLinOp.H:96
int con_ratio
Definition AMReX_MLLinOp.H:59
bool do_consolidation
Definition AMReX_MLLinOp.H:55
int con_grid_size
Definition AMReX_MLLinOp.H:58
LPInfo & setSemicoarsening(bool x) noexcept
Toggle plane-wise semicoarsening instead of full coarsening (x = true selects semicoarsening).
Definition AMReX_MLLinOp.H:73
LPInfo & setHiddenDirection(int n) noexcept
Specify a dimension n that should be treated as “hidden” (e.g., for thin domains).
Definition AMReX_MLLinOp.H:91
LPInfo & setConsolidation(bool x) noexcept
Enable or disable consolidation (MPI rank grouping) on coarse levels (x toggles the feature).
Definition AMReX_MLLinOp.H:71
LPInfo & setSemicoarseningDirection(int n) noexcept
Lock the direction n used for semicoarsening (-1 restores the default heuristic).
Definition AMReX_MLLinOp.H:89
LPInfo & setMaxSemicoarseningLevel(int n) noexcept
Cap the number of semicoarsening steps (when enabled) via n.
Definition AMReX_MLLinOp.H:87
bool do_agglomeration
Definition AMReX_MLLinOp.H:54
LPInfo & setMetricTerm(bool x) noexcept
Indicate whether metric terms are present so downstream code can skip metric work when absent.
Definition AMReX_MLLinOp.H:83
bool deterministic
Enable deterministic mode for GPU operations.
Definition AMReX_MLLinOp.H:66
static constexpr int getDefaultConsolidationGridSize()
Definition AMReX_MLLinOp.H:108
LPInfo & setConsolidationStrategy(int x) noexcept
Select the heuristic x used when forming consolidated grids.
Definition AMReX_MLLinOp.H:81
int max_coarsening_level
Definition AMReX_MLLinOp.H:62
int agg_grid_size
Definition AMReX_MLLinOp.H:57
static constexpr int getDefaultAgglomerationGridSize()
Definition AMReX_MLLinOp.H:100
int hidden_direction
Definition AMReX_MLLinOp.H:65
LPInfo & setAgglomerationGridSize(int x) noexcept
Override the target grid size x used when agglomerating patches.
Definition AMReX_MLLinOp.H:75
LPInfo & setMaxCoarseningLevel(int n) noexcept
Cap how many coarsening steps (standard or semi-) MLMG may perform by setting n.
Definition AMReX_MLLinOp.H:85
LPInfo & setDeterministic(bool x) noexcept
Enable deterministic reductions even on GPUs (slower but reproducible) by toggling x.
Definition AMReX_MLLinOp.H:93
LPInfo & setAgglomeration(bool x) noexcept
Enable or disable grid agglomeration on the coarsest MLMG levels (x = true enables it).
Definition AMReX_MLLinOp.H:69
int semicoarsening_direction
Definition AMReX_MLLinOp.H:64
Definition AMReX_MLLinOp.H:118
StateMode
Definition AMReX_MLLinOp.H:120
BCMode
Definition AMReX_MLLinOp.H:119
Location
Definition AMReX_MLLinOp.H:121
FabArray memory allocation information.
Definition AMReX_FabArray.H:73