3#include <AMReX_Config.H>
43 :
public std::runtime_error
46 using std::runtime_error::runtime_error;
81 template <
typename AMF>
83 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file =
nullptr);
95 template <
typename AMF>
96 RT solve (std::initializer_list<AMF*> a_sol,
97 std::initializer_list<AMF const*> a_rhs,
98 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file =
nullptr);
110 RT a_tol_rel,
RT a_tol_abs);
118 template <
typename AMF>
120 Location a_loc = Location::FaceCenter);
128 template <
typename AMF>
130 Location a_loc = Location::FaceCenter);
138 template <
typename AMF>
140 Location a_loc = Location::FaceCenter);
148 template <
typename AMF>
150 Location a_loc = Location::FaceCenter);
159 template <
typename AMF>
162 Location a_loc = Location::FaceCenter);
171 template <
typename AMF>
173 std::initializer_list<AMF*> a_sol,
174 Location a_loc = Location::FaceCenter);
182 template <
typename AMF>
184 Location a_loc = Location::CellCenter);
192 template <
typename AMF>
194 Location a_loc = Location::CellCenter);
203 template <
typename AMF>
206 Location a_loc = Location::CellCenter);
215 template <
typename AMF>
217 std::initializer_list<AMF*> a_sol,
218 Location a_loc = Location::CellCenter);
301 void setFixedIter (
int nit)
noexcept { do_fixed_number_of_iters = nit; }
348 [[nodiscard]]
bool usedAlgMG () const noexcept {
return m_algmg_active; }
361 m_algmg_options = std::move(f);
362 m_algmg_bottom.reset();
363 m_algmg_level0.reset();
372 hybrid_stall_window = window; hybrid_stall_rate = rate;
409 [[deprecated(
"Use MLMG::setConvergenceNormType() instead.")]]
438 void setNSolve (
int flag)
noexcept { do_nsolve = flag; }
461 void setNoGpuSync (
bool do_not_sync)
noexcept { do_no_sync_gpu = do_not_sync; }
463#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
483 void setHypreOptionsNamespace(
const std::string& prefix)
noexcept
485 hypre_options_namespace = prefix;
489 void setHypreOldDefault (
bool l)
noexcept {hypre_old_default = l;}
491 void setHypreRelaxType (
int n)
noexcept {hypre_relax_type = n;}
493 void setHypreRelaxOrder (
int n)
noexcept {hypre_relax_order = n;}
495 void setHypreNumSweeps (
int n)
noexcept {hypre_num_sweeps = n;}
497 void setHypreStrongThreshold (
Real t)
noexcept {hypre_strong_threshold = t;}
513 template <
typename AMF>
658#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
666 template <
class TMF=MF>
667 requires (std::same_as<TMF,MultiFab>)
668 void bottomSolveWithHypre (MF&
x,
const MF& b);
671#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
679 template <
class TMF=MF>
680 requires (std::same_as<TMF,MultiFab>)
681 void bottomSolveWithPETSc (MF&
x,
const MF& b);
695 template <
class TMF=MF>
696 requires (std::same_as<TMF,MultiFab>)
701 template <
class TMF=MF>
702 requires (std::same_as<TMF,MultiFab>)
705 template <
class TMF=MF>
706 requires (std::same_as<TMF,MultiFab>)
710 template <
class TMF=MF>
711 requires (std::same_as<TMF,MultiFab>)
718 RT best_norm, std::string& reason)
const;
727 [[nodiscard]]
int getNumIters () const noexcept {
return m_iter_fine_resnorm0.size(); }
734 bool precond_mode =
false;
735 bool throw_exception =
false;
739 int do_fixed_number_of_iters = 0;
740 int max_precond_iters = 1;
747 int max_fmg_iters = 0;
751 int bottom_verbose = 0;
752 int bottom_maxiter = 200;
753 RT bottom_reltol = std::is_same<RT,double>() ?
RT(1.e-4) :
RT(1.e-3);
754 RT bottom_abstol =
RT(-1.0);
759 bool m_algmg_active =
false;
760 int hybrid_stall_window = 4;
761 RT hybrid_stall_rate =
RT(0.8);
762 RT hybrid_divergence_factor =
RT(10.0);
763 RT m_algmg_reltol =
RT(0);
764 std::function<void(
AlgMG<RT>&)> m_algmg_options;
765 std::unique_ptr<MLAlgMG> m_algmg_bottom;
766 std::unique_ptr<MLAlgMG> m_algmg_level0;
768 int final_fill_bc = 0;
775 bool linop_prepared =
false;
776 Long solve_called = 0;
779 int do_nsolve =
false;
780 int nsolve_grid_size = 16;
781 std::unique_ptr<MLLinOpT<MF>> ns_linop;
782 std::unique_ptr<MLMGT<MF>> ns_mlmg;
783 std::unique_ptr<MF> ns_sol;
784 std::unique_ptr<MF> ns_rhs;
786 std::string print_ident;
788 bool do_no_sync_gpu =
false;
791#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
796 std::unique_ptr<Hypre> hypre_solver;
797 std::unique_ptr<MLMGBndryT<MF>> hypre_bndry;
798 std::unique_ptr<HypreNodeLap> hypre_node_solver;
800 std::string hypre_options_namespace =
"hypre";
804 int hypre_num_sweeps = 2;
805 Real hypre_strong_threshold = 0.25;
809#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
810 std::unique_ptr<PETScABecLap> petsc_solver;
811 std::unique_ptr<MLMGBndryT<MF>> petsc_bndry;
834 enum timer_types { solve_time=0, iter_time, bottom_time, ntimers };
835 Vector<double> timer;
837 RT m_rhsnorm0 =
RT(-1.0);
838 RT m_init_resnorm0 =
RT(-1.0);
839 RT m_final_resnorm0 =
RT(-1.0);
840 Vector<int> m_niters_cg;
841 Vector<RT> m_iter_fine_resnorm0;
852 void checkPoint (
const Vector<MultiFab*>& a_sol,
853 const Vector<MultiFab const*>& a_rhs,
854 RT a_tol_rel,
RT a_tol_abs,
const char* a_file_name)
const;
858template <
typename MF>
860 : linop(a_lp), ncomp(a_lp.getNComp()), namrlevs(a_lp.NAMRLevels()),
861 finest_amr_lev(a_lp.NAMRLevels()-1)
866template <
typename MF>
877template <
typename MF>
878template <
typename AMF>
881 std::initializer_list<AMF const*> a_rhs,
882 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file) ->
RT
886 a_tol_rel, a_tol_abs, checkpoint_file);
889template <
typename MF>
890template <
typename AMF>
893 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file) ->
RT
904 std::optional<Gpu::SyncAtExitOnly> no_sync_region;
905 std::optional<Gpu::SingleStreamRegion> single_stream_region;
906 if (do_no_sync_gpu) {
907 no_sync_region.emplace();
908 single_stream_region.emplace();
911 if constexpr (std::is_same<AMF,MultiFab>()) {
912 if (checkpoint_file !=
nullptr) {
913 checkPoint(a_sol, a_rhs, a_tol_rel, a_tol_abs, checkpoint_file);
922 bottom_solver = linop.getDefaultBottomSolver();
926 bool eb_linop =
false;
934#if (defined(AMREX_USE_HYPRE) || defined(AMREX_USE_PETSC)) && (AMREX_SPACEDIM > 1)
938 linop.setMaxOrder(std::min(3, linop.getMaxOrder()));
940#ifdef AMREX_USE_HYPRE
942 linop.setMaxOrder(std::min(3, linop.getMaxOrder()));
950 "MLMG: AlgMG is not available for this operator (single-component cell and nodal operators only)");
953 "MLMG: AlgMG does not support the ghostnodes strategy with ghost cells");
956 linop.setMaxOrder(std::min(3, linop.getMaxOrder()));
960 bool is_nsolve = linop.m_parent;
965 "MLMG: NSolve requires the geometric multigrid type");
967 "MLMG: the hybrid multigrid type needs a convergence test; as a preconditioner or with a fixed number of iterations use geometric or algebraic");
971 RT& composite_norminf = m_final_resnorm0;
974 m_iter_fine_resnorm0.clear();
988 amrex::Print() << print_ident <<
"MLMG: Initial rhs = " << rhsnorm0 <<
"\n"
989 << print_ident <<
"MLMG: Initial residual (resid0) = " << resnorm0 <<
"\n";
993 m_init_resnorm0 = resnorm0;
994 m_rhsnorm0 = rhsnorm0;
997 if ( throw_exception ) {
998 throw error(
"MLMG: rhs or initial residual is not finite.");
1000 amrex::Abort(
"MLMG: rhs or initial residual is not finite");
1004 RT max_norm = resnorm0;
1005 std::string norm_name =
"resid0";
1006 switch (norm_type) {
1008 if (rhsnorm0 >= resnorm0) {
1009 norm_name =
"bnorm";
1010 max_norm = rhsnorm0;
1012 norm_name =
"resid0";
1013 max_norm = resnorm0;
1017 norm_name =
"bnorm";
1018 max_norm = rhsnorm0;
1021 norm_name =
"resid0";
1022 max_norm = resnorm0;
1026 const RT res_target = std::max(a_tol_abs, std::max(a_tol_rel,std::numeric_limits<RT>::epsilon())*max_norm);
1028 if (!is_nsolve && resnorm0 <= res_target) {
1029 composite_norminf = resnorm0;
1031 amrex::Print() << print_ident <<
"MLMG: No iterations needed\n";
1035 bool converged =
false;
1042 bool hybrid_composite =
false;
1043 RT best_norm = resnorm0;
1045 if (namrlevs > 1) { best_norm =
ResNormInf(finest_amr_lev); }
1046 best_sol.resize(namrlevs);
1047 for (
int alev = 0; alev < namrlevs; ++alev) {
1049 best_sol[alev] = linop.make(alev, 0, ng);
1050 LocalCopy(best_sol[alev], sol[alev], 0, 0, ncomp, ng);
1054 int niters = do_fixed_number_of_iters ? do_fixed_number_of_iters : max_iters;
1055 for (
int iter = 0; iter < niters; ++iter)
1061 m_algmg_reltol = bottom_reltol;
1062 if (!is_nsolve && !do_fixed_number_of_iters && (m_algmg_active || linop.NMGLevels(0) == 1)) {
1063 RT const resnorm = (iter == 0) ? resnorm0 : composite_norminf;
1064 m_algmg_reltol = std::max(bottom_reltol, (namrlevs == 1) ? res_target/
resnorm :
RT(1.e-2));
1074 if (is_nsolve) {
continue; }
1077 m_iter_fine_resnorm0.push_back(fine_norminf);
1078 composite_norminf = fine_norminf;
1080 amrex::Print() << print_ident <<
"MLMG: Iteration " << std::setw(3) << iter+1 <<
" Fine resid/"
1081 << norm_name <<
" = " << fine_norminf/max_norm <<
"\n";
1083 bool fine_converged = (fine_norminf <= res_target);
1085 if (namrlevs == 1 && fine_converged) {
1087 }
else if (fine_converged) {
1092 amrex::Print() << print_ident <<
"MLMG: Iteration " << std::setw(3) << iter+1
1093 <<
" Crse resid/" << norm_name <<
" = "
1094 << crse_norminf/max_norm <<
"\n";
1096 converged = (crse_norminf <= res_target);
1097 composite_norminf = std::max(fine_norminf, crse_norminf);
1104 amrex::Print() << print_ident <<
"MLMG: Final Iter. " << iter+1
1105 <<
" resid, resid/" << norm_name <<
" = "
1106 << composite_norminf <<
", "
1107 << composite_norminf/max_norm <<
"\n";
1111 if (
hybrid && !m_algmg_active) {
1112 if (fine_converged && !hybrid_composite) {
1115 hybrid_composite =
true;
1116 hybrid_norms.clear();
1117 best_norm = composite_norminf;
1118 for (
int alev = 0; alev < namrlevs; ++alev) {
1122 hybrid_norms.push_back(composite_norminf);
1126 if (!do_switch && iter+1 == niters) {
1128 reason =
"not converged";
1132 amrex::Print() << print_ident <<
"MLMG: " << reason <<
" after "
1133 << iter+1 <<
" iterations, switching to AlgMG on AMR level 0\n";
1135 if (!
amrex::isfinite(composite_norminf) || composite_norminf > best_norm) {
1136 for (
int alev = 0; alev < namrlevs; ++alev) {
1140 composite_norminf = best_norm;
1142 amrex::Print() << print_ident <<
"MLMG: restarting from the best iterate, resid/"
1143 << norm_name <<
" = " << best_norm/max_norm <<
"\n";
1146 m_algmg_active =
true;
1147 niters = iter + 1 + max_iters;
1150 if (composite_norminf < best_norm) {
1151 best_norm = composite_norminf;
1152 for (
int alev = 0; alev < namrlevs; ++alev) {
1157 if (composite_norminf >
RT(1.e20)*max_norm || !
amrex::isfinite(composite_norminf))
1160 amrex::Print() << print_ident <<
"MLMG: Failing to converge after " << iter+1 <<
" iterations."
1161 <<
" resid, resid/" << norm_name <<
" = "
1162 << composite_norminf <<
", "
1163 << composite_norminf/max_norm <<
"\n";
1166 if ( throw_exception ) {
1167 throw error(
"MLMG blew up.");
1175 if (!converged && do_fixed_number_of_iters == 0) {
1177 amrex::Print() << print_ident <<
"MLMG: Failed to converge after " << niters <<
" iterations."
1178 <<
" resid, resid/" << norm_name <<
" = "
1179 << composite_norminf <<
", "
1180 << composite_norminf/max_norm <<
"\n";
1183 if ( throw_exception ) {
1184 throw error(
"MLMG failed to converge.");
1195 if (linop.hasHiddenDimension()) {
1196 ng_back[linop.hiddenDirection()] = 0;
1198 for (
int alev = 0; alev < namrlevs; ++alev)
1200 if (!sol_is_alias[alev]) {
1201 LocalCopy(*a_sol[alev], sol[alev], 0, 0, ncomp, ng_back);
1211 amrex::AllPrint() << print_ident <<
"MLMG: Timers: Solve = " << timer[solve_time]
1212 <<
" Iter = " << timer[iter_time]
1213 <<
" Bottom = " << timer[bottom_time] <<
"\n";
1219 return composite_norminf;
1222template <
typename MF>
1225 RT a_tol_rel,
RT a_tol_abs) ->
RT
1227 precond_mode =
true;
1228 std::swap(max_precond_iters, do_fixed_number_of_iters);
1229 linop.beginPrecondBC();
1231 auto r =
solve(a_sol, a_rhs, a_tol_rel, a_tol_abs);
1233 linop.endPrecondBC();
1234 std::swap(max_precond_iters, do_fixed_number_of_iters);
1235 precond_mode =
false;
1240template <
typename MF>
1244 for (
int alev = finest_amr_lev; alev >= 0; --alev) {
1245 const MF* crse_bcdata = (alev > 0) ? a_sol[alev-1] :
nullptr;
1246 linop.prepareForFluxes(alev, crse_bcdata);
1250template <
typename MF>
1251template <
typename AMF>
1256 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
1257 if constexpr (std::is_same<AMF,MF>()) {
1258 linop.compGrad(alev, a_grad_sol[alev], sol[alev], a_loc);
1261 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1262 auto const& amf = *(a_grad_sol[alev][idim]);
1265 linop.compGrad(alev,
GetArrOfPtrs(grad_sol), sol[alev], a_loc);
1266 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1267 LocalCopy(*a_grad_sol[alev][idim], grad_sol[idim], 0, 0, ncomp,
IntVect(0));
1273template <
typename MF>
1274template <
typename AMF>
1281template <
typename MF>
1282template <
typename AMF>
1287 if (!linop.isCellCentered()) {
1288 amrex::Abort(
"Calling wrong getFluxes for nodal solver");
1293 if constexpr (std::is_same<AMF,MF>()) {
1297 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1298 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1299 auto const& amf = *(a_flux[ilev][idim]);
1304 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1305 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1306 LocalCopy(*a_flux[ilev][idim], fluxes[ilev][idim], 0, 0, ncomp,
IntVect(0));
1312template <
typename MF>
1313template <
typename AMF>
1321template <
typename MF>
1322template <
typename AMF>
1329 if (!linop.isCellCentered()) {
1330 amrex::Abort(
"Calling wrong getFluxes for nodal solver");
1333 if constexpr (std::is_same<AMF,MF>()) {
1334 linop.getFluxes(a_flux, a_sol, a_loc);
1337 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1338 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1339 auto const& amf = *(a_flux[ilev][idim]);
1345 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1346 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1347 LocalCopy(*a_flux[ilev][idim], fluxes[ilev][idim], 0, 0, ncomp,
IntVect(0));
1353template <
typename MF>
1354template <
typename AMF>
1357 std::initializer_list<AMF*> a_sol,
Location a_loc)
1363template <
typename MF>
1364template <
typename AMF>
1369 if constexpr (std::is_same<AMF,MF>()) {
1373 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1374 auto const& amf = *a_flux[ilev];
1378 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1384template <
typename MF>
1385template <
typename AMF>
1392template <
typename MF>
1393template <
typename AMF>
1400 if constexpr (! std::is_same<AMF,MF>()) {
1401 for (
int alev = 0; alev < namrlevs; ++alev) {
1406 if (linop.isCellCentered())
1409 for (
int alev = 0; alev < namrlevs; ++alev) {
1410 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1411 const int mglev = 0;
1414 ffluxes[alev][idim].define(
amrex::convert(linop.m_grids[alev][mglev],
1416 linop.m_dmap[alev][mglev], ncomp, nghost,
MFInfo(),
1417 *linop.m_factory[alev][mglev]);
1420 if constexpr (std::is_same<AMF,MF>()) {
1425 for (
int alev = 0; alev < namrlevs; ++alev) {
1434 if constexpr (std::is_same<AMF,MF>()) {
1435 linop.getFluxes(a_flux, a_sol);
1438 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1439 auto const& amf = *a_flux[ilev];
1443 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
1450template <
typename MF>
1451template <
typename AMF>
1454 std::initializer_list<AMF*> a_sol,
Location a_loc)
1461template <
typename MF>
1465 if (!linop.isCellCentered()) {
1473template <
typename MF>
1479 if (!linop.isCellCentered()) {
1483 linop.getEBFluxes(a_eb_flux, a_sol);
1487template <
typename MF>
1495 if (linop.hasHiddenDimension()) { ng_sol[linop.hiddenDirection()] = 0; }
1497 sol.resize(namrlevs);
1498 sol_is_alias.resize(namrlevs,
true);
1499 for (
int alev = 0; alev < namrlevs; ++alev)
1503 sol[alev] = linop.makeAlias(*a_sol[alev]);
1504 sol_is_alias[alev] =
true;
1508 if (sol_is_alias[alev])
1510 sol[alev] = linop.make(alev, 0, ng_sol);
1511 sol_is_alias[alev] =
false;
1520 for (
int alev = finest_amr_lev; alev >= 0; --alev) {
1521 const MF* crse_bcdata = (alev > 0) ? &(sol[alev-1]) :
nullptr;
1522 const MF* prhs = a_rhs[alev];
1523#if (AMREX_SPACEDIM != 3)
1526 MFInfo(), *linop.Factory(alev));
1528 linop.applyMetricTerm(alev, 0, rhstmp);
1529 linop.unimposeNeumannBC(alev, rhstmp);
1530 linop.applyInhomogNeumannTerm(alev, rhstmp);
1533 linop.solutionResidual(alev, *a_res[alev], sol[alev], *prhs, crse_bcdata);
1534 if (alev < finest_amr_lev) {
1535 linop.reflux(alev, *a_res[alev], sol[alev], *prhs,
1536 *a_res[alev+1], sol[alev+1], *a_rhs[alev+1]);
1537 if (linop.isCellCentered()) {
1539 EB_average_down(*a_res[alev+1], *a_res[alev], 0, ncomp, linop.AMRRefRatioVect(alev));
1541 average_down(*a_res[alev+1], *a_res[alev], 0, ncomp, linop.AMRRefRatioVect(alev));
1548#if (AMREX_SPACEDIM != 3)
1549 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
1550 linop.unapplyMetricTerm(alev, 0, *a_res[alev]);
1555template <
typename MF>
1566 if (linop.hasHiddenDimension()) { ng_sol[linop.hiddenDirection()] = 0; }
1568 for (
int alev = 0; alev < namrlevs; ++alev)
1572 nghost = linop.getNGrow(alev);
1573 in[alev] = a_in[alev];
1575 else if (
nGrowVect(*a_in[alev]) == ng_sol)
1577 in[alev] = a_in[alev];
1583 in_raii[alev] = linop.make(alev, 0, ng,
1586 in[alev] = &(in_raii[alev]);
1588 rh[alev] = linop.make(alev, 0,
IntVect(nghost),
1595 for (
int alev = 0; alev < namrlevs; ++alev) {
1596 linop.applyInhomogNeumannTerm(alev, rh[alev]);
1600 for (
int alev = finest_amr_lev; alev >= 0; --alev) {
1601 const MF* crse_bcdata = (alev > 0) ? in[alev-1] :
nullptr;
1602 linop.solutionResidual(alev, *out[alev], *in[alev], rh[alev], crse_bcdata);
1603 if (alev < finest_amr_lev) {
1604 linop.reflux(alev, *out[alev], *in[alev], rh[alev],
1605 *out[alev+1], *in[alev+1], rh[alev+1]);
1606 if (linop.isCellCentered()) {
1611 average_down(*out[alev+1], *out[alev], 0,
nComp(*out[alev]), linop.AMRRefRatioVect(alev));
1614 amrex::Abort(
"MLMG: TODO average_down for non-MultiFab");
1620#if (AMREX_SPACEDIM != 3)
1621 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
1622 linop.unapplyMetricTerm(alev, 0, *out[alev]);
1626 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
1628 Scale(*out[alev],
RT(-1), 0,
nComp(*out[alev]), nghost);
1632template <
typename MF>
1636 precond_mode =
true;
1637 linop.beginPrecondBC();
1639 linop.endPrecondBC();
1640 precond_mode =
false;
1643template <
typename MF>
1644template <
typename AMF>
1653 timer.assign(ntimers, 0.0);
1657 if (linop.hasHiddenDimension()) { ng_sol[linop.hiddenDirection()] = 0; }
1659 linop.setPrintIndentation(print_ident);
1660 if (!linop_prepared) {
1661 linop.prepareForSolve();
1662 AMREX_ASSERT(!linop.m_mg_deferred || linop.m_mg_built);
1663 linop_prepared =
true;
1664 }
else if (linop.needsUpdate()) {
1667 m_algmg_bottom.reset();
1668 m_algmg_level0.reset();
1670#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
1671 hypre_solver.reset();
1672 hypre_bndry.reset();
1673 hypre_node_solver.reset();
1676#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
1677 petsc_solver.reset();
1678 petsc_bndry.reset();
1682 sol.resize(namrlevs);
1683 sol_is_alias.resize(namrlevs,
false);
1684 for (
int alev = 0; alev < namrlevs; ++alev)
1688 if constexpr (std::is_same<AMF,MF>()) {
1689 sol[alev] = linop.makeAlias(*a_sol[alev]);
1690 sol_is_alias[alev] =
true;
1692 amrex::Abort(
"Type conversion not supported for CFStrategy::ghostnodes");
1697 bool alias_made =
false;
1698 if (
nGrowVect(*a_sol[alev]) == ng_sol) {
1699 if constexpr (std::is_same<AMF,MF>()) {
1700 sol[alev] = linop.makeAlias(*a_sol[alev]);
1701 sol_is_alias[alev] =
true;
1706 if (sol_is_alias[alev] || !solve_called) {
1707 sol[alev] = linop.make(alev, 0, ng_sol);
1708 sol_is_alias[alev] =
false;
1716 rhs.resize(namrlevs);
1717 for (
int alev = 0; alev < namrlevs; ++alev)
1720 if (!solve_called) {
1721 rhs[alev] = linop.make(alev, 0, ng_rhs);
1723 LocalCopy(rhs[alev], *a_rhs[alev], 0, 0, ncomp, ng_rhs);
1724 linop.applyMetricTerm(alev, 0, rhs[alev]);
1725 linop.unimposeNeumannBC(alev, rhs[alev]);
1726 linop.applyInhomogNeumannTerm(alev, rhs[alev]);
1727 linop.applyOverset(alev, rhs[alev]);
1728 if ( ! precond_mode) {
1729 bool r = linop.scaleRHS(alev, &(rhs[alev]));
1735 if (factory && !factory->isAllRegular()) {
1736 if constexpr (std::is_same<MF,MultiFab>()) {
1740 amrex::Abort(
"TODO: MLMG with EB only works with MultiFab");
1746 for (
int falev = finest_amr_lev; falev > 0; --falev)
1748 linop.averageDownSolutionRHS(falev-1, sol[falev-1], rhs[falev-1], sol[falev], rhs[falev]);
1753 for (
int falev = 1; falev <= finest_amr_lev; ++falev) {
1754 linop.interpCoarseFineSolution(falev, sol[falev], sol[falev-1]);
1759 if (linop.isSingular(0) && linop.getEnforceSingularSolvable())
1764 IntVect ng = linop.getNGrowVectRestriction();
1766 if (!solve_called) {
1767 linop.make(res, ng);
1768 linop.make(rescor, ng);
1770 for (
int alev = 0; alev <= finest_amr_lev; ++alev)
1772 const int nmglevs = linop.NMGLevels(alev);
1773 for (
int mglev = 0; mglev < nmglevs; ++mglev)
1775 setVal(res [alev][mglev],
RT(0.0));
1776 setVal(rescor[alev][mglev],
RT(0.0));
1781 cor.resize(namrlevs);
1782 for (
int alev = 0; alev <= finest_amr_lev; ++alev)
1784 const int nmglevs = linop.NMGLevels(alev);
1785 cor[alev].resize(nmglevs);
1786 for (
int mglev = 0; mglev < nmglevs; ++mglev)
1788 if (!solve_called) {
1791 cor[alev][mglev] = linop.make(alev, mglev, _ng);
1797 cor_hold.resize(std::max(namrlevs-1,1));
1800 const int nmglevs = linop.NMGLevels(alev);
1801 cor_hold[alev].resize(nmglevs);
1802 for (
int mglev = 0; mglev < nmglevs-1; ++mglev)
1804 if (!solve_called) {
1807 cor_hold[alev][mglev] = linop.make(alev, mglev, _ng);
1809 setVal(cor_hold[alev][mglev],
RT(0.0));
1812 for (
int alev = 1; alev < finest_amr_lev; ++alev)
1814 cor_hold[alev].resize(1);
1815 if (!solve_called) {
1818 cor_hold[alev][0] = linop.make(alev, 0, _ng);
1820 setVal(cor_hold[alev][0],
RT(0.0));
1824 || !linop.supportNSolve())
1829 if (do_nsolve && ns_linop ==
nullptr)
1835 amrex::Print() << print_ident <<
"MLMG: # of AMR levels: " << namrlevs <<
"\n"
1836 << print_ident <<
" # of MG levels on the coarsest AMR level: " << linop.NMGLevels(0)
1839 amrex::Print() << print_ident <<
" # of MG levels in N-Solve: " << ns_linop->NMGLevels(0) <<
"\n"
1840 << print_ident <<
" # of grids in N-Solve: " << ns_linop->m_grids[0][0].size() <<
"\n";
1845template <
typename MF>
1849 linop.setPrintIndentation(print_ident);
1850 if (!linop_prepared) {
1851 linop.prepareForSolve();
1852 AMREX_ASSERT(!linop.m_mg_deferred || linop.m_mg_built);
1853 linop_prepared =
true;
1854 }
else if (linop.needsUpdate()) {
1857 m_algmg_bottom.reset();
1858 m_algmg_level0.reset();
1860#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
1861 hypre_solver.reset();
1862 hypre_bndry.reset();
1863 hypre_node_solver.reset();
1866#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
1867 petsc_solver.reset();
1868 petsc_bndry.reset();
1873template <
typename MF>
1878 linop.preparePrecond();
1881template <
typename MF>
1886 ns_linop = linop.makeNLinOp(nsolve_grid_size);
1891 const BoxArray& ba = (*ns_linop).m_grids[0][0];
1896 ns_sol = std::make_unique<MF>(ba, dm, ncomp, ng,
MFInfo(), *(ns_linop->Factory(0,0)));
1899 ns_rhs = std::make_unique<MF>(ba, dm, ncomp, ng,
MFInfo(), *(ns_linop->Factory(0,0)));
1903 ns_linop->setLevelBC(0, ns_sol.get());
1905 ns_mlmg = std::make_unique<MLMGT<MF>>(*ns_linop);
1906 ns_mlmg->setVerbose(0);
1907 ns_mlmg->setFixedIter(1);
1908 ns_mlmg->setMaxFmgIter(20);
1915template <
typename MF>
1920 for (
int alev = finest_amr_lev; alev > 0; --alev)
1926 LocalAdd(sol[alev], cor[alev][0], 0, 0, ncomp, nghost);
1931 if (alev != finest_amr_lev) {
1932 std::swap(cor_hold[alev][0], cor[alev][0]);
1939 if (linop.isSingular(0) && linop.getEnforceSingularSolvable())
1944 if (m_algmg_active) {
1945 if constexpr (std::is_same<MF,MultiFab>()) {
1948 amrex::Abort(
"MLMG: AlgMG is only supported for MultiFab");
1950 }
else if (iter < max_fmg_iters) {
1958 LocalAdd(sol[0], cor[0][0], 0, 0, ncomp, nghost);
1961 for (
int alev = 1; alev <= finest_amr_lev; ++alev)
1966 linop.applyOverset(alev, cor[alev][0]);
1970 LocalAdd(sol[alev], cor[alev][0], 0, 0, ncomp, nghost);
1972 if (alev != finest_amr_lev) {
1973 LocalAdd(cor_hold[alev][0], cor[alev][0], 0, 0, ncomp, nghost);
1981 LocalAdd(sol[alev], cor[alev][0], 0, 0, ncomp, nghost);
1983 if (alev != finest_amr_lev) {
1984 LocalAdd(cor[alev][0], cor_hold[alev][0], 0, 0, ncomp, nghost);
1988 linop.averageDownAndSync(sol);
1991template <
typename MF>
1996 const int mglev = 0;
2002template <
typename MF>
2008 const int mglev_bottom = linop.NMGLevels(amrlev) - 1;
2010 for (
int mglev = mglev_top; mglev < mglev_bottom; ++mglev)
2012 BL_PROFILE_VAR(
"MLMG::mgVcycle_down::"+std::to_string(mglev), blp_mgv_down_lev);
2017 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
2018 <<
" DN: Norm before smooth " <<
norm <<
"\n";
2021 setVal(cor[amrlev][mglev],
RT(0.0));
2022 bool skip_fillboundary =
true;
2023 linop.smooth(amrlev, mglev, cor[amrlev][mglev], res[amrlev][mglev], skip_fillboundary, nu1);
2031 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
2032 <<
" DN: Norm after smooth " <<
norm <<
"\n";
2036 linop.restriction(amrlev, mglev+1, res[amrlev][mglev+1], rescor[amrlev][mglev]);
2045 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
2046 <<
" DN: Norm before bottom " <<
norm <<
"\n";
2053 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
2054 <<
" UP: Norm after bottom " <<
norm <<
"\n";
2062 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
2063 <<
" Norm before smooth " <<
norm <<
"\n";
2065 setVal(cor[amrlev][mglev_bottom],
RT(0.0));
2066 bool skip_fillboundary =
true;
2067 linop.smooth(amrlev, mglev_bottom, cor[amrlev][mglev_bottom],
2068 res[amrlev][mglev_bottom], skip_fillboundary, nu1);
2073 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
2074 <<
" Norm after smooth " <<
norm <<
"\n";
2079 for (
int mglev = mglev_bottom-1; mglev >= mglev_top; --mglev)
2081 BL_PROFILE_VAR(
"MLMG::mgVcycle_up::"+std::to_string(mglev), blp_mgv_up_lev);
2088 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
2089 <<
" UP: Norm before smooth " <<
norm <<
"\n";
2091 linop.smooth(amrlev, mglev, cor[amrlev][mglev], res[amrlev][mglev],
false, nu2);
2099 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
2100 <<
" UP: Norm after smooth " <<
norm <<
"\n";
2108template <
typename MF>
2115 auto* pf = linop.Factory(0);
2116 auto is_all_regular = [pf] () {
2119 return f->isAllRegular();
2125 AMREX_ASSERT(linop.isCellCentered() || is_all_regular());
2128 const int amrlev = 0;
2129 const int mg_bottom_lev = linop.NMGLevels(amrlev) - 1;
2133 for (
int mglev = 1; mglev <= mg_bottom_lev; ++mglev)
2135 linop.avgDownResMG(mglev, res[amrlev][mglev], res[amrlev][mglev-1]);
2140 for (
int mglev = mg_bottom_lev-1; mglev >= 0; --mglev)
2148 LocalCopy(res[amrlev][mglev], rescor[amrlev][mglev], 0, 0, ncomp, nghost);
2151 std::swap(cor[amrlev][mglev], cor_hold[amrlev][mglev]);
2153 LocalAdd(cor[amrlev][mglev], cor_hold[amrlev][mglev], 0, 0, ncomp, nghost);
2160template <
typename MF>
2166 NSolve(*ns_mlmg, *ns_sol, *ns_rhs);
2174template <
typename MF>
2182 MF
const& res_bottom = res[0].back();
2193 RT(-1.0),
RT(-1.0));
2195 linop.copyNSolveSolution(cor[0].back(), a_sol);
2198template <
typename MF>
2203 m_niters_cg.push_back(niters);
2206 const int amrlev = 0;
2207 const int mglev = linop.NMGLevels(amrlev) - 1;
2208 auto&
x = cor[amrlev][mglev];
2209 auto& b = res[amrlev][mglev];
2210 const int n = (ret==0) ? nub : nuf;
2211 linop.smooth(amrlev, mglev,
x, b,
false, n);
2214template <
typename MF>
2220 if (!linop.isBottomActive()) {
return; }
2227 const int amrlev = 0;
2228 const int mglev = linop.NMGLevels(amrlev) - 1;
2229 auto&
x = cor[amrlev][mglev];
2230 auto& b = res[amrlev][mglev];
2236 bool skip_fillboundary =
true;
2237 linop.smooth(amrlev, mglev,
x, b, skip_fillboundary, nuf);
2243 if (linop.isBottomSingular() && linop.getEnforceSingularSolvable())
2246 raii_b = linop.make(amrlev, mglev, ng,
2256#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
2257 if constexpr (std::is_same<MF,MultiFab>()) {
2258 bottomSolveWithHypre(
x, *bottom_b);
2262 amrex::Abort(
"Using Hypre as bottom solver not supported in this case");
2267#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
2268 if constexpr (std::is_same<MF,MultiFab>()) {
2269 bottomSolveWithPETSc(
x, *bottom_b);
2273 amrex::Abort(
"Using PETSc as bottom solver not supported in this case");
2278 if constexpr (std::is_same<MF,MultiFab>()) {
2281 amrex::Abort(
"MLMG: AlgMG is only supported for MultiFab");
2286 linop.customBottomSolve(
this,
x, *bottom_b, bottom_reltol, bottom_abstol,
2327 if (! timer.empty()) {
2332template <
typename MF>
2344 int ret = cg_solver.
solve(
x, b, bottom_reltol, bottom_abstol);
2345 if (ret != 0 && verbose > 1) {
2346 amrex::Print() << print_ident <<
"MLMG: Bottom solve failed.\n";
2350 if (ret != 0 && ret != 9) {
2358template <
typename MF>
2364 const int mglev = 0;
2365 for (
int alev = amrlevmax; alev >= 0; --alev) {
2366 const MF* crse_bcdata = (alev > 0) ? &(sol[alev-1]) :
nullptr;
2367 linop.solutionResidual(alev, res[alev][mglev], sol[alev], rhs[alev], crse_bcdata);
2368 if (alev < finest_amr_lev) {
2369 linop.reflux(alev, res[alev][mglev], sol[alev], rhs[alev],
2370 res[alev+1][mglev], sol[alev+1], rhs[alev+1]);
2376template <
typename MF>
2381 const MF* crse_bcdata = (alev > 0) ? &(sol[alev-1]) :
nullptr;
2382 linop.solutionResidual(alev, res[alev][0], sol[alev], rhs[alev], crse_bcdata);
2386template <
typename MF>
2390 BL_PROFILE(
"MLMG::computeResWithCrseSolFineCor()");
2394 nghost =
IntVect(std::min(linop.getNGrow(falev),linop.getNGrow(calev)));
2397 MF& crse_sol = sol[calev];
2398 const MF& crse_rhs = rhs[calev];
2399 MF& crse_res = res[calev][0];
2401 MF& fine_sol = sol[falev];
2402 const MF& fine_rhs = rhs[falev];
2403 MF& fine_cor = cor[falev][0];
2404 MF& fine_res = res[falev][0];
2405 MF& fine_rescor = rescor[falev][0];
2407 const MF* crse_bcdata = (calev > 0) ? &(sol[calev-1]) :
nullptr;
2408 linop.solutionResidual(calev, crse_res, crse_sol, crse_rhs, crse_bcdata);
2410 linop.correctionResidual(falev, 0, fine_rescor, fine_cor, fine_res, BCMode::Homogeneous);
2411 LocalCopy(fine_res, fine_rescor, 0, 0, ncomp, nghost);
2413 linop.reflux(calev, crse_res, crse_sol, crse_rhs, fine_res, fine_sol, fine_rhs);
2415 linop.avgDownResAmr(calev, crse_res, fine_res);
2419template <
typename MF>
2423 BL_PROFILE(
"MLMG::computeResWithCrseCorFineCor()");
2427 nghost =
IntVect(linop.getNGrow(falev));
2430 const MF& crse_cor = cor[falev-1][0];
2432 MF& fine_cor = cor [falev][0];
2433 MF& fine_res = res [falev][0];
2434 MF& fine_rescor = rescor[falev][0];
2437 linop.correctionResidual(falev, 0, fine_rescor, fine_cor, fine_res,
2438 BCMode::Inhomogeneous, &crse_cor);
2439 LocalCopy(fine_res, fine_rescor, 0, 0, ncomp, nghost);
2443template <
typename MF>
2451 nghost =
IntVect(linop.getNGrow(alev));
2454 MF & crse_cor = cor[alev-1][0];
2455 MF & fine_cor = cor[alev ][0];
2457 const Geometry& crse_geom = linop.Geom(alev-1,0);
2460 int ng_dst = linop.isCellCentered() ? 1 : 0;
2463 ng_src = linop.getNGrow(alev-1);
2464 ng_dst = linop.getNGrow(alev-1);
2468 amrex::Abort(
"MLMG: CFStrategy::ghostnodes not supported for non-MultiFab like types");
2472 MF cfine = linop.makeCoarseAmr(alev,
IntVect(ng_dst),
2478 linop.interpolationAmr(alev, fine_cor, cfine, nghost);
2484template <
typename MF>
2490 MF& crse_cor = cor[alev][mglev+1];
2491 MF& fine_cor = cor[alev][mglev ];
2492 linop.interpAssign(alev, mglev, fine_cor, crse_cor);
2496template <
typename MF>
2502 const MF& crse_cor = cor[alev][mglev+1];
2503 MF& fine_cor = cor[alev][mglev ];
2508 if (linop.isMFIterSafe(alev, mglev, mglev+1))
2514 cfine = linop.makeCoarseMG(alev, mglev,
IntVect(0),
2520 linop.interpolation(alev, mglev, fine_cor, *cmf);
2527template <
typename MF>
2532 MF &
x = cor[amrlev][mglev];
2533 const MF& b = res[amrlev][mglev];
2534 MF & r = rescor[amrlev][mglev];
2535 linop.correctionResidual(amrlev, mglev, r,
x, b, BCMode::Homogeneous);
2539template <
typename MF>
2544 return linop.normInf(alev, res[alev][0], local);
2548template <
typename MF>
2554 for (
int alev = 0; alev <= alevmax; ++alev)
2563template <
typename MF>
2569 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
2570 auto t = linop.normInf(alev, rhs[alev],
true);
2577template <
typename MF>
2581 auto const& offset = linop.getSolvabilityOffset(0, 0, rhs[0]);
2583 for (
int c = 0; c < ncomp; ++c) {
2584 amrex::Print() << print_ident <<
"MLMG: Subtracting " << offset[c] <<
" from rhs component "
2588 for (
int alev = 0; alev < namrlevs; ++alev) {
2589 linop.fixSolvabilityByOffset(alev, 0, rhs[alev], offset);
2593template <
typename MF>
2597 auto const& offset = linop.getSolvabilityOffset(amrlev, mglev, mf);
2599 for (
int c = 0; c < ncomp; ++c) {
2600 amrex::Print() << print_ident <<
"MLMG: Subtracting " << offset[c]
2601 <<
" from mf component c = " << c
2602 <<
" on level (" << amrlev <<
", " << mglev <<
")\n";
2605 linop.fixSolvabilityByOffset(amrlev, mglev, mf, offset);
2608template <
typename MF>
2610requires (std::same_as<TMF,MultiFab>)
2626 if (m_algmg_options) { m_algmg_options(a); }
2630template <
typename MF>
2632requires (std::same_as<TMF,MultiFab>)
2641 s.
solve(
x, b, m_algmg_reltol,
RT(0), bottom_maxiter);
2642 }
catch (std::runtime_error
const& e) {
2643 throw error(e.what());
2648template <
typename MF>
2650requires (std::same_as<TMF,MultiFab>)
2654 const int amrlev = 0;
2655 const int mglev = linop.NMGLevels(amrlev) - 1;
2659 bool const fresh = (m_algmg_bottom ==
nullptr);
2660 if (fresh) { m_algmg_bottom = linop.makeAlgMG(mglev); }
2661 configureAlgMG(*m_algmg_bottom, linop.isBottomSingular(), fresh);
2664 if (linop.isSingular(amrlev) && linop.getEnforceSingularSolvable()) {
2669template <
typename MF>
2671requires (std::same_as<TMF,MultiFab>)
2681 bool const fresh = (m_algmg_level0 ==
nullptr);
2682 if (fresh) { m_algmg_level0 = linop.makeAlgMG(0); }
2684 algmgSolve(*m_algmg_level0, cor[0][0], res[0][0]);
2688 linop.applyOverset(0, cor[0][0]);
2690 if (linop.isSingular(0) && linop.getEnforceSingularSolvable()) {
2694 if (! timer.empty()) {
2699template <
typename MF>
2702 RT best_norm, std::string& reason)
const
2704 RT const rnorm = norms.back();
2706 reason =
"non-finite residual";
2709 if (rnorm >
RT(1.e20)*max_norm ||
2710 rnorm > hybrid_divergence_factor*best_norm) {
2711 reason =
"diverging";
2714 const int w = hybrid_stall_window;
2715 if (w > 0 &&
int(norms.
size()) > w) {
2716 const RT r_old = norms[norms.
size()-1-w];
2717 if (rnorm > std::pow(hybrid_stall_rate,
RT(w)) * r_old) {
2718 reason =
"stalling";
2725#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
2726template <
typename MF>
2728requires (std::same_as<TMF,MultiFab>)
2732 const int amrlev = 0;
2733 const int mglev = linop.NMGLevels(amrlev) - 1;
2737 if (linop.isCellCentered())
2739 if (hypre_solver ==
nullptr)
2741 hypre_solver = linop.makeHypre(hypre_interface);
2743 hypre_solver->setVerbose(bottom_verbose);
2745 hypre_solver->setHypreOptionsNamespace(hypre_options_namespace);
2747 hypre_solver->setHypreOldDefault(hypre_old_default);
2748 hypre_solver->setHypreRelaxType(hypre_relax_type);
2749 hypre_solver->setHypreRelaxOrder(hypre_relax_order);
2750 hypre_solver->setHypreNumSweeps(hypre_num_sweeps);
2751 hypre_solver->setHypreStrongThreshold(hypre_strong_threshold);
2754 const BoxArray& ba = linop.m_grids[amrlev].back();
2756 const Geometry& geom = linop.m_geom[amrlev].back();
2758 hypre_bndry = std::make_unique<MLMGBndryT<MF>>(ba, dm, ncomp, geom);
2759 hypre_bndry->setHomogValues();
2760 const Real* dx = linop.m_geom[0][0].CellSize();
2761 IntVect crse_ratio = linop.m_coarse_data_crse_ratio.allGT(0) ? linop.m_coarse_data_crse_ratio :
IntVect(1);
2763 0.5*dx[1]*crse_ratio[1],
2764 0.5*dx[2]*crse_ratio[2]));
2765 hypre_bndry->setLOBndryConds(linop.m_lobc, linop.m_hibc,
IntVect(-1), bclocation,
2766 linop.m_coarse_fine_bc_type);
2772 ? bottom_abstol :
Real(-1.0);
2773 hypre_solver->setThrowException(throw_exception);
2775 hypre_solver->solve(
2776 x, b, bottom_reltol, hypre_abstol, bottom_maxiter, *hypre_bndry,
2777 linop.getMaxOrder());
2778 }
catch (std::runtime_error
const& e) {
2779 throw error(e.what());
2784 if (hypre_node_solver ==
nullptr)
2787 linop.makeHypreNodeLap(bottom_verbose, hypre_options_namespace);
2789 hypre_node_solver->setThrowException(throw_exception);
2791 hypre_node_solver->solve(
x, b, bottom_reltol, bottom_abstol, bottom_maxiter);
2792 }
catch (std::runtime_error
const& e) {
2793 throw error(e.what());
2799 if (linop.isSingular(amrlev) && linop.getEnforceSingularSolvable())
2801 makeSolvable(amrlev, mglev,
x);
2806#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
2807template <
typename MF>
2809requires (std::same_as<TMF,MultiFab>)
2815 if(petsc_solver ==
nullptr)
2817 petsc_solver = linop.makePETSc();
2818 petsc_solver->setVerbose(bottom_verbose);
2820 const BoxArray& ba = linop.m_grids[0].back();
2822 const Geometry& geom = linop.m_geom[0].back();
2824 petsc_bndry = std::make_unique<MLMGBndryT<MF>>(ba, dm, ncomp, geom);
2825 petsc_bndry->setHomogValues();
2826 const Real* dx = linop.m_geom[0][0].CellSize();
2827 auto crse_ratio = linop.m_coarse_data_crse_ratio.allGT(0) ? linop.m_coarse_data_crse_ratio :
IntVect(1);
2829 0.5*dx[1]*crse_ratio[1],
2830 0.5*dx[2]*crse_ratio[2]));
2831 petsc_bndry->setLOBndryConds(linop.m_lobc, linop.m_hibc,
IntVect(-1), bclocation,
2832 linop.m_coarse_fine_bc_type);
2834 petsc_solver->solve(
x, b, bottom_reltol,
Real(-1.), bottom_maxiter, *petsc_bndry,
2835 linop.getMaxOrder());
2839template <
typename MF>
2843 RT a_tol_rel, RT a_tol_abs,
const char* a_file_name)
const
2845 std::string file_name(a_file_name);
2850 std::string HeaderFileName(std::string(a_file_name)+
"/Header");
2851 std::ofstream HeaderFile;
2852 HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
2853 std::ofstream::trunc |
2854 std::ofstream::binary);
2855 if( ! HeaderFile.good()) {
2859 HeaderFile.precision(17);
2863 HeaderFile << linop.name() <<
"\n"
2864 <<
"a_tol_rel = " << a_tol_rel <<
"\n"
2865 <<
"a_tol_abs = " << a_tol_abs <<
"\n"
2866 <<
"verbose = " <<
verbose <<
"\n"
2867 <<
"max_iters = " << max_iters <<
"\n"
2868 <<
"nu1 = " << nu1 <<
"\n"
2869 <<
"nu2 = " << nu2 <<
"\n"
2870 <<
"nuf = " << nuf <<
"\n"
2871 <<
"nub = " << nub <<
"\n"
2872 <<
"max_fmg_iters = " << max_fmg_iters <<
"\n"
2873 <<
"bottom_solver = " <<
static_cast<int>(bottom_solver) <<
"\n"
2874 <<
"bottom_verbose = " << bottom_verbose <<
"\n"
2875 <<
"bottom_maxiter = " << bottom_maxiter <<
"\n"
2876 <<
"bottom_reltol = " << bottom_reltol <<
"\n"
2877 <<
"convergence_norm = " << norm_name <<
"\n"
2878 <<
"namrlevs = " << namrlevs <<
"\n"
2879 <<
"finest_amr_lev = " << finest_amr_lev <<
"\n"
2880 <<
"linop_prepared = " << linop_prepared <<
"\n"
2881 <<
"solve_called = " << solve_called <<
"\n";
2883 for (
int ilev = 0; ilev <= finest_amr_lev; ++ilev) {
2890 for (
int ilev = 0; ilev <= finest_amr_lev; ++ilev) {
2891 VisMF::Write(*a_sol[ilev], file_name+
"/Level_"+std::to_string(ilev)+
"/sol");
2892 VisMF::Write(*a_rhs[ilev], file_name+
"/Level_"+std::to_string(ilev)+
"/rhs");
2895 linop.checkPoint(file_name+
"/linop");
2898template <
typename MF>
2902 print_ident.resize(print_ident.size()+4,
' ');
2905template <
typename MF>
2909 if (print_ident.size() > 4) {
2910 print_ident.resize(print_ident.size()-4,
' ');
2912 print_ident.clear();
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:593
#define BL_PROFILE_VAR_STOP(vname)
Definition AMReX_BLProfiler.H:605
#define BL_PROFILE_VAR(fname, vname)
Definition AMReX_BLProfiler.H:602
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
Enum reflection utilities and the AMREX_ENUM macro.
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
Algebraic multigrid solver for SpMatrix / AlgVector systems.
Definition AMReX_AlgMG.H:264
void setSingular(bool b)
Definition AMReX_AlgMG.H:330
void setPrintIndentation(std::string s)
Prefix of the lines the solver prints, e.g. to nest them in MLMG output.
Definition AMReX_AlgMG.H:286
void setThrowException(bool b)
Definition AMReX_AlgMG.H:370
void setVerbose(int v)
Definition AMReX_AlgMG.H:284
void setKrylovSolver(KrylovSolver a)
Krylov solver with the V-cycle as preconditioner (see KrylovSolver). Default None.
Definition AMReX_AlgMG.H:347
Print on all processors of the default communicator.
Definition AMReX_Print.H:113
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
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
static bool SameRefs(const DistributionMapping &lhs, const DistributionMapping &rhs)
Return true if lhs and rhs share the same underlying Ref.
Definition AMReX_DistributionMapping.H:295
Definition AMReX_EBFabFactory.H:32
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:87
Periodicity periodicity() const noexcept
Return the Periodicity based on the length of the domain.
Definition AMReX_Geometry.H:426
Interface
HYPRE interface modes supported.
Definition AMReX_Hypre.H:70
@ ij
Definition AMReX_Hypre.H:70
__host__ static __device__ constexpr IntVectND< dim > TheDimensionVector(int d) noexcept
Definition AMReX_IntVect.H:790
Algebraic system of one MG level of AMR level 0 of an MLLinOp, solved with AlgMG.
Definition AMReX_MLAlgMG.H:25
void applyVcycle(MultiFab &soln, MultiFab const &rhs)
One AlgMG V-cycle with zero initial guess: the preconditioner form.
Definition AMReX_MLAlgMG.cpp:145
AlgMG< Real > & solver() noexcept
The solver, for settings such as verbosity and Krylov acceleration.
Definition AMReX_MLAlgMG.cpp:142
void solve(MultiFab &soln, MultiFab const &rhs, Real reltol, Real abstol, int maxiter)
Solve A x = b with zero initial guess.
Definition AMReX_MLAlgMG.cpp:155
void setSolver(Type _typ) noexcept
Switch between BiCGStab and CG after construction.
Definition AMReX_MLCGSolver.H:48
void setVerbose(int _verbose)
Control how much logging is emitted (0 = silent).
Definition AMReX_MLCGSolver.H:72
int getNumIters() const noexcept
Iteration count from the last solve* call (or -1 if unused).
Definition AMReX_MLCGSolver.H:151
void setInitSolnZeroed(bool _sol_zeroed)
Definition AMReX_MLCGSolver.H:99
int solve(MF &solnL, const MF &rhsL, RT eps_rel, RT eps_abs)
Solve Lp(solnL)=rhsL to the requested tolerance.
Definition AMReX_MLCGSolver.H:176
Type
Definition AMReX_MLCGSolver.H:27
@ BiCGStab
Definition AMReX_MLCGSolver.H:27
@ CG
Definition AMReX_MLCGSolver.H:27
void setNGhost(int _nghost)
Set the number of grow cells used when allocating temporaries.
Definition AMReX_MLCGSolver.H:108
void setMaxIter(int _maxiter)
Cap the number of Krylov iterations performed.
Definition AMReX_MLCGSolver.H:81
void setPrintIndentation(std::string s)
Prefix printed messages (e.g., to indent per level).
Definition AMReX_MLCGSolver.H:90
Definition AMReX_MLLinOp.H:142
typename FabDataType< MF >::fab_type FAB
Definition AMReX_MLLinOp.H:153
typename FabDataType< MF >::value_type RT
Definition AMReX_MLLinOp.H:154
LinOpEnumType::Location Location
Definition AMReX_MLLinOp.H:159
LinOpEnumType::BCMode BCMode
Definition AMReX_MLLinOp.H:157
Definition AMReX_MLMG.H:44
Definition AMReX_MLMG.H:39
void prepareForFluxes(Vector< MF const * > const &a_sol)
Build boundary caches needed by getFluxes()/compFluxes.
Definition AMReX_MLMG.H:1242
void setBottomVerbose(int v) noexcept
Verbosity for the bottom solver (0 silent).
Definition AMReX_MLMG.H:388
void setMaxFmgIter(int n) noexcept
Cap the number of FMG cycles executed.
Definition AMReX_MLMG.H:294
RT MLResNormInf(int alevmax, bool local=false)
Composite infinity norm of the residual up to level alevmax.
Definition AMReX_MLMG.H:2550
void postCG(int ret, int niters=-1)
Post CG smoothing.
Definition AMReX_MLMG.H:2200
RT MLRhsNormInf(bool local=false)
Composite infinity norm of the RHS.
Definition AMReX_MLMG.H:2565
void setNoGpuSync(bool do_not_sync) noexcept
Control implicit GPU synchronization inside solve().
Definition AMReX_MLMG.H:461
MLMGT(MLMGT< MF > &&)=delete
bool hybridShouldSwitch(Vector< RT > const &norms, RT max_norm, RT best_norm, std::string &reason) const
Definition AMReX_MLMG.H:2701
void actualBottomSolve()
Execute the actual bottom solve after pre-smoothing and restriction.
Definition AMReX_MLMG.H:2216
MF MFType
Definition AMReX_MLMG.H:52
void interpCorrection(int alev, int mglev)
Interpolate corrections on (alev,mglev).
Definition AMReX_MLMG.H:2486
BottomSolver getBottomSolver() const noexcept
Definition AMReX_MLMG.H:341
void setPreSmooth(int n) noexcept
Number of pre-smoothing passes per V-cycle.
Definition AMReX_MLMG.H:315
void getFluxes(const Vector< AMF * > &a_flux, Location a_loc=Location::CellCenter)
Cell-centered flux helper.
Definition AMReX_MLMG.H:1366
void setBottomToleranceAbs(RT t) noexcept
Absolute tolerance for the bottom solver (not used by AlgMG and PETSc).
Definition AMReX_MLMG.H:406
RT getFinalResidual() const noexcept
Definition AMReX_MLMG.H:724
void interpCorrection(int alev)
Interpolate corrections onto AMR level alev.
Definition AMReX_MLMG.H:2445
void getEBFluxes(const Vector< MF * > &a_eb_flux)
Flux into the EB wall using the internally stored solution.
Definition AMReX_MLMG.H:1463
void getEBFluxes(const Vector< MF * > &a_eb_flux, const Vector< MF * > &a_sol)
Flux into the EB wall using an explicit solution vector.
Definition AMReX_MLMG.H:1475
friend class GMRESMLMGT
Definition AMReX_MLMG.H:50
void getGradSolution(const Vector< Array< AMF *, 3 > > &a_grad_sol, Location a_loc=Location::FaceCenter)
Populate gradient components of the converged solution.
Definition AMReX_MLMG.H:1253
void setBottomSmooth(int n) noexcept
Additional smoothing passes executed after the bottom solver.
Definition AMReX_MLMG.H:333
void setNSolve(int flag) noexcept
Enable (flag!=0) or disable the N-solve path.
Definition AMReX_MLMG.H:438
int getBottomVerbose() const
Definition AMReX_MLMG.H:262
void computeResOfCorrection(int amrlev, int mglev)
Compute the residual of the correction equation on (amrlev,mglev).
Definition AMReX_MLMG.H:2529
void applyPrecond(const Vector< MF * > &out, const Vector< MF * > &in)
Apply the linear operator as a preconditioner (out = L(in)).
Definition AMReX_MLMG.H:1634
void setCFStrategy(CFStrategy a_cf_strategy) noexcept
Select the coarse-fine synchronization strategy.
Definition AMReX_MLMG.H:382
void computeResWithCrseCorFineCor(int falev)
Residual update using coarse correction / fine correction.
Definition AMReX_MLMG.H:2421
void NSolve(MLMGT< MF > &a_solver, MF &a_sol, MF &a_rhs)
Perform an NSolve using an MLMGT wrapper.
Definition AMReX_MLMG.H:2176
void getFluxes(const Vector< Array< AMF *, 3 > > &a_flux, const Vector< AMF * > &a_sol, Location a_loc=Location::FaceCenter)
Face-centered flux helper that accepts an explicit solution vector.
Definition AMReX_MLMG.H:1324
typename MLLinOpT< MF >::Location Location
Definition AMReX_MLMG.H:57
void apply(const Vector< MF * > &out, const Vector< MF * > &in)
out = L(in). Note that, if no actual solve is needed, one could turn off multigrid coarsening by cons...
Definition AMReX_MLMG.H:1557
void getFluxes(const Vector< Array< AMF *, 3 > > &a_flux, Location a_loc=Location::FaceCenter)
Face-centered flux helper (-b grad(phi) for alpha a - beta div(b grad)).
Definition AMReX_MLMG.H:1284
void setNSolveGridSize(int s) noexcept
Set the tile size used for N-solve builds.
Definition AMReX_MLMG.H:444
void setVerbose(int v) noexcept
Set the main solver verbosity (0 silent).
Definition AMReX_MLMG.H:282
MultigridType getMultigridType() const noexcept
Definition AMReX_MLMG.H:345
void computeMLResidual(int amrlevmax)
Compute the composite residual norm up to AMR level amrlevmax.
Definition AMReX_MLMG.H:2360
RT getInitResidual() const noexcept
Definition AMReX_MLMG.H:722
int getNumIters() const noexcept
Definition AMReX_MLMG.H:727
void setPostSmooth(int n) noexcept
Number of post-smoothing passes per V-cycle.
Definition AMReX_MLMG.H:321
void mgVcycle(int amrlev, int mglev)
Run a multigrid V-cycle on (amrlev,mglev).
Definition AMReX_MLMG.H:2004
void prepareForNSolve()
Prepare the NSolve path.
Definition AMReX_MLMG.H:1883
RT precond(Vector< MF * > const &a_sol, Vector< MF const * > const &a_rhs, RT a_tol_rel, RT a_tol_abs)
Apply MLMG as a right-preconditioner with relaxed tolerances.
Definition AMReX_MLMG.H:1224
void makeSolvable(int amrlev, int mglev, MF &mf)
Adjust a field on (amrlev,mglev) to satisfy null-space constraints.
Definition AMReX_MLMG.H:2595
void getFluxes(std::initializer_list< Array< AMF *, 3 > > a_flux, std::initializer_list< AMF * > a_sol, Location a_loc=Location::FaceCenter)
Initializer-list convenience overload for the face-centered flux helper above.
Definition AMReX_MLMG.H:1356
void setHybridStallCriterion(int window, RT rate) noexcept
Hybrid mode: switch to AlgMG when the residual has not dropped by rate per iteration on average over ...
Definition AMReX_MLMG.H:371
void makeSolvable()
Adjust RHS/solution to satisfy null-space constraints.
Definition AMReX_MLMG.H:2579
void setBottomSolver(BottomSolver s) noexcept
Select the bottom solver type (e.g., CG, BiCGStab, Hypre, PETSc).
Definition AMReX_MLMG.H:340
void preparePrecond()
Prepare preconditioner-specific caches (e.g., boundary data).
Definition AMReX_MLMG.H:1875
friend class MLCGSolverT
Definition AMReX_MLMG.H:49
void incPrintIdentation()
Increase the indentation used when printing solver logs.
Definition AMReX_MLMG.H:2900
typename MLLinOpT< MF >::RT RT
Definition AMReX_MLMG.H:54
void setThrowException(bool t) noexcept
Control behavior when the solve fails to converge or blows up.
Definition AMReX_MLMG.H:276
void decPrintIdentation()
Decrease the indentation used when printing solver logs.
Definition AMReX_MLMG.H:2907
void setFixedIter(int nit) noexcept
Set the number of fixed MLMG iterations (convergence may still exit early if the residual is already ...
Definition AMReX_MLMG.H:301
void setMultigridType(MultigridType t) noexcept
Select how AMR level 0 is solved. See MultigridType.
Definition AMReX_MLMG.H:344
Vector< RT > const & getResidualHistory() const noexcept
Definition AMReX_MLMG.H:726
void prepareLinOp()
Finalize operator-dependent metadata before iterating.
Definition AMReX_MLMG.H:1847
void setPrecondIter(int nit) noexcept
Set how many MLMG iterations the preconditioner executes per Krylov call (still subject to early-conv...
Definition AMReX_MLMG.H:308
CFStrategy
Definition AMReX_MLMG.H:61
@ none
Definition AMReX_MLMG.H:61
@ ghostnodes
Definition AMReX_MLMG.H:61
amrex::BottomSolver BottomSolver
Definition AMReX_MLMG.H:59
void prepareForSolve(Vector< AMF * > const &a_sol, Vector< AMF const * > const &a_rhs)
Prepare linear operators, coefficients, and RHS data prior to solving.
Definition AMReX_MLMG.H:1646
int bottomSolveWithCG(MF &x, const MF &b, typename MLCGSolverT< MF >::Type type)
Bottom solve using CG/BiCGStab implemented in MLCGSolverT.
Definition AMReX_MLMG.H:2334
void getGradSolution(std::initializer_list< Array< AMF *, 3 > > a_grad_sol, Location a_loc=Location::FaceCenter)
Initializer-list convenience overload for getGradSolution.
Definition AMReX_MLMG.H:1276
void setAlwaysUseBNorm(int flag) noexcept
Deprecated flag for forcing B-norm convergence checks.
Definition AMReX_MLMG.H:868
bool usedAlgMG() const noexcept
Definition AMReX_MLMG.H:348
void compResidual(const Vector< MF * > &a_res, const Vector< MF * > &a_sol, const Vector< MF const * > &a_rhs)
Compute multilevel residuals a_rhs - L(a_sol) on each AMR level.
Definition AMReX_MLMG.H:1489
void miniCycle(int amrlev)
Execute a per-level mini cycle.
Definition AMReX_MLMG.H:1993
RT solve(std::initializer_list< AMF * > a_sol, std::initializer_list< AMF const * > a_rhs, RT a_tol_rel, RT a_tol_abs, const char *checkpoint_file=nullptr)
Convenience initializer-list overload that forwards to the Vector-based solve.
void getFluxes(const Vector< AMF * > &a_flux, const Vector< AMF * > &a_sol, Location a_loc=Location::CellCenter)
Cell-centered flux helper that accepts an explicit solution vector.
Definition AMReX_MLMG.H:1395
void setFinalFillBC(int flag) noexcept
Force a FillBoundary at the end of the solve (nonzero enables).
Definition AMReX_MLMG.H:429
typename MLLinOpT< MF >::BCMode BCMode
Definition AMReX_MLMG.H:56
void setConvergenceNormType(MLMGNormType norm) noexcept
Choose the norm used for convergence tests.
Definition AMReX_MLMG.H:422
void setHybridDivergenceFactor(RT f) noexcept
Definition AMReX_MLMG.H:376
void computeResWithCrseSolFineCor(int calev, int falev)
Residual update using coarse solution / fine correction.
Definition AMReX_MLMG.H:2388
MLMGT< MF > & operator=(MLMGT< MF > const &)=delete
MLMGT(MLLinOpT< MF > &a_lp)
Definition AMReX_MLMG.H:859
void computeResidual(int alev)
Compute the residual on AMR level alev.
Definition AMReX_MLMG.H:2378
MLLinOpT< MF > & getLinOp()
Definition AMReX_MLMG.H:730
void getFluxes(std::initializer_list< AMF * > a_flux, Location a_loc=Location::CellCenter)
Initializer-list convenience overload for cell-centered fluxes.
Definition AMReX_MLMG.H:1387
typename MLLinOpT< MF >::FAB FAB
Definition AMReX_MLMG.H:53
RT getBottomToleranceAbs() const noexcept
Definition AMReX_MLMG.H:407
int numAMRLevels() const noexcept
Definition AMReX_MLMG.H:431
MLMGT(MLMGT< MF > const &)=delete
void getFluxes(std::initializer_list< Array< AMF *, 3 > > a_flux, Location a_loc=Location::FaceCenter)
Initializer-list convenience overload for getFluxes (face-centered).
Definition AMReX_MLMG.H:1315
void mgFcycle()
Run an FMG cycle starting from the coarsest grid.
Definition AMReX_MLMG.H:2110
RT getInitRHS() const noexcept
Definition AMReX_MLMG.H:720
void algmgSolve(MLAlgMG &s, MultiFab &x, MultiFab const &b)
RT ResNormInf(int alev, bool local=false)
Infinity norm of the residual on level alev.
Definition AMReX_MLMG.H:2541
Vector< int > const & getNumCGIters() const noexcept
Definition AMReX_MLMG.H:728
amrex::MultigridType MultigridType
Definition AMReX_MLMG.H:60
void bottomSolveWithAlgMG(MultiFab &x, const MultiFab &b)
void bottomSolve()
Execute the configured bottom solver (Hypre, PETSc, CG, etc.).
Definition AMReX_MLMG.H:2162
void setAlgMGOptions(std::function< void(AlgMG< RT > &)> f)
Adjust the AlgMG solvers MLMG builds (level 0 and bottom).
Definition AMReX_MLMG.H:360
void setBottomTolerance(RT t) noexcept
Relative tolerance for the bottom solver.
Definition AMReX_MLMG.H:400
void setFinalSmooth(int n) noexcept
Number of smoothing passes when MLMG is used standalone (final smooth).
Definition AMReX_MLMG.H:327
void addInterpCorrection(int alev, int mglev)
Add interpolated corrections to (alev,mglev) data.
Definition AMReX_MLMG.H:2498
int getVerbose() const
Definition AMReX_MLMG.H:261
RT solve(const Vector< AMF * > &a_sol, const Vector< AMF const * > &a_rhs, RT a_tol_rel, RT a_tol_abs, const char *checkpoint_file=nullptr)
Solve the multilevel system; optional checkpoint_file is for debugging only.
void getFluxes(std::initializer_list< AMF * > a_flux, std::initializer_list< AMF * > a_sol, Location a_loc=Location::CellCenter)
Initializer-list convenience overload for the cell-centered flux helper above.
Definition AMReX_MLMG.H:1453
void setBottomMaxIter(int n) noexcept
Cap the number of iterations inside the bottom solver.
Definition AMReX_MLMG.H:394
void configureAlgMG(MLAlgMG &s, bool singular, bool with_options)
void oneIter(int iter)
Execute a single multigrid iteration (FMG or V-cycle).
Definition AMReX_MLMG.H:1916
void setMaxIter(int n) noexcept
Cap the number of MLMG iterations executed.
Definition AMReX_MLMG.H:288
This class provides the user with a few print options.
Definition AMReX_Print.H:35
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
static Long Write(const FabArray< FArrayBox > &mf, const std::string &name, VisMF::How how=NFiles, bool set_ghost=false)
Write a FabArray<FArrayBox> to disk in a "smart" way. Returns the total number of bytes written on th...
Definition AMReX_VisMF.cpp:998
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:80
amrex_long Long
Definition AMReX_INT.H:30
__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
std::array< T, N > Array
Definition AMReX_Array.H:31
Arena * The_Async_Arena()
Definition AMReX_Arena.cpp:849
void Max(KeyValuePair< K, V > &vi, int root, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:254
void Max(KeyValuePair< K, V > &vi, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:133
MLMGT< MultiFab > MLMG
Definition AMReX_MLMG.H:2919
#define AMREX_ENUM(CLASS,...)
Declare a scoped enum with reflection support.
Definition AMReX_Enum.H:270
std::string getEnumNameString(T const &v)
Get the name string of an enum value.
Definition AMReX_Enum.H:190
constexpr int relax_order
Definition AMReX_Hypre.H:45
constexpr int relax_type
Definition AMReX_Hypre.H:44
constexpr bool old_default
Falgout coarsening with modified classical interpolation.
Definition AMReX_Hypre.H:39
void push(MPI_Comm c)
Definition AMReX_ParallelContext.H:105
void BarrierSub() noexcept
Definition AMReX_ParallelContext.H:88
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int MyProcSub() noexcept
my sub-rank in current frame
Definition AMReX_ParallelContext.H:76
void pop()
Note that it's the user's responsibility to free the MPI_Comm.
Definition AMReX_ParallelContext.H:111
bool IOProcessorSub() noexcept
Am IO processor for current frame?
Definition AMReX_ParallelContext.H:80
int verbose
Definition AMReX.cpp:113
Definition AMReX_Amr.cpp:50
MultigridType
How MLMG solves the coarsest AMR level.
Definition AMReX_MLMG.H:34
@ geometric
Definition AMReX_MLMG.H:34
@ algebraic
Definition AMReX_MLMG.H:34
@ hybrid
Definition AMReX_MLMG.H:34
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:273
void FileOpenFailed(const std::string &file)
Output a message and abort when couldn't open the file.
Definition AMReX_Utility.cpp:116
std::array< T const *, 3 > GetArrOfConstPtrs(const std::array< T, 3 > &a) noexcept
Create an array of const-qualified pointers from an array of objects.
Definition AMReX_Array.H:1079
void EB_average_face_to_cellcenter(MultiFab &ccmf, int dcomp, const Array< MultiFab const *, 3 > &fmf)
Average face-centered values to cell centers.
Definition AMReX_EBMultiFabUtil.cpp:809
__host__ __device__ T norm(const GpuComplex< T > &a_z) noexcept
Return the norm (magnitude squared) of a complex number.
Definition AMReX_GpuComplex.H:349
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
void Scale(MF &dst, typename MF::value_type val, int scomp, int ncomp, int nghost)
dst *= val
Definition AMReX_FabArrayUtility.H:2180
BoxArray const & boxArray(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.boxArray().
Definition AMReX_FabArrayBase.cpp:2990
DistributionMapping const & DistributionMap(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.DistributionMap().
Definition AMReX_FabArrayBase.cpp:2995
void average_face_to_cellcenter(MultiFab &cc, int dcomp, const Vector< const MultiFab * > &fc, IntVect const &ng_vect)
Definition AMReX_MultiFabUtil.cpp:157
constexpr bool IsFabArray_v
Definition AMReX_TypeTraits.H:34
void EB_set_covered(MultiFab &mf, Real val)
Fill all covered cells with a single value val.
Definition AMReX_EBMultiFabUtil.cpp:21
constexpr bool IsMultiFabLike_v
Definition AMReX_TypeTraits.H:44
double second() noexcept
Definition AMReX_Utility.cpp:919
std::array< T *, 3 > GetArrOfPtrs(std::array< T, 3 > &a) noexcept
Create an array of pointers from an array of objects.
Definition AMReX_Array.H:1033
int nComp(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.nComp().
Definition AMReX_FabArrayBase.cpp:2980
void ParallelCopy(MF &dst, MF const &src, int scomp, int dcomp, int ncomp, IntVect const &ng_src=IntVect(0), IntVect const &ng_dst=IntVect(0), Periodicity const &period=Periodicity::NonPeriodic())
dst = src w/ MPI communication
Definition AMReX_FabArrayUtility.H:2256
void UtilCreateCleanDirectory(const std::string &path, bool callbarrier=true)
Create a new directory, renaming the old one if it exists.
Definition AMReX_Utility.cpp:146
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
void computeResidual(AlgVector< T, AllocV > &res, SpMatrix< T, AllocM > const &A, AlgVector< T, AllocV > const &x, AlgVector< T, AllocV > const &b)
Compute the residual res = b - A * x.
Definition AMReX_SpMV.H:345
@ 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
Vector< T * > GetVecOfPtrs(Vector< T > &a)
Definition AMReX_Vector.H:65
IntVect nGrowVect(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.nGrowVect().
Definition AMReX_FabArrayBase.cpp:2985
void LocalCopy(DMF &dst, SMF const &src, int scomp, int dcomp, int ncomp, IntVect const &nghost)
dst = src
Definition AMReX_FabArrayUtility.H:2187
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
void setBndry(MF &dst, typename MF::value_type val, int scomp, int ncomp)
dst = val in ghost cells.
Definition AMReX_FabArrayUtility.H:2173
MF::value_type norminf(MF const &mf, int scomp, int ncomp, IntVect const &nghost, bool local=false)
Return the infinity norm, with an MPI maximum unless local is true.
Definition AMReX_FabArrayUtility.H:2267
Vector< std::array< T *, 3 > > GetVecOfArrOfPtrs(const Vector< std::array< std::unique_ptr< T >, 3 > > &a)
Definition AMReX_Vector.H:142
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:244
MLMGNormType
Definition AMReX_MLMG.H:23
@ resnorm
Definition AMReX_MLMG.H:23
@ bnorm
Definition AMReX_MLMG.H:23
@ greater
Definition AMReX_MLMG.H:23
RealVectND< 3 > RealVect
Definition AMReX_ParmParse.H:39
__host__ __device__ bool isfinite(T x) noexcept
Return true if x is neither NaN nor infinity. Works under fast math.
Definition AMReX_Math.H:155
void LocalAdd(MF &dst, MF const &src, int scomp, int dcomp, int ncomp, IntVect const &nghost)
dst += src
Definition AMReX_FabArrayUtility.H:2195
void setVal(MF &dst, typename MF::value_type val)
dst = val
Definition AMReX_FabArrayUtility.H:2166
FabArray memory allocation information.
Definition AMReX_FabArray.H:73