Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_MLLinOp.H
Go to the documentation of this file.
1#ifndef AMREX_ML_LINOP_H_
2#define AMREX_ML_LINOP_H_
3#include <AMReX_Config.H>
4
5#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
6#include <AMReX_Hypre.H>
8#endif
9
10#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
11#include <AMReX_PETSc.H>
12#endif
13
14#ifdef AMREX_USE_EB
16#include <AMReX_MultiCutFab.H>
17#endif
18
19#include <AMReX_Any.H>
20#include <AMReX_BndryRegister.H>
21#include <AMReX_FabDataType.H>
22#include <AMReX_MLMGBndry.H>
23#include <AMReX_MLAlgMG.H>
24#include <AMReX_MultiFab.H>
25#include <AMReX_MultiFabUtil.H>
26
27#include <algorithm>
28#include <iterator>
29#include <limits>
30#include <string>
31
32namespace amrex {
33
41
45
52struct LPInfo
53{
54 bool do_agglomeration = true;
55 bool do_consolidation = true;
56 bool do_semicoarsening = false;
57 int agg_grid_size = -1;
58 int con_grid_size = -1;
59 int con_ratio = 2;
60 int con_strategy = 3;
61 bool has_metric_term = true;
66 bool deterministic = false;
67
69 LPInfo& setAgglomeration (bool x) noexcept { do_agglomeration = x; return *this; }
71 LPInfo& setConsolidation (bool x) noexcept { do_consolidation = x; return *this; }
73 LPInfo& setSemicoarsening (bool x) noexcept { do_semicoarsening = x; return *this; }
75 LPInfo& setAgglomerationGridSize (int x) noexcept { agg_grid_size = x; return *this; }
77 LPInfo& setConsolidationGridSize (int x) noexcept { con_grid_size = x; return *this; }
79 LPInfo& setConsolidationRatio (int x) noexcept { con_ratio = x; return *this; }
81 LPInfo& setConsolidationStrategy (int x) noexcept { con_strategy = x; return *this; }
83 LPInfo& setMetricTerm (bool x) noexcept { has_metric_term = x; return *this; }
85 LPInfo& setMaxCoarseningLevel (int n) noexcept { max_coarsening_level = n; return *this; }
87 LPInfo& setMaxSemicoarseningLevel (int n) noexcept { max_semicoarsening_level = n; return *this; }
89 LPInfo& setSemicoarseningDirection (int n) noexcept { semicoarsening_direction = n; return *this; }
91 LPInfo& setHiddenDirection (int n) noexcept { hidden_direction = n; return *this; }
94 LPInfo& setDeterministic (bool x) noexcept { deterministic = x; return *this; }
95
97 [[nodiscard]] bool hasHiddenDimension () const noexcept {
98 return hidden_direction >=0 && hidden_direction < AMREX_SPACEDIM;
99 }
100
101 static constexpr int getDefaultAgglomerationGridSize () {
102#ifdef AMREX_USE_GPU
103 return 32;
104#else
105 return AMREX_D_PICK(32, 16, 8);
106#endif
107 }
108
109 static constexpr int getDefaultConsolidationGridSize () {
110#ifdef AMREX_USE_GPU
111 return 32;
112#else
113 return AMREX_D_PICK(32, 16, 8);
114#endif
115 }
116};
117
124
125template <typename T> class MLMGT;
126template <typename T> class MLCGSolverT;
127template <typename T> class MLPoissonT;
128template <typename T> class MLABecLaplacianT;
129template <typename T> class GMRESMLMGT;
130
132
138class HypreMLNodeLap;
139
140template <typename MF>
142{
143public:
144
145 template <typename T> friend class MLMGT;
146 template <typename T> friend class MLCGSolverT;
147 template <typename T> friend class MLPoissonT;
148 template <typename T> friend class MLABecLaplacianT;
149 template <typename T> friend class GMRESMLMGT;
150 friend class HypreMLNodeLap;
151
152 using MFType = MF;
155
160
161 MLLinOpT () = default;
162 virtual ~MLLinOpT () = default;
163
164 MLLinOpT (const MLLinOpT<MF>&) = delete;
165 MLLinOpT (MLLinOpT<MF>&&) = delete;
168
180 void define (const Vector<Geometry>& a_geom,
181 const Vector<BoxArray>& a_grids,
182 const Vector<DistributionMapping>& a_dmap,
183 const LPInfo& a_info,
184 const Vector<FabFactory<FAB> const*>& a_factory,
185 bool eb_limit_coarsening = true);
186
187 [[nodiscard]] virtual std::string name () const { return std::string("Unspecified"); }
188
200 const Array<BCType,AMREX_SPACEDIM>& hibc) noexcept;
201
213
225 const Array<Real,AMREX_SPACEDIM>& hi_bcloc) noexcept;
226
234 [[nodiscard]] bool needsCoarseDataForBC () const noexcept { return m_needs_coarse_data_for_bc; }
235
257 void setCoarseFineBC (const MF* crse, int crse_ratio,
258 LinOpBCType bc_type = LinOpBCType::Dirichlet) noexcept;
259
260 void setCoarseFineBC (const MF* crse, IntVect const& crse_ratio,
261 LinOpBCType bc_type = LinOpBCType::Dirichlet) noexcept;
262
263 template <typename AMF>
264 requires (!std::same_as<MF,AMF>)
265 void setCoarseFineBC (const AMF* crse, int crse_ratio,
266 LinOpBCType bc_type = LinOpBCType::Dirichlet) noexcept;
267
268 template <typename AMF>
269 requires (!std::same_as<MF,AMF>)
270 void setCoarseFineBC (const AMF* crse, IntVect const& crse_ratio,
271 LinOpBCType bc_type = LinOpBCType::Dirichlet) noexcept;
272
273
292 virtual void setLevelBC (int /*amrlev*/, const MF* /*levelbcdata*/,
293 const MF* /*robinbc_a*/ = nullptr,
294 const MF* /*robinbc_b*/ = nullptr,
295 const MF* /*robinbc_f*/ = nullptr) = 0;
296
297 template <MultiFabLike AMF>
298 requires (!std::same_as<MF,AMF>)
299 void setLevelBC (int amrlev, const AMF* levelbcdata,
300 const AMF* robinbc_a = nullptr,
301 const AMF* robinbc_b = nullptr,
302 const AMF* robinbc_f = nullptr);
303
309 void setVerbose (int v) noexcept { verbose = v; }
310
316 void setPrintIndentation (std::string s) { print_ident = std::move(s); }
317
323 void setMaxOrder (int o) noexcept { maxorder = o; }
325 [[nodiscard]] int getMaxOrder () const noexcept { return maxorder; }
326
335 [[nodiscard]] bool getEnforceSingularSolvable () const noexcept { return enforceSingularSolvable; }
336
337 [[nodiscard]] virtual BottomSolver getDefaultBottomSolver () const { return BottomSolver::bicgstab; }
338
340 [[nodiscard]] virtual bool supportCustomBottomSolver () const { return false; }
341
353 virtual void customBottomSolve (MLMGT<MF>* mlmg, MF& x, const MF& b,
354 RT eps_rel, RT eps_abs, int maxiter)
355 {
356 amrex::ignore_unused(mlmg, x, b, eps_rel, eps_abs, maxiter);
357 amrex::Abort("customBottomSolve not implemented");
358 }
359
361 [[nodiscard]] virtual int getNComp () const { return 1; }
362
363 [[nodiscard]] virtual int getNGrow (int /*a_lev*/ = 0, int /*mg_lev*/ = 0) const { return 0; }
364
366 [[nodiscard]] virtual bool needsUpdate () const { return false; }
368 virtual void update () {}
369
379 virtual void restriction (int amrlev, int cmglev, MF& crse, MF& fine) const = 0;
380
389 virtual void interpolation (int amrlev, int fmglev, MF& fine, const MF& crse) const = 0;
390
399 virtual void interpAssign (int amrlev, int fmglev, MF& fine, MF& crse) const
400 {
401 amrex::ignore_unused(amrlev, fmglev, fine, crse);
402 amrex::Abort("MLLinOpT::interpAssign: Must be implemented for FMG cycle");
403 }
404
413 virtual void interpolationAmr (int famrlev, MF& fine, const MF& crse,
414 IntVect const& nghost) const
415 {
416 amrex::ignore_unused(famrlev, fine, crse, nghost);
417 amrex::Abort("MLLinOpT::interpolationAmr: Must be implemented for composite solves across multiple AMR levels");
418 }
419
431 virtual void interpCoarseFineSolution (int famrlev, MF& fine_sol, const MF& crse_sol) const
432 {
433 amrex::ignore_unused(famrlev, fine_sol, crse_sol);
434 }
435
445 virtual void averageDownSolutionRHS (int camrlev, MF& crse_sol, MF& crse_rhs,
446 const MF& fine_sol, const MF& fine_rhs)
447 {
448 amrex::ignore_unused(camrlev, crse_sol, crse_rhs, fine_sol, fine_rhs);
449 amrex::Abort("MLLinOpT::averageDownSolutionRHS: Must be implemented for composite solves across multiple AMR levels");
450 }
451
463 virtual void apply (int amrlev, int mglev, MF& out, MF& in, BCMode bc_mode,
464 StateMode s_mode, const MLMGBndryT<MF>* bndry=nullptr) const = 0;
465
476 virtual void smooth (int amrlev, int mglev, MF& sol, const MF& rhs,
477 bool skip_fillboundary, int niter) const = 0;
478
486 virtual void normalize (int amrlev, int mglev, MF& mf) const {
487 amrex::ignore_unused(amrlev, mglev, mf);
488 }
489
499 virtual void solutionResidual (int amrlev, MF& resid, MF& x, const MF& b,
500 const MF* crse_bcdata=nullptr) = 0;
501
508 virtual void prepareForFluxes (int amrlev, const MF* crse_bcdata = nullptr) {
509 amrex::ignore_unused(amrlev, crse_bcdata);
510 }
511
523 virtual void correctionResidual (int amrlev, int mglev, MF& resid, MF& x, const MF& b,
524 BCMode bc_mode, const MF* crse_bcdata=nullptr) = 0;
525
537 virtual void reflux (int crse_amrlev,
538 MF& res, const MF& crse_sol, const MF& crse_rhs,
539 MF& fine_res, MF& fine_sol, const MF& fine_rhs) const
540 {
541 amrex::ignore_unused(crse_amrlev, res, crse_sol, crse_rhs, fine_res,
542 fine_sol, fine_rhs);
543 amrex::Abort("MLLinOpT::reflux: Must be implemented for composite solves across multiple AMR levels");
544 }
545
554 virtual void compFlux (int amrlev, const Array<MF*,AMREX_SPACEDIM>& fluxes,
555 MF& sol, Location loc) const
556 {
557 amrex::ignore_unused(amrlev, fluxes, sol, loc);
558 amrex::Abort("AMReX_MLLinOp::compFlux::How did we get here?");
559 }
560
569 virtual void compGrad (int amrlev, const Array<MF*,AMREX_SPACEDIM>& grad,
570 MF& sol, Location loc) const
571 {
572 amrex::ignore_unused(amrlev, grad, sol, loc);
573 amrex::Abort("AMReX_MLLinOp::compGrad::How did we get here?");
574 }
575
583 virtual void applyMetricTerm (int amrlev, int mglev, MF& rhs) const {
584 amrex::ignore_unused(amrlev, mglev, rhs);
585 }
586
593 virtual void unapplyMetricTerm (int amrlev, int mglev, MF& rhs) const {
594 amrex::ignore_unused(amrlev, mglev, rhs);
595 }
596
603 virtual void unimposeNeumannBC (int amrlev, MF& rhs) const {
604 amrex::ignore_unused(amrlev, rhs);
605 }
606
613 virtual void applyInhomogNeumannTerm (int amrlev, MF& rhs) const {
614 amrex::ignore_unused(amrlev, rhs);
615 }
616
623 virtual void applyOverset (int amrlev, MF& rhs) const {
624 amrex::ignore_unused(amrlev, rhs);
625 }
626
634 [[nodiscard]] virtual bool scaleRHS (int amrlev, MF* rhs) const {
635 amrex::ignore_unused(amrlev, rhs);
636 return false;
637 }
638
647 virtual Vector<RT> getSolvabilityOffset (int amrlev, int mglev,
648 MF const& rhs) const {
649 amrex::ignore_unused(amrlev, mglev, rhs);
650 return {};
651 }
652
661 virtual void fixSolvabilityByOffset (int amrlev, int mglev, MF& rhs,
662 Vector<RT> const& offset) const {
663 amrex::ignore_unused(amrlev, mglev, rhs, offset);
664 }
665
669 virtual void prepareForSolve () = 0;
670
675 virtual void preparePrecond () {}
676
685 virtual void setDirichletNodesToZero (int amrlev, int mglev,
686 MF& mf) const
687 {
688 amrex::ignore_unused(amrlev, mglev, mf);
689 amrex::Warning("This function might need to be implemented for GMRES to work with this LinOp.");
690 }
691
693 [[nodiscard]] virtual bool isSingular (int amrlev) const = 0;
695 [[nodiscard]] virtual bool isBottomSingular () const = 0;
696
706 virtual RT xdoty (int amrlev, int mglev, const MF& x, const MF& y, bool local) const = 0;
707
717
725 virtual RT norm2Precond (Vector<MF const*> const& x) const;
726
732 virtual std::unique_ptr<MLLinOpT<MF>> makeNLinOp (int grid_size) const
733 {
734 amrex::ignore_unused(grid_size);
735 amrex::Abort("MLLinOp::makeNLinOp: NSolve not supported");
736 return nullptr;
737 }
738
746 virtual void getFluxes (const Vector<Array<MF*,AMREX_SPACEDIM> >& a_flux,
747 const Vector<MF*>& a_sol,
748 Location a_loc) const {
749 amrex::ignore_unused(a_flux, a_sol, a_loc);
750 amrex::Abort("MLLinOp::getFluxes: How did we get here?");
751 }
752
758 virtual void getFluxes (const Vector<MF*>& a_flux,
759 const Vector<MF*>& a_sol) const {
760 amrex::ignore_unused(a_flux, a_sol);
761 amrex::Abort("MLLinOp::getFluxes: How did we get here?");
762 }
763
764#ifdef AMREX_USE_EB
771 virtual void getEBFluxes (const Vector<MF*>& a_flux,
772 const Vector<MF*>& a_sol) const {
773 amrex::ignore_unused(a_flux, a_sol);
774 amrex::Abort("MLLinOp::getEBFluxes: How did we get here?");
775 }
776#endif
777
782 [[nodiscard]] virtual std::unique_ptr<MLAlgMG> makeAlgMG (int mglev) const {
784 amrex::Abort("MLLinOp::makeAlgMG: not supported by this operator");
785 return {nullptr};
786 }
787
789 [[nodiscard]] virtual bool supportsAlgMG () const { return false; }
790
799 [[nodiscard]] virtual bool supportsAnisotropicCoarsening () const { return false; }
800
806 [[nodiscard]] virtual GpuArray<Real,AMREX_SPACEDIM>
807 anisotropicCoarseningCellSize (Geometry const& geom) const { return geom.CellSizeArray(); }
808
809#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
815 [[nodiscard]] virtual std::unique_ptr<Hypre> makeHypre (Hypre::Interface hypre_interface) const {
816 amrex::ignore_unused(hypre_interface);
817 amrex::Abort("MLLinOp::makeHypre: How did we get here?");
818 return {nullptr};
819 }
826 [[nodiscard]] virtual std::unique_ptr<HypreNodeLap> makeHypreNodeLap(
827 int bottom_verbose,
828 const std::string& options_namespace) const
829 {
830 amrex::ignore_unused(bottom_verbose, options_namespace);
831 amrex::Abort("MLLinOp::makeHypreNodeLap: How did we get here?");
832 return {nullptr};
833 }
834#endif
835
836#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
840 [[nodiscard]] virtual std::unique_ptr<PETScABecLap> makePETSc () const {
841 amrex::Abort("MLLinOp::makePETSc: How did we get here?");
842 return {nullptr};
843 }
844#endif
845
849 [[nodiscard]] virtual bool supportNSolve () const { return false; }
850
857 virtual void copyNSolveSolution (MF& dst, MF const& src) const {
858 amrex::ignore_unused(dst, src);
859 }
860
866 virtual void postSolve (Vector<MF*> const& sol) const {
868 }
869
877 [[nodiscard]] virtual RT normInf (int amrlev, MF const& mf, bool local) const = 0;
878
884 virtual void averageDownAndSync (Vector<MF>& sol) const = 0;
885
886 virtual void avgDownResAmr (int clev, MF& cres, MF const& fres) const
887 {
888 amrex::ignore_unused(clev, cres, fres);
889 amrex::Abort("MLLinOpT::avgDownResAmr: Must be implemented for composite solves across multiple AMR levels");
890 }
891
899 virtual void avgDownResMG (int clev, MF& cres, MF const& fres) const;
900
904 virtual void beginPrecondBC () { m_precond_mode = true; }
908 virtual void endPrecondBC () { m_precond_mode = false; }
909
917 [[nodiscard]] bool isMFIterSafe (int amrlev, int mglev1, int mglev2) const;
918
920 [[nodiscard]] int NAMRLevels () const noexcept { return m_num_amr_levels; }
921
928 [[nodiscard]] int NMGLevels (int amrlev) const noexcept { return m_num_mg_levels[amrlev]; }
929
931 [[nodiscard]] const Geometry& Geom (int amr_lev, int mglev=0) const noexcept { return m_geom[amr_lev][mglev]; }
932
933 // BC
936 // Need to save the original copy because we change the BC type to
937 // Neumann for inhomogeneous Neumann and Robin.
940
941protected:
942
943 static constexpr int mg_coarsen_ratio = 2;
946 int mg_agg_no_split_direction = -1; // keep agglomerated grids whole in it
947 bool mg_odd_coarsening = false; // coarsen by 3 or 5 where 2 does not fit
948 bool mg_independent_coarsening = false; // coarsen directions on their own
949
951
952 int verbose = 0;
953 std::string print_ident;
954
955 int maxorder = 3;
956
958 bool m_mg_deferred = false;
959 bool m_mg_built = false;
960
963
965 const MLLinOpT<MF>* m_parent = nullptr;
966
968
969 bool m_do_agglomeration = false;
970 bool m_do_consolidation = false;
971
974
981
985 struct CommContainer {
986 MPI_Comm comm;
987 CommContainer (MPI_Comm m) noexcept : comm(m) {}
988 CommContainer (const CommContainer&) = delete;
989 CommContainer (CommContainer&&) = delete;
990 void operator= (const CommContainer&) = delete;
991 void operator= (CommContainer&&) = delete;
992 ~CommContainer () { // NOLINT(modernize-use-equals-default)
993#ifdef BL_USE_MPI
994 if (comm != MPI_COMM_NULL) { MPI_Comm_free(&comm); }
995#endif
996 }
997 };
999 std::unique_ptr<CommContainer> m_raii_comm;
1000
1003
1008 const MF* m_coarse_data_for_bc = nullptr;
1010
1011 bool m_precond_mode = false;
1012
1014 [[nodiscard]] const Vector<int>& AMRRefRatio () const noexcept { return m_amr_ref_ratio; }
1015
1017 [[nodiscard]] int AMRRefRatio (int amr_lev) const noexcept { return m_amr_ref_ratio[amr_lev]; }
1018
1020 [[nodiscard]] IntVect AMRRefRatioVect (int amr_lev) const noexcept {
1021 IntVect rr(m_amr_ref_ratio[amr_lev]);
1022 if (info.hasHiddenDimension()) { rr[info.hidden_direction] = 1; }
1023 return rr;
1024 }
1025
1026 [[nodiscard]] FabFactory<FAB> const* Factory (int amr_lev, int mglev=0) const noexcept {
1027 return m_factory[amr_lev][mglev].get();
1028 }
1029
1030 [[nodiscard]] GpuArray<BCType,AMREX_SPACEDIM> LoBC (int icomp = 0) const noexcept {
1032 m_lobc[icomp][1],
1033 m_lobc[icomp][2])}};
1034 }
1035 [[nodiscard]] GpuArray<BCType,AMREX_SPACEDIM> HiBC (int icomp = 0) const noexcept {
1037 m_hibc[icomp][1],
1038 m_hibc[icomp][2])}};
1039 }
1040
1041 [[nodiscard]] bool hasBC (BCType bct) const noexcept;
1042 [[nodiscard]] bool hasInhomogNeumannBC () const noexcept;
1043 [[nodiscard]] bool hasRobinBC () const noexcept;
1044
1045 [[nodiscard]] virtual bool supportRobinBC () const noexcept { return false; }
1046 [[nodiscard]] virtual bool supportInhomogNeumannBC () const noexcept { return false; }
1047
1048#ifdef BL_USE_MPI
1049 [[nodiscard]] bool isBottomActive () const noexcept { return m_bottom_comm != MPI_COMM_NULL; }
1050#else
1051 [[nodiscard]] bool isBottomActive () const noexcept { return true; }
1052#endif
1053 [[nodiscard]] MPI_Comm BottomCommunicator () const noexcept { return m_bottom_comm; }
1054 [[nodiscard]] MPI_Comm Communicator () const noexcept { return m_default_comm; }
1055
1056 void setCoarseFineBCLocation (const RealVect& cloc) noexcept { m_coarse_bc_loc = cloc; }
1057
1058 [[nodiscard]] bool doAgglomeration () const noexcept { return m_do_agglomeration; }
1059 [[nodiscard]] bool doConsolidation () const noexcept { return m_do_consolidation; }
1060 [[nodiscard]] bool doSemicoarsening () const noexcept { return m_do_semicoarsening; }
1061
1062 [[nodiscard]] bool isCellCentered () const noexcept { return m_ixtype == 0; }
1063
1064 [[nodiscard]] virtual IntVect getNGrowVectRestriction () const {
1065 return isCellCentered() ? IntVect(0) : IntVect(1);
1066 }
1067
1068 virtual void make (Vector<Vector<MF> >& mf, IntVect const& ng) const;
1069
1070 [[nodiscard]] virtual MF make (int amrlev, int mglev, IntVect const& ng) const;
1071
1073 [[nodiscard]] virtual MF make (int amrlev, int mglev, IntVect const& ng,
1074 MFInfo const& mf_info) const;
1075
1076 [[nodiscard]] virtual MF makeAlias (MF const& mf) const;
1077
1079 [[nodiscard]] virtual MF makeCoarseMG (int amrlev, int mglev, IntVect const& ng) const;
1080
1082 [[nodiscard]] virtual MF makeCoarseMG (int amrlev, int mglev, IntVect const& ng,
1083 MFInfo const& mf_info) const;
1084
1086 [[nodiscard]] virtual MF makeCoarseAmr (int famrlev, IntVect const& ng) const;
1087
1089 [[nodiscard]] virtual MF makeCoarseAmr (int famrlev, IntVect const& ng,
1090 MFInfo const& mf_info) const;
1091
1092 [[nodiscard]] virtual std::unique_ptr<FabFactory<FAB> > makeFactory (int /*amrlev*/, int /*mglev*/) const {
1093 return std::make_unique<DefaultFabFactory<FAB>>();
1094 }
1095
1096 virtual void resizeMultiGrid (int new_size);
1097
1100
1102 virtual void buildMGHierarchy () {
1103 BL_PROFILE("MLLinOp::buildMGHierarchy()");
1104 defineCoarseMGLevels();
1105 }
1106
1107 [[nodiscard]] bool hasHiddenDimension () const noexcept { return info.hasHiddenDimension(); }
1108 [[nodiscard]] int hiddenDirection () const noexcept { return info.hidden_direction; }
1109 [[nodiscard]] Box compactify (Box const& b) const noexcept;
1110
1111 template <typename T>
1112 [[nodiscard]] Array4<T> compactify (Array4<T> const& a) const noexcept
1113 {
1114 if (info.hidden_direction == 0) {
1115 return Array4<T>(a.dataPtr(), {a.begin[1],a.begin[2],0}, {a.end[1],a.end[2],1}, a.nComp());
1116 } else if (info.hidden_direction == 1) {
1117 return Array4<T>(a.dataPtr(), {a.begin[0],a.begin[2],0}, {a.end[0],a.end[2],1}, a.nComp());
1118 } else if (info.hidden_direction == 2) {
1119 return Array4<T>(a.dataPtr(), {a.begin[0],a.begin[1],0}, {a.end[0],a.end[1],1}, a.nComp());
1120 } else {
1121 return a;
1122 }
1123 }
1124
1125 template <typename T>
1126 [[nodiscard]] T get_d0 (T const& dx, T const& dy, T const&) const noexcept
1127 {
1128 if (info.hidden_direction == 0) {
1129 return dy;
1130 } else {
1131 return dx;
1132 }
1133 }
1134
1135 template <typename T>
1136 [[nodiscard]] T get_d1 (T const&, T const& dy, T const& dz) const noexcept
1137 {
1138 if (info.hidden_direction == 0 || info.hidden_direction == 1) {
1139 return dz;
1140 } else {
1141 return dy;
1142 }
1143 }
1144
1145private:
1146
1147 void defineGrids (const Vector<Geometry>& a_geom,
1148 const Vector<BoxArray>& a_grids,
1149 const Vector<DistributionMapping>& a_dmap,
1150 const Vector<FabFactory<FAB> const*>& a_factory);
1151 void defineBC ();
1152 void defineCoarseMGLevels ();
1153 static void makeAgglomeratedDMap (const Vector<BoxArray>& ba, Vector<DistributionMapping>& dm);
1154 static void makeConsolidatedDMap (const Vector<BoxArray>& ba, Vector<DistributionMapping>& dm,
1155 int ratio, int strategy);
1156 [[nodiscard]] MPI_Comm makeSubCommunicator (const DistributionMapping& dm);
1157
1158 virtual void checkPoint (std::string const& /*file_name*/) const {
1159 amrex::Abort("MLLinOp:checkPoint: not implemented");
1160 }
1161
1162 Vector<std::unique_ptr<MF>> levelbc_raii;
1163 Vector<std::unique_ptr<MF>> robin_a_raii;
1164 Vector<std::unique_ptr<MF>> robin_b_raii;
1165 Vector<std::unique_ptr<MF>> robin_f_raii;
1166};
1167
1168template <typename MF>
1169void
1171 const Vector<BoxArray>& a_grids,
1172 const Vector<DistributionMapping>& a_dmap,
1173 const LPInfo& a_info,
1174 const Vector<FabFactory<FAB> const*>& a_factory,
1175 [[maybe_unused]] bool eb_limit_coarsening)
1176{
1177 BL_PROFILE("MLLinOp::define()");
1178
1179 info = a_info;
1180#ifdef AMREX_USE_GPU
1182 {
1183 if (info.agg_grid_size <= 0) { info.agg_grid_size = AMREX_D_PICK(32, 16, 8); }
1184 if (info.con_grid_size <= 0) { info.con_grid_size = AMREX_D_PICK(32, 16, 8); }
1185 }
1186 else
1187#endif
1188 {
1189 if (info.agg_grid_size <= 0) { info.agg_grid_size = LPInfo::getDefaultAgglomerationGridSize(); }
1190 if (info.con_grid_size <= 0) { info.con_grid_size = LPInfo::getDefaultConsolidationGridSize(); }
1191 }
1192
1193#ifdef AMREX_USE_EB
1194 if (!a_factory.empty() && eb_limit_coarsening) {
1195 const auto *f = dynamic_cast<EBFArrayBoxFactory const*>(a_factory[0]);
1196 if (f) {
1197 info.max_coarsening_level = std::min(info.max_coarsening_level,
1198 f->maxCoarseningLevel());
1199 }
1200 }
1201#endif
1203 m_mg_built = false;
1204 defineGrids(a_geom, a_grids, a_dmap, a_factory);
1205 defineBC();
1206}
1207
1208template <typename MF>
1209void
1210MLLinOpT<MF>::defineGrids (const Vector<Geometry>& a_geom,
1211 const Vector<BoxArray>& a_grids,
1212 const Vector<DistributionMapping>& a_dmap,
1213 const Vector<FabFactory<FAB> const*>& a_factory)
1214{
1215 BL_PROFILE("MLLinOp::defineGrids()");
1216
1217#ifdef AMREX_USE_EB
1218 if ( ! a_factory.empty() ) {
1219 auto const* ebf = dynamic_cast<EBFArrayBoxFactory const*>(a_factory[0]);
1220 if (ebf && !(ebf->isAllRegular())) { // Has non-trivial EB
1221 mg_domain_min_width = 4;
1222 }
1223 }
1224#endif
1225
1226 m_num_amr_levels = 0;
1227 for (int amrlev = 0; amrlev < std::ssize(a_geom); amrlev++) {
1228 if (!a_grids[amrlev].empty()) {
1229 m_num_amr_levels++;
1230 }
1231 }
1232
1233 m_amr_ref_ratio.resize(m_num_amr_levels);
1234 m_num_mg_levels.resize(m_num_amr_levels);
1235
1236 m_geom.clear();
1237 m_grids.clear();
1238 m_dmap.clear();
1239 m_factory.clear();
1240 m_domain_covered.clear();
1241 mg_coarsen_ratio_vec.clear();
1242
1243 m_geom.resize(m_num_amr_levels);
1244 m_grids.resize(m_num_amr_levels);
1245 m_dmap.resize(m_num_amr_levels);
1246 m_factory.resize(m_num_amr_levels);
1247
1248 m_default_comm = ParallelContext::CommunicatorSub();
1249
1250 const RealBox& rb = a_geom[0].ProbDomain();
1251 const int coord = a_geom[0].Coord();
1252 const Array<int,AMREX_SPACEDIM>& is_per = a_geom[0].isPeriodic();
1253
1254 IntVect mg_coarsen_ratio_v(mg_coarsen_ratio);
1255 if (hasHiddenDimension()) {
1256 AMREX_ASSERT_WITH_MESSAGE(AMREX_SPACEDIM == 3,
1257 "Hidden direction only supported for 3d");
1258 mg_coarsen_ratio_v[info.hidden_direction] = 1;
1259 }
1260
1261 // fine amr levels
1262 for (int amrlev = m_num_amr_levels-1; amrlev > 0; --amrlev)
1263 {
1264 m_num_mg_levels[amrlev] = 1;
1265 m_geom[amrlev].push_back(a_geom[amrlev]);
1266 m_grids[amrlev].push_back(a_grids[amrlev]);
1267 m_dmap[amrlev].push_back(a_dmap[amrlev]);
1268 if (amrlev < std::ssize(a_factory)) {
1269 m_factory[amrlev].emplace_back(a_factory[amrlev]->clone());
1270 } else {
1271 m_factory[amrlev].push_back(std::make_unique<DefaultFabFactory<FAB>>());
1272 }
1273
1274 IntVect rr = mg_coarsen_ratio_v;
1275 const Box& dom = a_geom[amrlev].Domain();
1276 for (int i = 0; i < 2; ++i)
1277 {
1278 if (!dom.coarsenable(rr)) { amrex::Abort("MLLinOp: Uncoarsenable domain"); }
1279
1280 const Box& cdom = amrex::coarsen(dom,rr);
1281 if (cdom == a_geom[amrlev-1].Domain()) { break; }
1282
1283 ++(m_num_mg_levels[amrlev]);
1284
1285 m_geom[amrlev].emplace_back(cdom, rb, coord, is_per);
1286
1287 m_grids[amrlev].push_back(a_grids[amrlev]);
1288 AMREX_ASSERT(m_grids[amrlev].back().coarsenable(rr));
1289 m_grids[amrlev].back().coarsen(rr);
1290
1291 m_dmap[amrlev].push_back(a_dmap[amrlev]);
1292
1293 rr *= mg_coarsen_ratio_v;
1294 }
1295
1296#if (AMREX_SPACEDIM > 1)
1297 if (hasHiddenDimension()) {
1298 m_amr_ref_ratio[amrlev-1] = rr[(info.hidden_direction+1) % AMREX_SPACEDIM];
1299 } else
1300#endif
1301 {
1302 m_amr_ref_ratio[amrlev-1] = rr[0];
1303 }
1304 }
1305
1306 // coarsest amr level
1307 m_num_mg_levels[0] = 1;
1308 m_geom[0].push_back(a_geom[0]);
1309 m_grids[0].push_back(a_grids[0]);
1310 m_dmap[0].push_back(a_dmap[0]);
1311 if (!a_factory.empty()) {
1312 m_factory[0].emplace_back(a_factory[0]->clone());
1313 } else {
1314 m_factory[0].push_back(std::make_unique<DefaultFabFactory<FAB>>());
1315 }
1316
1317 m_domain_covered.resize(m_num_amr_levels, false);
1318 auto npts0 = m_grids[0][0].numPts();
1319 m_domain_covered[0] = (npts0 == compactify(m_geom[0][0].Domain()).numPts());
1320 for (int amrlev = 1; amrlev < m_num_amr_levels; ++amrlev)
1321 {
1322 if (!m_domain_covered[amrlev-1]) { break; }
1323 m_domain_covered[amrlev] = (m_grids[amrlev][0].numPts() ==
1324 compactify(m_geom[amrlev][0].Domain()).numPts());
1325 }
1326
1327 if (m_mg_deferred) {
1328 // MG levels > 0 of AMR level 0 are built by prepareMGHierarchy.
1329 m_bottom_comm = m_default_comm;
1330 m_do_agglomeration = false;
1331 m_do_consolidation = false;
1332 } else {
1333 defineCoarseMGLevels();
1334 }
1335
1336 for (int amrlev = 1; amrlev < m_num_amr_levels; ++amrlev)
1337 {
1338 for (int mglev = 1; mglev < m_num_mg_levels[amrlev]; ++mglev)
1339 {
1340 m_factory[amrlev].emplace_back(makeFactory(amrlev,mglev));
1341 }
1342 }
1343
1344 for (int amrlev = 1; amrlev < m_num_amr_levels; ++amrlev)
1345 {
1346 AMREX_ASSERT_WITH_MESSAGE(m_grids[amrlev][0].coarsenable(AMRRefRatioVect(amrlev-1)),
1347 "MLLinOp: grids not coarsenable between AMR levels");
1348 }
1349}
1350
1351template <typename MF>
1352void
1353MLLinOpT<MF>::defineCoarseMGLevels ()
1354{
1355 BL_PROFILE("MLLinOp::defineCoarseMGLevels()");
1356
1357 AMREX_ASSERT(m_grids[0].size() == 1 && mg_coarsen_ratio_vec.empty());
1358
1359 // Copies, because m_geom[0], m_grids[0] and m_dmap[0] grow below.
1360 Geometry const geom0 = m_geom[0][0];
1361 BoxArray const ba0 = m_grids[0][0];
1362 DistributionMapping const dm0 = m_dmap[0][0];
1363
1364 const RealBox& rb = geom0.ProbDomain();
1365 const int coord = geom0.Coord();
1366 const Array<int,AMREX_SPACEDIM>& is_per = geom0.isPeriodic();
1367 auto const npts0 = ba0.numPts();
1368
1369 IntVect mg_coarsen_ratio_v(mg_coarsen_ratio);
1370 IntVect mg_box_min_width_v(mg_box_min_width);
1371 IntVect mg_domain_min_width_v(mg_domain_min_width);
1372 if (hasHiddenDimension()) {
1373 mg_coarsen_ratio_v[info.hidden_direction] = 1;
1374 mg_box_min_width_v[info.hidden_direction] = 0;
1375 mg_domain_min_width_v[info.hidden_direction] = 0;
1376 }
1377
1378 Box aggbox;
1379 bool aggable = false;
1380
1381 if (ba0.size() > 1 && info.do_agglomeration)
1382 {
1383 if (m_domain_covered[0])
1384 {
1385 aggbox = geom0.Domain();
1386 if (hasHiddenDimension()) {
1387 aggbox.makeSlab(hiddenDirection(), ba0[0].smallEnd(hiddenDirection()));
1388 }
1389 aggable = true;
1390 }
1391 else
1392 {
1393 aggbox = ba0.minimalBox();
1394 aggable = (aggbox.numPts() == npts0);
1395 }
1396 }
1397
1398 bool agged = false;
1399 bool coned = false;
1400 int agg_lev = 0, con_lev = 0;
1401
1402 AMREX_ALWAYS_ASSERT( ! (info.do_semicoarsening && info.hasHiddenDimension()
1403 && (info.semicoarsening_direction == -1 ||
1404 info.semicoarsening_direction == info.hidden_direction))
1405 && info.semicoarsening_direction >= -1
1406 && info.semicoarsening_direction < AMREX_SPACEDIM );
1407
1408 // Directions to coarsen for stretched cells: those shorter than 1.5
1409 // times the shortest. A fixed semicoarsening direction takes precedence.
1410 bool const aniso_coarsening = supportsAnisotropicCoarsening() && !hasHiddenDimension()
1411 && !(info.do_semicoarsening && info.semicoarsening_direction != -1);
1412 auto const dx0 = anisotropicCoarseningCellSize(geom0);
1413 auto base_ratio = [&] (IntVect const& accum) -> IntVect
1414 {
1415 IntVect rr = mg_coarsen_ratio_v;
1416 if (aniso_coarsening) {
1417 Real dxmin = std::numeric_limits<Real>::max();
1418 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1419 dxmin = std::min(dxmin, dx0[idim]*Real(accum[idim]));
1420 }
1421 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1422 if (dx0[idim]*Real(accum[idim]) >= Real(1.5)*dxmin) { rr[idim] = 1; }
1423 }
1424 }
1425 return rr;
1426 };
1427
1428 if (info.do_agglomeration && aggable)
1429 {
1430 Box dbx = geom0.Domain();
1431 Box bbx = aggbox;
1432 Real const nbxs = static_cast<Real>(ba0.size());
1433 Long const threshold_npts = AMREX_D_TERM(Long(info.agg_grid_size),
1434 *info.agg_grid_size,
1435 *info.agg_grid_size);
1436 Vector<Box> domainboxes{dbx};
1437 Vector<Box> boundboxes{bbx};
1438 Vector<int> agg_flag{false};
1439 Vector<IntVect> accum_coarsen_ratio{IntVect(1)};
1440 int numsclevs = 0;
1441
1442 for (int lev = 0; lev < info.max_coarsening_level; ++lev)
1443 {
1444 IntVect const rr_base = base_ratio(accum_coarsen_ratio.back());
1445 IntVect rr_level = rr_base;
1446 bool const do_semicoarsening_level = info.do_semicoarsening
1447 && numsclevs < info.max_semicoarsening_level;
1448 if (do_semicoarsening_level
1449 && info.semicoarsening_direction != -1)
1450 {
1451 rr_level[info.semicoarsening_direction] = 1;
1452 }
1453 IntVect is_coarsenable;
1454 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1455 IntVect rr_dir(1);
1456 rr_dir[idim] = rr_level[idim];
1457 // With odd ratios, the first ratio must also fit the original boxes.
1458 bool const fit_ba0 = mg_odd_coarsening && lev == 0;
1459 is_coarsenable[idim] = dbx.coarsenable(rr_dir, mg_domain_min_width_v)
1460 && bbx.coarsenable(rr_dir, mg_box_min_width_v)
1461 && (!fit_ba0 || ba0.coarsenable(rr_dir, mg_box_min_width_v));
1462 for (int r : {3, 5}) {
1463 if (is_coarsenable[idim] || !mg_odd_coarsening || rr_level[idim] != 2) {
1464 break;
1465 }
1466 rr_dir[idim] = r;
1467 if (dbx.coarsenable(rr_dir, mg_domain_min_width_v)
1468 && bbx.coarsenable(rr_dir, mg_box_min_width_v)
1469 && (!fit_ba0 || ba0.coarsenable(rr_dir, mg_box_min_width_v)))
1470 {
1471 is_coarsenable[idim] = true;
1472 rr_level[idim] = r;
1473 }
1474 }
1475 if (!is_coarsenable[idim] && do_semicoarsening_level
1476 && info.semicoarsening_direction == -1)
1477 {
1478 is_coarsenable[idim] = true;
1479 rr_level[idim] = 1;
1480 }
1481 }
1482 if (mg_independent_coarsening) {
1483 // A direction that cannot be coarsened gets ratio 1, and one whose
1484 // cells are 1.5 times longer than the shortest coarsenable waits.
1485 Real hmin = std::numeric_limits<Real>::max();
1486 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1487 if (is_coarsenable[idim] && rr_level[idim] > 1) {
1488 hmin = std::min(hmin, dx0[idim]*Real(accum_coarsen_ratio.back()[idim]));
1489 }
1490 }
1491 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1492 if (!is_coarsenable[idim] || dx0[idim]*Real(accum_coarsen_ratio.back()[idim]) >= Real(1.5)*hmin) {
1493 is_coarsenable[idim] = true;
1494 rr_level[idim] = 1;
1495 }
1496 }
1497 }
1498 if (is_coarsenable != IntVect(1) || rr_level == IntVect(1)) {
1499 break;
1500 }
1501 if (do_semicoarsening_level && info.semicoarsening_direction == -1) {
1502 // make sure there is at most one direction that is not coarsened
1503 int n_ones = AMREX_D_TERM( static_cast<int>(rr_level[0] == 1),
1504 + static_cast<int>(rr_level[1] == 1),
1505 + static_cast<int>(rr_level[2] == 1));
1506 if (n_ones > 1 && !aniso_coarsening) { break; }
1507 }
1508 bool semi_level = false; // odd ratios do not count
1509 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1510 semi_level = semi_level || (rr_level[idim] == 1 && rr_base[idim] != 1);
1511 }
1512 if (semi_level) {
1513 ++numsclevs;
1514 }
1515
1516 accum_coarsen_ratio.push_back(accum_coarsen_ratio.back()*rr_level);
1517 domainboxes.push_back(dbx.coarsen(rr_level));
1518 boundboxes.push_back(bbx.coarsen(rr_level));
1519 bool to_agg = (bbx.d_numPts() / nbxs)
1520 < Real(0.999)*static_cast<Real>(threshold_npts);
1521 agg_flag.push_back(to_agg);
1522 }
1523
1524 for (int lev = 1, nlevs = static_cast<int>(domainboxes.size()); lev < nlevs; ++lev) {
1525 if (!agged && !agg_flag[lev] &&
1526 ba0.coarsenable(accum_coarsen_ratio[lev], mg_box_min_width_v))
1527 {
1528 m_grids[0].push_back(amrex::coarsen(ba0, accum_coarsen_ratio[lev]));
1529 m_dmap[0].push_back(dm0);
1530 } else {
1531 IntVect cr = domainboxes[lev-1].length() / domainboxes[lev].length();
1532 if (!agged && lev > 1 && !m_grids[0].back().coarsenable(cr)) {
1533 // The boxes of level lev-1 cannot be coarsened further,
1534 // so agglomerate from that level instead.
1535 m_grids[0].pop_back();
1536 m_dmap[0].pop_back();
1537 m_geom[0].pop_back();
1538 --lev;
1539 cr = domainboxes[lev-1].length() / domainboxes[lev].length();
1540 }
1541 if (!m_grids[0].back().coarsenable(cr)) {
1542 break; // average_down would fail if fine boxarray is not coarsenable.
1543 }
1544 m_grids[0].emplace_back(boundboxes[lev]);
1545 Box const cell_box = amrex::enclosedCells(boundboxes[lev]);
1546 if (cell_box.numPts() > threshold_npts) {
1547 IntVect max_grid_size(info.agg_grid_size);
1548 if (info.do_semicoarsening && info.max_semicoarsening_level >= lev
1549 && info.semicoarsening_direction != -1)
1550 {
1551 IntVect blen = cell_box.size();
1552 AMREX_D_TERM(int mgs_0 = (max_grid_size[0]+blen[0]-1) / blen[0];,
1553 int mgs_1 = (max_grid_size[1]+blen[1]-1) / blen[1];,
1554 int mgs_2 = (max_grid_size[2]+blen[2]-1) / blen[2]);
1555 max_grid_size[info.semicoarsening_direction]
1556 *= AMREX_D_TERM(mgs_0, *mgs_1, *mgs_2);
1557 }
1558 if (mg_agg_no_split_direction >= 0 &&
1559 mg_agg_no_split_direction < AMREX_SPACEDIM)
1560 {
1561 int const d = mg_agg_no_split_direction;
1562 max_grid_size[d] = std::max(max_grid_size[d], cell_box.length(d));
1563 }
1564 // Chop in units of the next coarsening ratio, so that
1565 // the boxes can be coarsened.
1566 IntVect const rn = (lev+1 < nlevs)
1567 ? domainboxes[lev].length() / domainboxes[lev+1].length() : IntVect(1);
1568 BoxArray& cba = m_grids[0].back();
1569 cba.coarsen(rn);
1570 cba.maxSize((max_grid_size+rn-1)/rn);
1571 cba.refine(rn);
1572 }
1573 m_dmap[0].push_back(DistributionMapping());
1574 if (!agged) {
1575 agged = true;
1576 agg_lev = lev;
1577 }
1578 }
1579 m_geom[0].emplace_back(domainboxes[lev],rb,coord,is_per);
1580 }
1581 }
1582 else
1583 {
1584 Long consolidation_threshold = 0;
1585 Real avg_npts = 0.0;
1586 if (info.do_consolidation) {
1587 avg_npts = static_cast<Real>(ba0.d_numPts()) / static_cast<Real>(ParallelContext::NProcsSub());
1588 consolidation_threshold = AMREX_D_TERM(Long(info.con_grid_size),
1589 *info.con_grid_size,
1590 *info.con_grid_size);
1591 }
1592
1593 Box const& dom0 = geom0.Domain();
1594 IntVect rr_vec(1);
1595 int numsclevs = 0;
1596 for (int lev = 0; lev < info.max_coarsening_level; ++lev)
1597 {
1598 IntVect const rr_base = base_ratio(rr_vec);
1599 IntVect rr_level = rr_base;
1600 bool do_semicoarsening_level = info.do_semicoarsening
1601 && numsclevs < info.max_semicoarsening_level;
1602 if (do_semicoarsening_level
1603 && info.semicoarsening_direction != -1)
1604 {
1605 rr_level[info.semicoarsening_direction] = 1;
1606 }
1607 IntVect is_coarsenable;
1608 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1609 IntVect rr_dir(1);
1610 rr_dir[idim] = rr_vec[idim] * rr_level[idim];
1611 is_coarsenable[idim] = dom0.coarsenable(rr_dir, mg_domain_min_width_v)
1612 && ba0.coarsenable(rr_dir, mg_box_min_width_v);
1613 for (int r : {3, 5}) {
1614 if (is_coarsenable[idim] || !mg_odd_coarsening || rr_level[idim] != 2) {
1615 break;
1616 }
1617 rr_dir[idim] = rr_vec[idim] * r;
1618 if (dom0.coarsenable(rr_dir, mg_domain_min_width_v)
1619 && ba0.coarsenable(rr_dir, mg_box_min_width_v))
1620 {
1621 is_coarsenable[idim] = true;
1622 rr_level[idim] = r;
1623 }
1624 }
1625 if (!is_coarsenable[idim] && do_semicoarsening_level
1626 && info.semicoarsening_direction == -1)
1627 {
1628 is_coarsenable[idim] = true;
1629 rr_level[idim] = 1;
1630 }
1631 }
1632 if (mg_independent_coarsening) {
1633 // A direction that cannot be coarsened gets ratio 1, and one whose
1634 // cells are 1.5 times longer than the shortest coarsenable waits.
1635 Real hmin = std::numeric_limits<Real>::max();
1636 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1637 if (is_coarsenable[idim] && rr_level[idim] > 1) {
1638 hmin = std::min(hmin, dx0[idim]*Real(rr_vec[idim]));
1639 }
1640 }
1641 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1642 if (!is_coarsenable[idim] || dx0[idim]*Real(rr_vec[idim]) >= Real(1.5)*hmin) {
1643 is_coarsenable[idim] = true;
1644 rr_level[idim] = 1;
1645 }
1646 }
1647 }
1648 if (is_coarsenable != IntVect(1) || rr_level == IntVect(1)) {
1649 break;
1650 }
1651 if (do_semicoarsening_level && info.semicoarsening_direction == -1) {
1652 // make sure there is at most one direction that is not coarsened
1653 int n_ones = AMREX_D_TERM( static_cast<int>(rr_level[0] == 1),
1654 + static_cast<int>(rr_level[1] == 1),
1655 + static_cast<int>(rr_level[2] == 1));
1656 if (n_ones > 1 && !aniso_coarsening) { break; }
1657 }
1658 bool semi_level = false; // odd ratios do not count
1659 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1660 semi_level = semi_level || (rr_level[idim] == 1 && rr_base[idim] != 1);
1661 }
1662 if (semi_level) {
1663 ++numsclevs;
1664 }
1665 rr_vec *= rr_level;
1666
1667 m_geom[0].emplace_back(amrex::coarsen(dom0, rr_vec), rb, coord, is_per);
1668 m_grids[0].push_back(amrex::coarsen(ba0, rr_vec));
1669
1670 if (info.do_consolidation)
1671 {
1672 if (avg_npts/static_cast<Real>(AMREX_D_TERM(rr_vec[0], *rr_vec[1], *rr_vec[2]))
1673 < Real(0.999)*static_cast<Real>(consolidation_threshold))
1674 {
1675 coned = true;
1676 con_lev = m_dmap[0].size();
1677 m_dmap[0].push_back(DistributionMapping());
1678 }
1679 else
1680 {
1681 m_dmap[0].push_back(m_dmap[0].back());
1682 }
1683 }
1684 else
1685 {
1686 m_dmap[0].push_back(dm0);
1687 }
1688 }
1689 }
1690
1691 m_num_mg_levels[0] = m_grids[0].size();
1692
1693 for (int mglev = 0; mglev < m_num_mg_levels[0] - 1; mglev++){
1694 const Box& fine_domain = m_geom[0][mglev].Domain();
1695 const Box& crse_domain = m_geom[0][mglev+1].Domain();
1696 mg_coarsen_ratio_vec.push_back(fine_domain.length()/crse_domain.length());
1697 }
1698
1699 for (int amrlev = 0; amrlev < m_num_amr_levels; ++amrlev) {
1700 if (AMRRefRatio(amrlev) == 4 && mg_coarsen_ratio_vec.empty()) {
1701 mg_coarsen_ratio_vec.push_back(IntVect(2));
1702 }
1703 }
1704
1705 if (agged)
1706 {
1707 makeAgglomeratedDMap(m_grids[0], m_dmap[0]);
1708 }
1709 else if (coned)
1710 {
1711 makeConsolidatedDMap(m_grids[0], m_dmap[0], info.con_ratio, info.con_strategy);
1712 }
1713
1714 if (agged || coned)
1715 {
1716 m_bottom_comm = makeSubCommunicator(m_dmap[0].back());
1717 }
1718 else
1719 {
1720 m_bottom_comm = m_default_comm;
1721 }
1722
1723 m_do_agglomeration = agged;
1724 m_do_consolidation = coned;
1725
1726 if (verbose > 1) {
1727 if (agged) {
1728 Print() << "MLLinOp::defineGrids(): agglomerated AMR level 0 starting at MG level "
1729 << agg_lev << " of " << m_num_mg_levels[0] << "\n";
1730 } else if (coned) {
1731 Print() << "MLLinOp::defineGrids(): consolidated AMR level 0 starting at MG level "
1732 << con_lev << " of " << m_num_mg_levels[0]
1733 << " (ratio = " << info.con_ratio << ")" << "\n";
1734 } else {
1735 Print() << "MLLinOp::defineGrids(): no agglomeration or consolidation of AMR level 0\n";
1736 }
1737 }
1738
1739 for (int mglev = 1; mglev < m_num_mg_levels[0]; ++mglev)
1740 {
1741 m_factory[0].emplace_back(makeFactory(0,mglev));
1742 }
1743}
1744
1745template <typename MF>
1746void
1756
1757template <typename MF>
1758void
1759MLLinOpT<MF>::defineBC ()
1760{
1761 m_needs_coarse_data_for_bc = !m_domain_covered[0];
1762
1763 levelbc_raii.resize(m_num_amr_levels);
1764 robin_a_raii.resize(m_num_amr_levels);
1765 robin_b_raii.resize(m_num_amr_levels);
1766 robin_f_raii.resize(m_num_amr_levels);
1767}
1768
1769template <typename MF>
1770void
1772 const Array<BCType,AMREX_SPACEDIM>& a_hibc) noexcept
1773{
1774 const int ncomp = getNComp();
1776 Vector<Array<BCType,AMREX_SPACEDIM> >(ncomp,a_hibc));
1777}
1778
1779template <typename MF>
1780void
1782 const Vector<Array<BCType,AMREX_SPACEDIM> >& a_hibc)
1783{
1784 const int ncomp = getNComp();
1785 AMREX_ASSERT_WITH_MESSAGE(ncomp == a_lobc.size() && ncomp == a_hibc.size(),
1786 "MLLinOp::setDomainBC: wrong size");
1787 m_lobc = a_lobc;
1788 m_hibc = a_hibc;
1791 for (int icomp = 0; icomp < ncomp; ++icomp) {
1792 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1793 if (m_geom[0][0].isPeriodic(idim)) {
1794 AMREX_ALWAYS_ASSERT(m_lobc[icomp][idim] == BCType::Periodic &&
1795 m_hibc[icomp][idim] == BCType::Periodic);
1796 } else {
1797 AMREX_ALWAYS_ASSERT(m_lobc[icomp][idim] != BCType::Periodic &&
1798 m_hibc[icomp][idim] != BCType::Periodic);
1799 }
1800
1801 if (m_lobc[icomp][idim] == LinOpBCType::inhomogNeumann ||
1802 m_lobc[icomp][idim] == LinOpBCType::Robin)
1803 {
1804 m_lobc[icomp][idim] = LinOpBCType::Neumann;
1805 }
1806
1807 if (m_hibc[icomp][idim] == LinOpBCType::inhomogNeumann ||
1808 m_hibc[icomp][idim] == LinOpBCType::Robin)
1809 {
1810 m_hibc[icomp][idim] = LinOpBCType::Neumann;
1811 }
1812 }
1813 }
1814
1815 if (hasHiddenDimension()) {
1816 const int hd = hiddenDirection();
1817 for (int n = 0; n < ncomp; ++n) {
1820 }
1821 }
1822
1824 amrex::Abort("Inhomogeneous Neumann BC not supported");
1825 }
1826 if (hasRobinBC() && !supportRobinBC()) {
1827 amrex::Abort("Robin BC not supported");
1828 }
1829}
1830
1831template <typename MF>
1832bool
1833MLLinOpT<MF>::hasBC (BCType bct) const noexcept
1834{
1835 int ncomp = m_lobc_orig.size();
1836 for (int n = 0; n < ncomp; ++n) {
1837 for (int idim = 0; idim <AMREX_SPACEDIM; ++idim) {
1838 if (m_lobc_orig[n][idim] == bct || m_hibc_orig[n][idim] == bct) {
1839 return true;
1840 }
1841 }
1842 }
1843 return false;
1844}
1845
1846template <typename MF>
1847bool
1849{
1850 return hasBC(BCType::inhomogNeumann);
1851}
1852
1853template <typename MF>
1854bool
1856{
1857 return hasBC(BCType::Robin);
1858}
1859
1860template <typename MF>
1861Box
1862MLLinOpT<MF>::compactify (Box const& b) const noexcept
1863{
1864#if (AMREX_SPACEDIM == 3)
1865 if (info.hasHiddenDimension()) {
1866 const auto& lo = b.smallEnd();
1867 const auto& hi = b.bigEnd();
1868 if (info.hidden_direction == 0) {
1869 return Box(IntVect(lo[1],lo[2],0), IntVect(hi[1],hi[2],0), b.ixType());
1870 } else if (info.hidden_direction == 1) {
1871 return Box(IntVect(lo[0],lo[2],0), IntVect(hi[0],hi[2],0), b.ixType());
1872 } else {
1873 return Box(IntVect(lo[0],lo[1],0), IntVect(hi[0],hi[1],0), b.ixType());
1874 }
1875 } else
1876#endif
1877 {
1878 return b;
1879 }
1880}
1881
1882template <typename MF>
1883void
1884MLLinOpT<MF>::makeAgglomeratedDMap (const Vector<BoxArray>& ba,
1886{
1887 BL_PROFILE("MLLinOp::makeAgglomeratedDMap");
1888
1889 BL_ASSERT(!dm[0].empty());
1890 for (int i = 1, N=static_cast<int>(ba.size()); i < N; ++i)
1891 {
1892 if (dm[i].empty())
1893 {
1894 const std::vector< std::vector<int> >& sfc = DistributionMapping::makeSFC(ba[i]);
1895
1896 const int nprocs = ParallelContext::NProcsSub();
1897 AMREX_ASSERT(std::ssize(sfc) == nprocs);
1898
1899 Vector<int> pmap(ba[i].size());
1900 for (int iproc = 0; iproc < nprocs; ++iproc) {
1901 int grank = ParallelContext::local_to_global_rank(iproc);
1902 for (int ibox : sfc[iproc]) {
1903 pmap[ibox] = grank;
1904 }
1905 }
1906 dm[i].define(std::move(pmap));
1907 }
1908 }
1909}
1910
1911template <typename MF>
1912void
1913MLLinOpT<MF>::makeConsolidatedDMap (const Vector<BoxArray>& ba,
1915 int ratio, int strategy)
1916{
1917 BL_PROFILE("MLLinOp::makeConsolidatedDMap()");
1918
1919 int factor = 1;
1920 BL_ASSERT(!dm[0].empty());
1921 for (int i = 1, N=static_cast<int>(ba.size()); i < N; ++i)
1922 {
1923 if (dm[i].empty())
1924 {
1925 factor *= ratio;
1926
1927 const int nprocs = ParallelContext::NProcsSub();
1928 const auto& pmap_fine = dm[i-1].ProcessorMap();
1929 Vector<int> pmap(pmap_fine.size());
1930 ParallelContext::global_to_local_rank(pmap.data(), pmap_fine.data(), static_cast<int>(pmap.size()));
1931 if (strategy == 1) {
1932 for (auto& x: pmap) {
1933 x /= ratio;
1934 }
1935 } else if (strategy == 2) {
1936 int nprocs_con = static_cast<int>(std::ceil(static_cast<Real>(nprocs)
1937 / static_cast<Real>(factor)));
1938 for (auto& x: pmap) {
1939 auto d = std::div(x,nprocs_con);
1940 x = d.rem;
1941 }
1942 } else if (strategy == 3) {
1943 if (factor == ratio) {
1944 const std::vector< std::vector<int> >& sfc = DistributionMapping::makeSFC(ba[i]);
1945 for (int iproc = 0; iproc < nprocs; ++iproc) {
1946 for (int ibox : sfc[iproc]) {
1947 pmap[ibox] = iproc;
1948 }
1949 }
1950 }
1951 for (auto& x: pmap) {
1952 x /= ratio;
1953 }
1954 }
1955
1957 dm[i].define(std::move(pmap));
1958 } else {
1959 Vector<int> pmap_g(pmap.size());
1960 ParallelContext::local_to_global_rank(pmap_g.data(), pmap.data(), static_cast<int>(pmap.size()));
1961 dm[i].define(std::move(pmap_g));
1962 }
1963 }
1964 }
1965}
1966
1967template <typename MF>
1969MLLinOpT<MF>::makeSubCommunicator (const DistributionMapping& dm)
1970{
1971 BL_PROFILE("MLLinOp::makeSubCommunicator()");
1972
1973#ifdef BL_USE_MPI
1974
1975 Vector<int> newgrp_ranks = dm.ProcessorMap();
1976 std::ranges::sort(newgrp_ranks);
1977 auto last = std::unique(newgrp_ranks.begin(), newgrp_ranks.end());
1978 newgrp_ranks.erase(last, newgrp_ranks.end());
1979
1980 MPI_Comm newcomm;
1981 MPI_Group defgrp, newgrp;
1982 MPI_Comm_group(m_default_comm, &defgrp);
1984 MPI_Group_incl(defgrp, static_cast<int>(newgrp_ranks.size()), newgrp_ranks.data(), &newgrp);
1985 } else {
1986 Vector<int> local_newgrp_ranks(newgrp_ranks.size());
1987 ParallelContext::global_to_local_rank(local_newgrp_ranks.data(),
1988 newgrp_ranks.data(), static_cast<int>(newgrp_ranks.size()));
1989 MPI_Group_incl(defgrp, static_cast<int>(local_newgrp_ranks.size()), local_newgrp_ranks.data(), &newgrp);
1990 }
1991
1992 MPI_Comm_create(m_default_comm, newgrp, &newcomm);
1993
1994 m_raii_comm = std::make_unique<CommContainer>(newcomm);
1995
1996 MPI_Group_free(&defgrp);
1997 MPI_Group_free(&newgrp);
1998
1999 return newcomm;
2000#else
2002 return m_default_comm;
2003#endif
2004}
2005
2006template <typename MF>
2007void
2009 const Array<Real,AMREX_SPACEDIM>& hi_bcloc) noexcept
2010{
2011 m_domain_bloc_lo = lo_bcloc;
2012 m_domain_bloc_hi = hi_bcloc;
2013}
2014
2015template <typename MF>
2016void
2017MLLinOpT<MF>::setCoarseFineBC (const MF* crse, int crse_ratio,
2018 LinOpBCType bc_type) noexcept
2019{
2020 setCoarseFineBC(crse, IntVect(crse_ratio), bc_type);
2021}
2022
2023template <typename MF>
2024void
2025MLLinOpT<MF>::setCoarseFineBC (const MF* crse, IntVect const& crse_ratio,
2026 LinOpBCType bc_type) noexcept
2027{
2028 m_coarse_data_for_bc = crse;
2029 m_coarse_data_crse_ratio = crse_ratio;
2030 m_coarse_fine_bc_type = bc_type;
2031}
2032
2033template <typename MF>
2034template <typename AMF>
2035requires (!std::same_as<MF,AMF>)
2036void
2037MLLinOpT<MF>::setCoarseFineBC (const AMF* crse, int crse_ratio,
2038 LinOpBCType bc_type) noexcept
2039{
2040 setCoarseFineBC(crse, IntVect(crse_ratio), bc_type);
2041}
2042
2043template <typename MF>
2044template <typename AMF>
2045requires (!std::same_as<MF,AMF>)
2046void
2047MLLinOpT<MF>::setCoarseFineBC (const AMF* crse, IntVect const& crse_ratio,
2048 LinOpBCType bc_type) noexcept
2049{
2050 if (crse) {
2051 m_coarse_data_for_bc_raii = MF(crse->boxArray(), crse->DistributionMap(),
2052 crse->nComp(), crse->nGrowVect());
2053 m_coarse_data_for_bc_raii.LocalCopy(*crse, 0, 0, crse->nComp(),
2054 crse->nGrowVect());
2056 } else {
2057 m_coarse_data_for_bc = nullptr;
2058 }
2059 m_coarse_data_crse_ratio = crse_ratio;
2060 m_coarse_fine_bc_type = bc_type;
2061}
2062
2063template <typename MF>
2064void
2066{
2067 mf.clear();
2068 mf.resize(m_num_amr_levels);
2069 for (int alev = 0; alev < m_num_amr_levels; ++alev) {
2070 mf[alev].resize(m_num_mg_levels[alev]);
2071 for (int mlev = 0; mlev < m_num_mg_levels[alev]; ++mlev) {
2072 mf[alev][mlev] = make(alev, mlev, ng);
2073 }
2074 }
2075}
2076
2077template <typename MF>
2078MF
2079MLLinOpT<MF>::make (int amrlev, int mglev, IntVect const& ng) const
2080{
2081 return make(amrlev, mglev, ng, MFInfo());
2082}
2083
2084template <typename MF>
2085MF
2086MLLinOpT<MF>::make (int amrlev, int mglev, IntVect const& ng, MFInfo const& mf_info) const
2087{
2088 if constexpr (IsMultiFabLike_v<MF>) {
2089 return MF(amrex::convert(m_grids[amrlev][mglev], m_ixtype),
2090 m_dmap[amrlev][mglev], getNComp(), ng, mf_info,
2091 *m_factory[amrlev][mglev]);
2092 } else {
2093 amrex::ignore_unused(amrlev, mglev, ng);
2094 amrex::Abort("MLLinOpT::make: how did we get here?");
2095 return {};
2096 }
2097}
2098
2099template <typename MF>
2100MF
2101MLLinOpT<MF>::makeAlias (MF const& mf) const
2102{
2103 if constexpr (IsMultiFabLike_v<MF>) {
2104 return MF(mf, amrex::make_alias, 0, mf.nComp());
2105 } else {
2107 amrex::Abort("MLLinOpT::makeAlias: how did we get here?");
2108 return {};
2109 }
2110}
2111
2112template <typename MF>
2113MF
2114MLLinOpT<MF>::makeCoarseMG (int amrlev, int mglev, IntVect const& ng) const
2115{
2116 return makeCoarseMG(amrlev, mglev, ng, MFInfo());
2117}
2118
2119template <typename MF>
2120MF
2121MLLinOpT<MF>::makeCoarseMG (int amrlev, int mglev, IntVect const& ng,
2122 MFInfo const& mf_info) const
2123{
2124 if constexpr (IsMultiFabLike_v<MF>) {
2125 BoxArray cba = m_grids[amrlev][mglev];
2126 IntVect ratio = (amrlev > 0) ? IntVect(2) : mg_coarsen_ratio_vec[mglev];
2127 if (hasHiddenDimension()) { ratio[hiddenDirection()] = 1; }
2128 cba.coarsen(ratio);
2129 cba.convert(m_ixtype);
2130 return MF(cba, m_dmap[amrlev][mglev], getNComp(), ng, mf_info);
2131 } else {
2132 amrex::ignore_unused(amrlev, mglev, ng);
2133 amrex::Abort("MLLinOpT::makeCoarseMG: how did we get here?");
2134 return {};
2135 }
2136}
2137
2138template <typename MF>
2139MF
2140MLLinOpT<MF>::makeCoarseAmr (int famrlev, IntVect const& ng) const
2141{
2142 return makeCoarseAmr(famrlev, ng, MFInfo());
2143}
2144
2145template <typename MF>
2146MF
2147MLLinOpT<MF>::makeCoarseAmr (int famrlev, IntVect const& ng, MFInfo const& mf_info) const
2148{
2149 if constexpr (IsMultiFabLike_v<MF>) {
2150 BoxArray cba = m_grids[famrlev][0];
2151 IntVect ratio(AMRRefRatioVect(famrlev-1));
2152 cba.coarsen(ratio);
2153 cba.convert(m_ixtype);
2154 return MF(cba, m_dmap[famrlev][0], getNComp(), ng, mf_info);
2155 } else {
2156 amrex::ignore_unused(famrlev, ng);
2157 amrex::Abort("MLLinOpT::makeCoarseAmr: how did we get here?");
2158 return {};
2159 }
2160}
2161
2162template <typename MF>
2163void
2165{
2166 if (new_size <= 0 || new_size >= m_num_mg_levels[0]) { return; }
2167
2168 m_num_mg_levels[0] = new_size;
2169
2170 m_geom[0].resize(new_size);
2171 m_grids[0].resize(new_size);
2172 m_dmap[0].resize(new_size);
2173 m_factory[0].resize(new_size);
2174
2176 m_bottom_comm = makeSubCommunicator(m_dmap[0].back());
2177 }
2178}
2179
2180template <typename MF>
2181void
2182MLLinOpT<MF>::avgDownResMG (int clev, MF& cres, MF const& fres) const
2183{
2184 amrex::ignore_unused(clev, cres, fres);
2185 if constexpr (amrex::IsFabArray<MF>::value) {
2186 const int ncomp = this->getNComp();
2187#ifdef AMREX_USE_EB
2188 if (!fres.isAllRegular()) {
2189 if constexpr (std::is_same<MF,MultiFab>()) {
2190 amrex::EB_average_down(fres, cres, 0, ncomp,
2191 mg_coarsen_ratio_vec[clev-1]);
2192 } else {
2193 amrex::Abort("EB_average_down only works with MultiFab");
2194 }
2195 } else
2196#endif
2197 {
2198 amrex::average_down(fres, cres, 0, ncomp, mg_coarsen_ratio_vec[clev-1]);
2199 }
2200 } else {
2201 amrex::Abort("For non-FabArray, MLLinOpT<MF>::avgDownResMG should be overridden.");
2202 }
2203}
2204
2205template <typename MF>
2206bool
2207MLLinOpT<MF>::isMFIterSafe (int amrlev, int mglev1, int mglev2) const
2208{
2209 return m_dmap[amrlev][mglev1] == m_dmap[amrlev][mglev2]
2210 && BoxArray::SameRefs(m_grids[amrlev][mglev1], m_grids[amrlev][mglev2]);
2211}
2212
2213template <typename MF>
2214template <MultiFabLike AMF>
2215requires (!std::same_as<MF,AMF>)
2216void
2217MLLinOpT<MF>::setLevelBC (int amrlev, const AMF* levelbcdata,
2218 const AMF* robinbc_a, const AMF* robinbc_b,
2219 const AMF* robinbc_f)
2220{
2221 const int ncomp = this->getNComp();
2222 if (levelbcdata) {
2223 levelbc_raii[amrlev] = std::make_unique<MF>(levelbcdata->boxArray(),
2224 levelbcdata->DistributionMap(),
2225 ncomp, levelbcdata->nGrowVect());
2226 levelbc_raii[amrlev]->LocalCopy(*levelbcdata, 0, 0, ncomp,
2227 levelbcdata->nGrowVect());
2228 } else {
2229 levelbc_raii[amrlev].reset();
2230 }
2231
2232 if (robinbc_a) {
2233 robin_a_raii[amrlev] = std::make_unique<MF>(robinbc_a->boxArray(),
2234 robinbc_a->DistributionMap(),
2235 ncomp, robinbc_a->nGrowVect());
2236 robin_a_raii[amrlev]->LocalCopy(*robinbc_a, 0, 0, ncomp,
2237 robinbc_a->nGrowVect());
2238 } else {
2239 robin_a_raii[amrlev].reset();
2240 }
2241
2242 if (robinbc_b) {
2243 robin_b_raii[amrlev] = std::make_unique<MF>(robinbc_b->boxArray(),
2244 robinbc_b->DistributionMap(),
2245 ncomp, robinbc_b->nGrowVect());
2246 robin_b_raii[amrlev]->LocalCopy(*robinbc_b, 0, 0, ncomp,
2247 robinbc_b->nGrowVect());
2248 } else {
2249 robin_b_raii[amrlev].reset();
2250 }
2251
2252 if (robinbc_f) {
2253 robin_f_raii[amrlev] = std::make_unique<MF>(robinbc_f->boxArray(),
2254 robinbc_f->DistributionMap(),
2255 ncomp, robinbc_f->nGrowVect());
2256 robin_f_raii[amrlev]->LocalCopy(*robinbc_f, 0, 0, ncomp,
2257 robinbc_f->nGrowVect());
2258 } else {
2259 robin_f_raii[amrlev].reset();
2260 }
2261
2262 this->setLevelBC(amrlev, levelbc_raii[amrlev].get(), robin_a_raii[amrlev].get(),
2263 robin_b_raii[amrlev].get(), robin_f_raii[amrlev].get());
2264}
2265
2266template <typename MF>
2267auto
2269{
2271 return xdoty(0,0,*x[0],*y[0],false);
2272}
2273
2274template <typename MF>
2275auto
2277{
2279 auto r = xdoty(0,0,*x[0],*x[0],false);
2280 return std::sqrt(r);
2281}
2282
2283extern template class MLLinOpT<MultiFab>;
2284
2287
2288}
2289
2290#endif
Type-erased container that supports move-only types.
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:593
#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.
#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
BoxArray & refine(int refinement_ratio)
Refine each Box in the BoxArray by refinement_ratio.
Definition AMReX_BoxArray.cpp:606
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
BoxArray & maxSize(int block_size)
Split any Box whose side length exceeds block_size.
Definition AMReX_BoxArray.cpp:553
GpuArray< Real, 3 > CellSizeArray() const noexcept
Returns the cell sizes as a GpuArray for use on host or device.
Definition AMReX_CoordSys.H:85
Default FabFactory that calls new / delete on the FAB type directly.
Definition AMReX_FabFactory.H:124
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
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:87
Interface
HYPRE interface modes supported.
Definition AMReX_Hypre.H:70
Definition AMReX_MLLinOp.H:142
virtual void copyNSolveSolution(MF &dst, MF const &src) const
Copy an NSolve solution from src to dst.
Definition AMReX_MLLinOp.H:857
const MultiFab * m_coarse_data_for_bc
Definition AMReX_MLLinOp.H:1008
bool mg_odd_coarsening
Definition AMReX_MLLinOp.H:947
virtual void postSolve(Vector< MF * > const &sol) const
Optional hook invoked after the main solve completes.
Definition AMReX_MLLinOp.H:866
Vector< Vector< std::unique_ptr< FabFactory< FAB > > > > m_factory
Definition AMReX_MLLinOp.H:979
virtual bool scaleRHS(int amrlev, MF *rhs) const
Optionally scale the RHS to fix solvability.
Definition AMReX_MLLinOp.H:634
bool m_mg_deferred
Definition AMReX_MLLinOp.H:958
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:2182
int NAMRLevels() const noexcept
Return the number of AMR levels.
Definition AMReX_MLLinOp.H:920
friend class HypreMLNodeLap
Definition AMReX_MLLinOp.H:150
bool m_do_consolidation
Definition AMReX_MLLinOp.H:970
bool isCellCentered() const noexcept
Definition AMReX_MLLinOp.H:1062
IntVect m_ixtype
Definition AMReX_MLLinOp.H:967
void setVerbose(int v) noexcept
Set verbosity.
Definition AMReX_MLLinOp.H:309
bool isMFIterSafe(int amrlev, int mglev1, int mglev2) const
Check whether mixing MFIter loops for different MG levels is safe.
Definition AMReX_MLLinOp.H:2207
RealVect m_coarse_bc_loc
Definition AMReX_MLLinOp.H:1007
virtual bool needsUpdate() const
Does it need update if it's reused?
Definition AMReX_MLLinOp.H:366
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:2079
virtual void applyOverset(int amrlev, MF &rhs) const
Overset-only hook for zeroing regions covered by masks.
Definition AMReX_MLLinOp.H:623
FabFactory< FAB > const * Factory(int amr_lev, int mglev=0) const noexcept
Definition AMReX_MLLinOp.H:1026
LinOpEnumType::StateMode StateMode
Definition AMReX_MLLinOp.H:158
void setDomainBC(const Vector< Array< BCType, 3 > > &lobc, const Vector< Array< BCType, 3 > > &hibc)
Boundary of the whole domain.
Definition AMReX_MLLinOp.H:1781
Array< Real, 3 > m_domain_bloc_hi
Definition AMReX_MLLinOp.H:1002
T get_d0(T const &dx, T const &dy, T const &) const noexcept
Definition AMReX_MLLinOp.H:1126
MPI_Comm BottomCommunicator() const noexcept
Definition AMReX_MLLinOp.H:1053
void setEnforceSingularSolvable(bool o) noexcept
Control whether the solver should try to make singular problems solvable.
Definition AMReX_MLLinOp.H:332
MPI_Comm Communicator() const noexcept
Definition AMReX_MLLinOp.H:1054
friend class GMRESMLMGT
Definition AMReX_MLLinOp.H:149
void setPrintIndentation(std::string s)
Prefix printed messages (e.g., to indent per level).
Definition AMReX_MLLinOp.H:316
int mg_domain_min_width
Definition AMReX_MLLinOp.H:945
void setMaxOrder(int o) noexcept
Set order of interpolation at coarse/fine boundary.
Definition AMReX_MLLinOp.H:323
virtual void compGrad(int amrlev, const Array< MF *, 3 > &grad, MF &sol, Location loc) const
Compute gradients of the solution.
Definition AMReX_MLLinOp.H:569
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:399
virtual std::string name() const
Definition AMReX_MLLinOp.H:187
GpuArray< BCType, 3 > LoBC(int icomp=0) const noexcept
Definition AMReX_MLLinOp.H:1030
virtual void getEBFluxes(const Vector< MF * > &a_flux, const Vector< MF * > &a_sol) const
Extract embedded-boundary fluxes.
Definition AMReX_MLLinOp.H:771
bool doAgglomeration() const noexcept
Definition AMReX_MLLinOp.H:1058
virtual bool supportCustomBottomSolver() const
Does this operator provide its own bottom solver (BottomSolver::custom)?
Definition AMReX_MLLinOp.H:340
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:2147
MultiFab m_coarse_data_for_bc_raii
Definition AMReX_MLLinOp.H:1009
MLLinOpT< MF > & operator=(const MLLinOpT< MF > &)=delete
int mg_box_min_width
Definition AMReX_MLLinOp.H:944
std::unique_ptr< CommContainer > m_raii_comm
Definition AMReX_MLLinOp.H:999
bool m_do_semicoarsening
Definition AMReX_MLLinOp.H:972
bool hasRobinBC() const noexcept
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:732
friend class MLPoissonT
Definition AMReX_MLLinOp.H:147
Vector< Array< BCType, 3 > > m_hibc
Definition AMReX_MLLinOp.H:935
virtual void resizeMultiGrid(int new_size)
Definition AMReX_MLLinOp.H:2164
Vector< Vector< BoxArray > > m_grids
Definition AMReX_MLLinOp.H:977
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:2140
bool m_do_agglomeration
Definition AMReX_MLLinOp.H:969
virtual MF makeAlias(MF const &mf) const
Definition AMReX_MLLinOp.H:2101
Array4< T > compactify(Array4< T > const &a) const noexcept
Definition AMReX_MLLinOp.H:1112
static constexpr int mg_coarsen_ratio
Definition AMReX_MLLinOp.H:943
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:325
virtual int getNComp() const
Return number of components.
Definition AMReX_MLLinOp.H:361
void setCoarseFineBCLocation(const RealVect &cloc) noexcept
Definition AMReX_MLLinOp.H:1056
Vector< int > m_amr_ref_ratio
Definition AMReX_MLLinOp.H:962
MPI_Comm m_default_comm
Definition AMReX_MLLinOp.H:982
virtual void unapplyMetricTerm(int amrlev, int mglev, MF &rhs) const
Remove metric scaling previously applied via applyMetricTerm().
Definition AMReX_MLLinOp.H:593
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:685
bool isBottomActive() const noexcept
Definition AMReX_MLLinOp.H:1051
virtual void applyInhomogNeumannTerm(int amrlev, MF &rhs) const
Add extra terms introduced when treating inhomogeneous Neumann BC as homogeneous.
Definition AMReX_MLLinOp.H:613
virtual BottomSolver getDefaultBottomSolver() const
Definition AMReX_MLLinOp.H:337
virtual void prepareForFluxes(int amrlev, const MF *crse_bcdata=nullptr)
Ensure BC caches are populated before flux extraction.
Definition AMReX_MLLinOp.H:508
typename FabDataType< MF >::fab_type FAB
Definition AMReX_MLLinOp.H:153
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:964
bool hasBC(BCType bct) const noexcept
Definition AMReX_MLLinOp.H:1833
Vector< Vector< DistributionMapping > > m_dmap
Definition AMReX_MLLinOp.H:978
int verbose
Definition AMReX_MLLinOp.H:952
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:2086
IntVect m_coarse_data_crse_ratio
Definition AMReX_MLLinOp.H:1006
LinOpBCType BCType
Definition AMReX_MLLinOp.H:156
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:353
const Vector< int > & AMRRefRatio() const noexcept
Return AMR refinement ratios.
Definition AMReX_MLLinOp.H:1014
MLLinOpT(MLLinOpT< MF > &&)=delete
Vector< Array< BCType, 3 > > m_hibc_orig
Definition AMReX_MLLinOp.H:939
virtual void unimposeNeumannBC(int amrlev, MF &rhs) const
Undo Neumann contributions stored on the RHS.
Definition AMReX_MLLinOp.H:603
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:2017
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:946
friend class MLCGSolverT
Definition AMReX_MLLinOp.H:146
std::string print_ident
Definition AMReX_MLLinOp.H:953
virtual void interpCoarseFineSolution(int famrlev, MF &fine_sol, const MF &crse_sol) const
Before a composite solve, set the solution at the nodes that fine AMR level famrlev takes from the co...
Definition AMReX_MLLinOp.H:431
bool needsCoarseDataForBC() const noexcept
Needs coarse data for bc?
Definition AMReX_MLLinOp.H:234
typename FabDataType< MF >::value_type RT
Definition AMReX_MLLinOp.H:154
virtual void update()
Update for reuse.
Definition AMReX_MLLinOp.H:368
Vector< Array< BCType, 3 > > m_lobc_orig
Definition AMReX_MLLinOp.H:938
bool m_precond_mode
Definition AMReX_MLLinOp.H:1011
virtual std::unique_ptr< FabFactory< FAB > > makeFactory(int, int) const
Definition AMReX_MLLinOp.H:1092
bool hasHiddenDimension() const noexcept
Definition AMReX_MLLinOp.H:1107
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:537
virtual IntVect getNGrowVectRestriction() const
Definition AMReX_MLLinOp.H:1064
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:782
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:799
virtual void compFlux(int amrlev, const Array< MF *, 3 > &fluxes, MF &sol, Location loc) const
Compute fluxes.
Definition AMReX_MLLinOp.H:554
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:2268
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:2114
const Geometry & Geom(int amr_lev, int mglev=0) const noexcept
Geometry accessor for (amr_lev,mglev).
Definition AMReX_MLLinOp.H:931
virtual void endPrecondBC()
Called when the operator stops being used as a preconditioner.
Definition AMReX_MLLinOp.H:908
int hiddenDirection() const noexcept
Definition AMReX_MLLinOp.H:1108
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:2008
Vector< Array< BCType, 3 > > m_lobc
Definition AMReX_MLLinOp.H:934
Vector< int > m_domain_covered
Definition AMReX_MLLinOp.H:980
void prepareMGHierarchy()
Build the deferred MG levels of AMR level 0 once. See supportsAnisotropicCoarsening.
Definition AMReX_MLLinOp.H:1747
const MLLinOpT< MultiFab > * m_parent
Definition AMReX_MLLinOp.H:965
bool doSemicoarsening() const noexcept
Definition AMReX_MLLinOp.H:1060
virtual bool supportNSolve() const
Whether this operator supports NSolve.
Definition AMReX_MLLinOp.H:849
virtual bool supportRobinBC() const noexcept
Definition AMReX_MLLinOp.H:1045
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:486
virtual void avgDownResAmr(int clev, MF &cres, MF const &fres) const
Definition AMReX_MLLinOp.H:886
Vector< Vector< Geometry > > m_geom
Definition AMReX_MLLinOp.H:976
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:2276
MLLinOpT(const MLLinOpT< MF > &)=delete
friend class MLABecLaplacianT
Definition AMReX_MLLinOp.H:148
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:2025
MLLinOpT()=default
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:758
Box compactify(Box const &b) const noexcept
Definition AMReX_MLLinOp.H:1862
bool m_needs_coarse_data_for_bc
Definition AMReX_MLLinOp.H:1004
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:661
GpuArray< BCType, 3 > HiBC(int icomp=0) const noexcept
Definition AMReX_MLLinOp.H:1035
int maxorder
Definition AMReX_MLLinOp.H:955
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:1170
Vector< IntVect > mg_coarsen_ratio_vec
Definition AMReX_MLLinOp.H:973
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:2121
LinOpEnumType::Location Location
Definition AMReX_MLLinOp.H:159
MF MFType
Definition AMReX_MLLinOp.H:152
virtual void preparePrecond()
Prepare auxiliary data used when the operator acts as a preconditioner.
Definition AMReX_MLLinOp.H:675
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:445
LPInfo info
Definition AMReX_MLLinOp.H:950
friend class MLMGT
Definition AMReX_MLLinOp.H:145
int NMGLevels(int amrlev) const noexcept
Return the number of MG levels at given AMR level.
Definition AMReX_MLLinOp.H:928
LinOpEnumType::BCMode BCMode
Definition AMReX_MLLinOp.H:157
virtual Vector< RT > getSolvabilityOffset(int amrlev, int mglev, MF const &rhs) const
Compute offsets used to enforce solvability (per component).
Definition AMReX_MLLinOp.H:647
T get_d1(T const &, T const &dy, T const &dz) const noexcept
Definition AMReX_MLLinOp.H:1136
bool enforceSingularSolvable
Definition AMReX_MLLinOp.H:957
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:413
bool doConsolidation() const noexcept
Definition AMReX_MLLinOp.H:1059
virtual bool supportInhomogNeumannBC() const noexcept
Definition AMReX_MLLinOp.H:1046
LinOpBCType m_coarse_fine_bc_type
Definition AMReX_MLLinOp.H:1005
Array< Real, 3 > m_domain_bloc_lo
Definition AMReX_MLLinOp.H:1001
virtual bool supportsAlgMG() const
True if makeAlgMG is implemented for this operator.
Definition AMReX_MLLinOp.H:789
bool m_mg_built
Definition AMReX_MLLinOp.H:959
virtual void buildMGHierarchy()
Build the MG levels of AMR level 0 below the finest one.
Definition AMReX_MLLinOp.H:1102
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:1017
MPI_Comm m_bottom_comm
Definition AMReX_MLLinOp.H:983
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:746
virtual void beginPrecondBC()
Called when the operator starts being used as a preconditioner.
Definition AMReX_MLLinOp.H:904
virtual void applyMetricTerm(int amrlev, int mglev, MF &rhs) const
Apply metric scaling to the RHS on (amrlev,mglev).
Definition AMReX_MLLinOp.H:583
bool mg_independent_coarsening
Definition AMReX_MLLinOp.H:948
bool getEnforceSingularSolvable() const noexcept
Definition AMReX_MLLinOp.H:335
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:1020
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:807
virtual void make(Vector< Vector< MF > > &mf, IntVect const &ng) const
Definition AMReX_MLLinOp.H:2065
bool hasInhomogNeumannBC() const noexcept
Definition AMReX_MLLinOp.H:1848
void setDomainBC(const Array< BCType, 3 > &lobc, const Array< BCType, 3 > &hibc) noexcept
Boundary of the whole domain.
Definition AMReX_MLLinOp.H:1771
virtual int getNGrow(int=0, int=0) const
Definition AMReX_MLLinOp.H:363
int m_num_amr_levels
Definition AMReX_MLLinOp.H:961
Boundary helper for MLMG that manages coarse/fine and physical BC metadata.
Definition AMReX_MLMGBndry.H:20
This class provides the user with a few print options.
Definition AMReX_Print.H:35
A Box with real dimensions.
Definition AMReX_RealBox.H:28
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
ArrayND< T, 4, true > Array4
Convenient alias for a 4D ArrayND with three spatial dimensions plus a component dimension.
Definition AMReX_Array4.H:1340
__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:1632
__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:1471
__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:1666
std::array< T, N > Array
Definition AMReX_Array.H:31
MLLinOpT< MultiFab > MLLinOp
Definition AMReX_MLLinOp.H:2286
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
static constexpr int MPI_COMM_NULL
Definition AMReX_ccse-mpi.H:59
int MPI_Group
Definition AMReX_ccse-mpi.H:52
__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:360
constexpr bool IsMultiFabLike_v
Definition AMReX_TypeTraits.H:44
@ bicgstab
Definition AMReX_AlgMG.H:210
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
@ Robin
Definition AMReX_LO_BCTYPES.H:36
@ Neumann
Definition AMReX_LO_BCTYPES.H:30
@ Dirichlet
Definition AMReX_LO_BCTYPES.H:29
@ inhomogNeumann
Definition AMReX_LO_BCTYPES.H:35
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
@ y
Definition AMReX_Orientation.H:14
@ x
Definition AMReX_Orientation.H:14
BottomSolver
Definition AMReX_MLLinOp.H:42
@ algmg
Definition AMReX_MLLinOp.H:43
@ bicgcg
Definition AMReX_MLLinOp.H:43
@ petsc
Definition AMReX_MLLinOp.H:43
@ cg
Definition AMReX_MLLinOp.H:43
@ Default
Definition AMReX_MLLinOp.H:43
@ custom
Definition AMReX_MLLinOp.H:43
@ cgbicg
Definition AMReX_MLLinOp.H:43
@ hypre
Definition AMReX_MLLinOp.H:43
@ smoother
Definition AMReX_MLLinOp.H:43
@ bicgstab
Definition AMReX_MLLinOp.H:43
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
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
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
RealVectND< 3 > RealVect
Definition AMReX_ParmParse.H:39
__host__ __device__ constexpr int get(IntVectND< dim > const &iv) noexcept
Get the Idx-th element of IntVectND<dim>.
Definition AMReX_IntVect.H:1360
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:97
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:109
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:101
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
Definition AMReX_MLLinOp.H:94
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:119
StateMode
Definition AMReX_MLLinOp.H:121
@ Solution
Definition AMReX_MLLinOp.H:121
@ Correction
Definition AMReX_MLLinOp.H:121
BCMode
Definition AMReX_MLLinOp.H:120
@ Homogeneous
Definition AMReX_MLLinOp.H:120
@ Inhomogeneous
Definition AMReX_MLLinOp.H:120
Location
Definition AMReX_MLLinOp.H:122
@ CellCentroid
Definition AMReX_MLLinOp.H:122
@ FaceCentroid
Definition AMReX_MLLinOp.H:122
@ FaceCenter
Definition AMReX_MLLinOp.H:122
@ CellCenter
Definition AMReX_MLLinOp.H:122
FabArray memory allocation information.
Definition AMReX_FabArray.H:73