3#include <AMReX_Config.H>
21 :
public std::runtime_error
24 using std::runtime_error::runtime_error;
49 template <
typename AMF>
51 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file =
nullptr);
53 template <
typename AMF>
54 RT solve (std::initializer_list<AMF*> a_sol,
55 std::initializer_list<AMF const*> a_rhs,
56 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file =
nullptr);
59 RT a_tol_rel,
RT a_tol_abs);
61 template <
typename AMF>
63 Location a_loc = Location::FaceCenter);
65 template <
typename AMF>
67 Location a_loc = Location::FaceCenter);
72 template <
typename AMF>
74 Location a_loc = Location::FaceCenter);
76 template <
typename AMF>
78 Location a_loc = Location::FaceCenter);
80 template <
typename AMF>
83 Location a_loc = Location::FaceCenter);
85 template <
typename AMF>
87 std::initializer_list<AMF*> a_sol,
88 Location a_loc = Location::FaceCenter);
90 template <
typename AMF>
92 Location a_loc = Location::CellCenter);
94 template <
typename AMF>
95 void getFluxes (std::initializer_list<AMF*> a_flux,
96 Location a_loc = Location::CellCenter);
98 template <
typename AMF>
101 Location a_loc = Location::CellCenter);
103 template <
typename AMF>
104 void getFluxes (std::initializer_list<AMF*> a_flux,
105 std::initializer_list<AMF*> a_sol,
106 Location a_loc = Location::CellCenter);
137 void setFixedIter (
int nit)
noexcept { do_fixed_number_of_iters = nit; }
154 [[deprecated(
"Use MLMG::setConvergenceNormType() instead.")]]
163 void setNSolve (
int flag)
noexcept { do_nsolve = flag; }
166 void setNoGpuSync (
bool do_not_sync)
noexcept { do_no_sync_gpu = do_not_sync; }
168#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
179 void setHypreOptionsNamespace(
const std::string& prefix)
noexcept
181 hypre_options_namespace = prefix;
184 void setHypreOldDefault (
bool l)
noexcept {hypre_old_default = l;}
185 void setHypreRelaxType (
int n)
noexcept {hypre_relax_type = n;}
186 void setHypreRelaxOrder (
int n)
noexcept {hypre_relax_order = n;}
187 void setHypreNumSweeps (
int n)
noexcept {hypre_num_sweeps = n;}
188 void setHypreStrongThreshold (
Real t)
noexcept {hypre_strong_threshold = t;}
193 template <
typename AMF>
194 void prepareForSolve (Vector<AMF*>
const& a_sol, Vector<AMF const*>
const& a_rhs);
206 void mgVcycle (
int amrlev,
int mglev);
210 void NSolve (MLMGT<MF>& a_solver, MF& a_sol, MF& a_rhs);
230#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
231 template <
class TMF=MF,std::enable_if_t<std::is_same_v<TMF,MultiFab>,
int> = 0>
232 void bottomSolveWithHypre (MF&
x,
const MF& b);
235#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
236 template <
class TMF=MF,std::enable_if_t<std::is_same_v<TMF,MultiFab>,
int> = 0>
237 void bottomSolveWithPETSc (MF&
x,
const MF& b);
249 [[nodiscard]]
int getNumIters () const noexcept {
return m_iter_fine_resnorm0.
size(); }
256 bool precond_mode =
false;
257 bool throw_exception =
false;
261 int do_fixed_number_of_iters = 0;
262 int max_precond_iters = 1;
269 int max_fmg_iters = 0;
273 int bottom_verbose = 0;
274 int bottom_maxiter = 200;
275 RT bottom_reltol = std::is_same<RT,double>() ?
RT(1.e-4) :
RT(1.e-3);
276 RT bottom_abstol =
RT(-1.0);
280 int final_fill_bc = 0;
287 bool linop_prepared =
false;
288 Long solve_called = 0;
291 int do_nsolve =
false;
292 int nsolve_grid_size = 16;
293 std::unique_ptr<MLLinOpT<MF>> ns_linop;
294 std::unique_ptr<MLMGT<MF>> ns_mlmg;
295 std::unique_ptr<MF> ns_sol;
296 std::unique_ptr<MF> ns_rhs;
298 std::string print_ident;
300 bool do_no_sync_gpu =
false;
303#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
308 std::unique_ptr<Hypre> hypre_solver;
309 std::unique_ptr<MLMGBndryT<MF>> hypre_bndry;
310 std::unique_ptr<HypreNodeLap> hypre_node_solver;
312 std::string hypre_options_namespace =
"hypre";
313 bool hypre_old_default =
true;
314 int hypre_relax_type = 6;
315 int hypre_relax_order = 1;
316 int hypre_num_sweeps = 2;
317 Real hypre_strong_threshold = 0.25;
321#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
322 std::unique_ptr<PETScABecLap> petsc_solver;
323 std::unique_ptr<MLMGBndryT<MF>> petsc_bndry;
346 enum timer_types { solve_time=0, iter_time, bottom_time, ntimers };
347 Vector<double> timer;
349 RT m_rhsnorm0 =
RT(-1.0);
350 RT m_init_resnorm0 =
RT(-1.0);
351 RT m_final_resnorm0 =
RT(-1.0);
352 Vector<int> m_niters_cg;
353 Vector<RT> m_iter_fine_resnorm0;
355 void checkPoint (
const Vector<MultiFab*>& a_sol,
356 const Vector<MultiFab const*>& a_rhs,
357 RT a_tol_rel,
RT a_tol_abs,
const char* a_file_name)
const;
361template <
typename MF>
363 : linop(a_lp), ncomp(a_lp.getNComp()), namrlevs(a_lp.NAMRLevels()),
364 finest_amr_lev(a_lp.NAMRLevels()-1)
369template <
typename MF>
380template <
typename MF>
381template <
typename AMF>
384 std::initializer_list<AMF const*> a_rhs,
385 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file) ->
RT
389 a_tol_rel, a_tol_abs, checkpoint_file);
392template <
typename MF>
393template <
typename AMF>
396 RT a_tol_rel,
RT a_tol_abs,
const char* checkpoint_file) ->
RT
400 bool prev_in_single_stream_region =
false;
401 bool prev_in_nosync_region =
false;
403 if (do_no_sync_gpu) {
408 if constexpr (std::is_same<AMF,MultiFab>()) {
409 if (checkpoint_file !=
nullptr) {
410 checkPoint(a_sol, a_rhs, a_tol_rel, a_tol_abs, checkpoint_file);
415 bottom_solver = linop.getDefaultBottomSolver();
418#if (defined(AMREX_USE_HYPRE) || defined(AMREX_USE_PETSC)) && (AMREX_SPACEDIM > 1)
419 if constexpr (IsFabArray_v<AMF>) {
421 int mo = linop.getMaxOrder();
422 if (a_sol[0]->hasEBFabFactory()) {
423 linop.setMaxOrder(2);
425 linop.setMaxOrder(std::min(3,mo));
431 bool is_nsolve = linop.m_parent;
435 RT& composite_norminf = m_final_resnorm0;
438 m_iter_fine_resnorm0.clear();
440 prepareForSolve(a_sol, a_rhs);
442 computeMLResidual(finest_amr_lev);
445 RT resnorm0 = MLResNormInf(finest_amr_lev, local);
446 RT rhsnorm0 = MLRhsNormInf(local);
452 amrex::Print() << print_ident <<
"MLMG: Initial rhs = " << rhsnorm0 <<
"\n"
453 << print_ident <<
"MLMG: Initial residual (resid0) = " << resnorm0 <<
"\n";
457 m_init_resnorm0 = resnorm0;
458 m_rhsnorm0 = rhsnorm0;
460 RT max_norm = resnorm0;
461 std::string norm_name =
"resid0";
464 if (rhsnorm0 >= resnorm0) {
468 norm_name =
"resid0";
477 norm_name =
"resid0";
482 const RT res_target = std::max(a_tol_abs, std::max(a_tol_rel,
RT(1.e-16))*max_norm);
484 if (!is_nsolve && resnorm0 <= res_target) {
485 composite_norminf = resnorm0;
487 amrex::Print() << print_ident <<
"MLMG: No iterations needed\n";
491 bool converged =
false;
493 const int niters = do_fixed_number_of_iters ? do_fixed_number_of_iters : max_iters;
494 for (
int iter = 0; iter < niters; ++iter)
503 if (is_nsolve) {
continue; }
505 RT fine_norminf = ResNormInf(finest_amr_lev);
506 m_iter_fine_resnorm0.push_back(fine_norminf);
507 composite_norminf = fine_norminf;
509 amrex::Print() << print_ident <<
"MLMG: Iteration " << std::setw(3) << iter+1 <<
" Fine resid/"
510 << norm_name <<
" = " << fine_norminf/max_norm <<
"\n";
512 bool fine_converged = (fine_norminf <= res_target);
514 if (namrlevs == 1 && fine_converged) {
516 }
else if (fine_converged) {
518 computeMLResidual(finest_amr_lev-1);
519 RT crse_norminf = MLResNormInf(finest_amr_lev-1);
521 amrex::Print() << print_ident <<
"MLMG: Iteration " << std::setw(3) << iter+1
522 <<
" Crse resid/" << norm_name <<
" = "
523 << crse_norminf/max_norm <<
"\n";
525 converged = (crse_norminf <= res_target);
526 composite_norminf = std::max(fine_norminf, crse_norminf);
533 amrex::Print() << print_ident <<
"MLMG: Final Iter. " << iter+1
534 <<
" resid, resid/" << norm_name <<
" = "
535 << composite_norminf <<
", "
536 << composite_norminf/max_norm <<
"\n";
540 if (composite_norminf >
RT(1.e20)*max_norm)
543 amrex::Print() << print_ident <<
"MLMG: Failing to converge after " << iter+1 <<
" iterations."
544 <<
" resid, resid/" << norm_name <<
" = "
545 << composite_norminf <<
", "
546 << composite_norminf/max_norm <<
"\n";
549 if ( throw_exception ) {
550 throw error(
"MLMG blew up.");
558 if (!converged && do_fixed_number_of_iters == 0) {
560 amrex::Print() << print_ident <<
"MLMG: Failed to converge after " << max_iters <<
" iterations."
561 <<
" resid, resid/" << norm_name <<
" = "
562 << composite_norminf <<
", "
563 << composite_norminf/max_norm <<
"\n";
566 if ( throw_exception ) {
567 throw error(
"MLMG failed to converge.");
578 if (linop.hasHiddenDimension()) {
579 ng_back[linop.hiddenDirection()] = 0;
581 for (
int alev = 0; alev < namrlevs; ++alev)
583 if (!sol_is_alias[alev]) {
584 LocalCopy(*a_sol[alev], sol[alev], 0, 0, ncomp, ng_back);
590 ParallelReduce::Max<double>(timer.data(), timer.size(), 0,
594 amrex::AllPrint() << print_ident <<
"MLMG: Timers: Solve = " << timer[solve_time]
595 <<
" Iter = " << timer[iter_time]
596 <<
" Bottom = " << timer[bottom_time] <<
"\n";
602 if (do_no_sync_gpu) {
607 return composite_norminf;
610template <
typename MF>
613 RT a_tol_rel,
RT a_tol_abs) ->
RT
616 std::swap(max_precond_iters, do_fixed_number_of_iters);
617 linop.beginPrecondBC();
619 auto r = solve(a_sol, a_rhs, a_tol_rel, a_tol_abs);
621 linop.endPrecondBC();
622 std::swap(max_precond_iters, do_fixed_number_of_iters);
623 precond_mode =
false;
628template <
typename MF>
632 for (
int alev = finest_amr_lev; alev >= 0; --alev) {
633 const MF* crse_bcdata = (alev > 0) ? a_sol[alev-1] :
nullptr;
634 linop.prepareForFluxes(alev, crse_bcdata);
638template <
typename MF>
639template <
typename AMF>
644 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
645 if constexpr (std::is_same<AMF,MF>()) {
646 linop.compGrad(alev, a_grad_sol[alev], sol[alev], a_loc);
649 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
650 auto const& amf = *(a_grad_sol[alev][idim]);
653 linop.compGrad(alev,
GetArrOfPtrs(grad_sol), sol[alev], a_loc);
654 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
655 LocalCopy(*a_grad_sol[alev][idim], grad_sol[idim], 0, 0, ncomp,
IntVect(0));
661template <
typename MF>
662template <
typename AMF>
669template <
typename MF>
670template <
typename AMF>
675 if (!linop.isCellCentered()) {
676 amrex::Abort(
"Calling wrong getFluxes for nodal solver");
681 if constexpr (std::is_same<AMF,MF>()) {
685 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
686 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
687 auto const& amf = *(a_flux[ilev][idim]);
692 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
693 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
694 LocalCopy(*a_flux[ilev][idim], fluxes[ilev][idim], 0, 0, ncomp,
IntVect(0));
700template <
typename MF>
701template <
typename AMF>
709template <
typename MF>
710template <
typename AMF>
717 if (!linop.isCellCentered()) {
718 amrex::Abort(
"Calling wrong getFluxes for nodal solver");
721 if constexpr (std::is_same<AMF,MF>()) {
722 linop.getFluxes(a_flux, a_sol, a_loc);
725 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
726 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
727 auto const& amf = *(a_flux[ilev][idim]);
733 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
734 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
735 LocalCopy(*a_flux[ilev][idim], fluxes[ilev][idim], 0, 0, ncomp,
IntVect(0));
741template <
typename MF>
742template <
typename AMF>
745 std::initializer_list<AMF*> a_sol,
Location a_loc)
751template <
typename MF>
752template <
typename AMF>
757 if constexpr (std::is_same<AMF,MF>()) {
761 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
762 auto const& amf = *a_flux[ilev];
766 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
772template <
typename MF>
773template <
typename AMF>
780template <
typename MF>
781template <
typename AMF>
788 if constexpr (! std::is_same<AMF,MF>()) {
789 for (
int alev = 0; alev < namrlevs; ++alev) {
794 if (linop.isCellCentered())
797 for (
int alev = 0; alev < namrlevs; ++alev) {
798 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
801 if (cf_strategy == CFStrategy::ghostnodes) { nghost = linop.getNGrow(alev); }
802 ffluxes[alev][idim].define(
amrex::convert(linop.m_grids[alev][mglev],
804 linop.m_dmap[alev][mglev], ncomp, nghost,
MFInfo(),
805 *linop.m_factory[alev][mglev]);
808 if constexpr (std::is_same<AMF,MF>()) {
813 for (
int alev = 0; alev < namrlevs; ++alev) {
822 if constexpr (std::is_same<AMF,MF>()) {
823 linop.getFluxes(a_flux, a_sol);
826 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
827 auto const& amf = *a_flux[ilev];
831 for (
int ilev = 0; ilev < namrlevs; ++ilev) {
838template <
typename MF>
839template <
typename AMF>
842 std::initializer_list<AMF*> a_sol,
Location a_loc)
849template <
typename MF>
853 if (!linop.isCellCentered()) {
861template <
typename MF>
867 if (!linop.isCellCentered()) {
871 linop.getEBFluxes(a_eb_flux, a_sol);
875template <
typename MF>
883 if (linop.hasHiddenDimension()) { ng_sol[linop.hiddenDirection()] = 0; }
886 sol_is_alias.resize(namrlevs,
true);
887 for (
int alev = 0; alev < namrlevs; ++alev)
889 if (cf_strategy == CFStrategy::ghostnodes ||
nGrowVect(*a_sol[alev]) == ng_sol)
891 sol[alev] = linop.makeAlias(*a_sol[alev]);
892 sol_is_alias[alev] =
true;
896 if (sol_is_alias[alev])
898 sol[alev] = linop.make(alev, 0, ng_sol);
906 const auto& amrrr = linop.AMRRefRatio();
908 for (
int alev = finest_amr_lev; alev >= 0; --alev) {
909 const MF* crse_bcdata = (alev > 0) ? &(sol[alev-1]) :
nullptr;
910 const MF* prhs = a_rhs[alev];
911#if (AMREX_SPACEDIM != 3)
912 int nghost = (cf_strategy == CFStrategy::ghostnodes) ? linop.getNGrow(alev) : 0;
914 MFInfo(), *linop.Factory(alev));
916 linop.applyMetricTerm(alev, 0, rhstmp);
917 linop.unimposeNeumannBC(alev, rhstmp);
918 linop.applyInhomogNeumannTerm(alev, rhstmp);
921 linop.solutionResidual(alev, *a_res[alev], sol[alev], *prhs, crse_bcdata);
922 if (alev < finest_amr_lev) {
923 linop.reflux(alev, *a_res[alev], sol[alev], *prhs,
924 *a_res[alev+1], sol[alev+1], *a_rhs[alev+1]);
925 if (linop.isCellCentered()) {
929 average_down(*a_res[alev+1], *a_res[alev], 0, ncomp, amrrr[alev]);
936#if (AMREX_SPACEDIM != 3)
937 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
938 linop.unapplyMetricTerm(alev, 0, *a_res[alev]);
943template <
typename MF>
954 if (linop.hasHiddenDimension()) { ng_sol[linop.hiddenDirection()] = 0; }
956 for (
int alev = 0; alev < namrlevs; ++alev)
958 if (cf_strategy == CFStrategy::ghostnodes)
960 nghost = linop.getNGrow(alev);
961 in[alev] = a_in[alev];
963 else if (
nGrowVect(*a_in[alev]) == ng_sol)
965 in[alev] = a_in[alev];
970 if (cf_strategy == CFStrategy::ghostnodes) { ng =
IntVect(nghost); }
971 in_raii[alev] = linop.make(alev, 0, ng);
973 in[alev] = &(in_raii[alev]);
975 rh[alev] = linop.make(alev, 0,
IntVect(nghost));
981 for (
int alev = 0; alev < namrlevs; ++alev) {
982 linop.applyInhomogNeumannTerm(alev, rh[alev]);
985 const auto& amrrr = linop.AMRRefRatio();
987 for (
int alev = finest_amr_lev; alev >= 0; --alev) {
988 const MF* crse_bcdata = (alev > 0) ? in[alev-1] :
nullptr;
989 linop.solutionResidual(alev, *out[alev], *in[alev], rh[alev], crse_bcdata);
990 if (alev < finest_amr_lev) {
991 linop.reflux(alev, *out[alev], *in[alev], rh[alev],
992 *out[alev+1], *in[alev+1], rh[alev+1]);
993 if (linop.isCellCentered()) {
994 if constexpr (IsMultiFabLike_v<MF>) {
1001 amrex::Abort(
"MLMG: TODO average_down for non-MultiFab");
1007#if (AMREX_SPACEDIM != 3)
1008 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
1009 linop.unapplyMetricTerm(alev, 0, *out[alev]);
1013 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
1014 if (cf_strategy == CFStrategy::ghostnodes) { nghost = linop.getNGrow(alev); }
1015 Scale(*out[alev],
RT(-1), 0,
nComp(*out[alev]), nghost);
1019template <
typename MF>
1023 precond_mode =
true;
1024 linop.beginPrecondBC();
1026 linop.endPrecondBC();
1027 precond_mode =
false;
1030template <
typename MF>
1031template <
typename AMF>
1040 timer.assign(ntimers, 0.0);
1044 if (linop.hasHiddenDimension()) { ng_sol[linop.hiddenDirection()] = 0; }
1046 if (!linop_prepared) {
1047 linop.prepareForSolve();
1048 linop_prepared =
true;
1049 }
else if (linop.needsUpdate()) {
1052#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
1053 hypre_solver.reset();
1054 hypre_bndry.reset();
1055 hypre_node_solver.reset();
1058#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
1059 petsc_solver.reset();
1060 petsc_bndry.reset();
1065 sol_is_alias.resize(namrlevs,
false);
1066 for (
int alev = 0; alev < namrlevs; ++alev)
1068 if (cf_strategy == CFStrategy::ghostnodes)
1070 if constexpr (std::is_same<AMF,MF>()) {
1071 sol[alev] = linop.makeAlias(*a_sol[alev]);
1072 sol_is_alias[alev] =
true;
1074 amrex::Abort(
"Type conversion not supported for CFStrategy::ghostnodes");
1079 if (
nGrowVect(*a_sol[alev]) == ng_sol) {
1080 if constexpr (std::is_same<AMF,MF>()) {
1081 sol[alev] = linop.makeAlias(*a_sol[alev]);
1082 sol_is_alias[alev] =
true;
1085 if (!sol_is_alias[alev]) {
1086 if (!solve_called) {
1087 sol[alev] = linop.make(alev, 0, ng_sol);
1095 rhs.resize(namrlevs);
1096 for (
int alev = 0; alev < namrlevs; ++alev)
1098 if (cf_strategy == CFStrategy::ghostnodes) { ng_rhs =
IntVect(linop.getNGrow(alev)); }
1099 if (!solve_called) {
1100 rhs[alev] = linop.make(alev, 0, ng_rhs);
1102 LocalCopy(rhs[alev], *a_rhs[alev], 0, 0, ncomp, ng_rhs);
1103 linop.applyMetricTerm(alev, 0, rhs[alev]);
1104 linop.unimposeNeumannBC(alev, rhs[alev]);
1105 linop.applyInhomogNeumannTerm(alev, rhs[alev]);
1106 linop.applyOverset(alev, rhs[alev]);
1107 if ( ! precond_mode) {
1108 bool r = linop.scaleRHS(alev, &(rhs[alev]));
1114 if (factory && !factory->isAllRegular()) {
1115 if constexpr (std::is_same<MF,MultiFab>()) {
1119 amrex::Abort(
"TODO: MLMG with EB only works with MultiFab");
1125 for (
int falev = finest_amr_lev; falev > 0; --falev)
1127 linop.averageDownSolutionRHS(falev-1, sol[falev-1], rhs[falev-1], sol[falev], rhs[falev]);
1131 if (linop.isSingular(0) && linop.getEnforceSingularSolvable())
1136 IntVect ng = linop.getNGrowVectRestriction();
1137 if (cf_strategy == CFStrategy::ghostnodes) { ng = ng_rhs; }
1138 if (!solve_called) {
1139 linop.make(res, ng);
1140 linop.make(rescor, ng);
1142 for (
int alev = 0; alev <= finest_amr_lev; ++alev)
1144 const int nmglevs = linop.NMGLevels(alev);
1145 for (
int mglev = 0; mglev < nmglevs; ++mglev)
1147 setVal(res [alev][mglev],
RT(0.0));
1148 setVal(rescor[alev][mglev],
RT(0.0));
1152 if (cf_strategy != CFStrategy::ghostnodes) { ng = ng_sol; }
1154 for (
int alev = 0; alev <= finest_amr_lev; ++alev)
1156 const int nmglevs = linop.NMGLevels(alev);
1157 cor[alev].resize(nmglevs);
1158 for (
int mglev = 0; mglev < nmglevs; ++mglev)
1160 if (!solve_called) {
1162 if (cf_strategy == CFStrategy::ghostnodes) { _ng=
IntVect(linop.getNGrow(alev,mglev)); }
1163 cor[alev][mglev] = linop.make(alev, mglev, _ng);
1169 cor_hold.resize(std::max(namrlevs-1,1));
1172 const int nmglevs = linop.NMGLevels(alev);
1173 cor_hold[alev].resize(nmglevs);
1174 for (
int mglev = 0; mglev < nmglevs-1; ++mglev)
1176 if (!solve_called) {
1178 if (cf_strategy == CFStrategy::ghostnodes) { _ng=
IntVect(linop.getNGrow(alev,mglev)); }
1179 cor_hold[alev][mglev] = linop.make(alev, mglev, _ng);
1181 setVal(cor_hold[alev][mglev],
RT(0.0));
1184 for (
int alev = 1; alev < finest_amr_lev; ++alev)
1186 cor_hold[alev].resize(1);
1187 if (!solve_called) {
1189 if (cf_strategy == CFStrategy::ghostnodes) { _ng=
IntVect(linop.getNGrow(alev)); }
1190 cor_hold[alev][0] = linop.make(alev, 0, _ng);
1192 setVal(cor_hold[alev][0],
RT(0.0));
1196 || !linop.supportNSolve())
1201 if (do_nsolve && ns_linop ==
nullptr)
1207 amrex::Print() << print_ident <<
"MLMG: # of AMR levels: " << namrlevs <<
"\n"
1208 << print_ident <<
" # of MG levels on the coarsest AMR level: " << linop.NMGLevels(0)
1211 amrex::Print() << print_ident <<
" # of MG levels in N-Solve: " << ns_linop->NMGLevels(0) <<
"\n"
1212 << print_ident <<
" # of grids in N-Solve: " << ns_linop->m_grids[0][0].size() <<
"\n";
1217template <
typename MF>
1221 if (!linop_prepared) {
1222 linop.prepareForSolve();
1223 linop_prepared =
true;
1224 }
else if (linop.needsUpdate()) {
1229template <
typename MF>
1234 linop.preparePrecond();
1237template <
typename MF>
1241 if constexpr (IsMultiFabLike_v<MF>) {
1242 ns_linop = linop.makeNLinOp(nsolve_grid_size);
1245 if (cf_strategy == CFStrategy::ghostnodes) { nghost = linop.getNGrow(); }
1247 const BoxArray& ba = (*ns_linop).m_grids[0][0];
1251 if (cf_strategy == CFStrategy::ghostnodes) { ng = nghost; }
1252 ns_sol = std::make_unique<MF>(ba, dm, ncomp, ng,
MFInfo(), *(ns_linop->Factory(0,0)));
1254 if (cf_strategy == CFStrategy::ghostnodes) { ng = nghost; }
1255 ns_rhs = std::make_unique<MF>(ba, dm, ncomp, ng,
MFInfo(), *(ns_linop->Factory(0,0)));
1259 ns_linop->setLevelBC(0, ns_sol.get());
1261 ns_mlmg = std::make_unique<MLMGT<MF>>(*ns_linop);
1262 ns_mlmg->setVerbose(0);
1263 ns_mlmg->setFixedIter(1);
1264 ns_mlmg->setMaxFmgIter(20);
1271template <
typename MF>
1276 for (
int alev = finest_amr_lev; alev > 0; --alev)
1281 if (cf_strategy == CFStrategy::ghostnodes) { nghost =
IntVect(linop.getNGrow(alev)); }
1282 LocalAdd(sol[alev], cor[alev][0], 0, 0, ncomp, nghost);
1285 computeResWithCrseSolFineCor(alev-1,alev);
1287 if (alev != finest_amr_lev) {
1288 std::swap(cor_hold[alev][0], cor[alev][0]);
1295 if (linop.isSingular(0) && linop.getEnforceSingularSolvable())
1297 makeSolvable(0,0,res[0][0]);
1300 if (iter < max_fmg_iters) {
1307 if (cf_strategy == CFStrategy::ghostnodes) { nghost =
IntVect(linop.getNGrow(0)); }
1308 LocalAdd(sol[0], cor[0][0], 0, 0, ncomp, nghost);
1311 for (
int alev = 1; alev <= finest_amr_lev; ++alev)
1314 interpCorrection(alev);
1317 if (cf_strategy == CFStrategy::ghostnodes) { nghost =
IntVect(linop.getNGrow(alev)); }
1318 LocalAdd(sol[alev], cor[alev][0], 0, 0, ncomp, nghost);
1320 if (alev != finest_amr_lev) {
1321 LocalAdd(cor_hold[alev][0], cor[alev][0], 0, 0, ncomp, nghost);
1325 computeResWithCrseCorFineCor(alev);
1329 LocalAdd(sol[alev], cor[alev][0], 0, 0, ncomp, nghost);
1331 if (alev != finest_amr_lev) {
1332 LocalAdd(cor[alev][0], cor_hold[alev][0], 0, 0, ncomp, nghost);
1336 linop.averageDownAndSync(sol);
1339template <
typename MF>
1344 const int mglev = 0;
1345 mgVcycle(amrlev, mglev);
1350template <
typename MF>
1356 const int mglev_bottom = linop.NMGLevels(amrlev) - 1;
1358 for (
int mglev = mglev_top; mglev < mglev_bottom; ++mglev)
1360 BL_PROFILE_VAR(
"MLMG::mgVcycle_down::"+std::to_string(mglev), blp_mgv_down_lev);
1365 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
1366 <<
" DN: Norm before smooth " <<
norm <<
"\n";
1369 setVal(cor[amrlev][mglev],
RT(0.0));
1370 bool skip_fillboundary =
true;
1371 linop.smooth(amrlev, mglev, cor[amrlev][mglev], res[amrlev][mglev], skip_fillboundary, nu1);
1374 computeResOfCorrection(amrlev, mglev);
1379 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
1380 <<
" DN: Norm after smooth " <<
norm <<
"\n";
1384 linop.restriction(amrlev, mglev+1, res[amrlev][mglev+1], rescor[amrlev][mglev]);
1393 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
1394 <<
" DN: Norm before bottom " <<
norm <<
"\n";
1399 computeResOfCorrection(amrlev, mglev_bottom);
1401 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
1402 <<
" UP: Norm after bottom " <<
norm <<
"\n";
1410 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
1411 <<
" Norm before smooth " <<
norm <<
"\n";
1413 setVal(cor[amrlev][mglev_bottom],
RT(0.0));
1414 bool skip_fillboundary =
true;
1415 linop.smooth(amrlev, mglev_bottom, cor[amrlev][mglev_bottom],
1416 res[amrlev][mglev_bottom], skip_fillboundary, nu1);
1419 computeResOfCorrection(amrlev, mglev_bottom);
1421 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev_bottom
1422 <<
" Norm after smooth " <<
norm <<
"\n";
1427 for (
int mglev = mglev_bottom-1; mglev >= mglev_top; --mglev)
1429 BL_PROFILE_VAR(
"MLMG::mgVcycle_up::"+std::to_string(mglev), blp_mgv_up_lev);
1431 addInterpCorrection(amrlev, mglev);
1434 computeResOfCorrection(amrlev, mglev);
1436 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
1437 <<
" UP: Norm before smooth " <<
norm <<
"\n";
1439 linop.smooth(amrlev, mglev, cor[amrlev][mglev], res[amrlev][mglev],
false, nu2);
1441 if (cf_strategy == CFStrategy::ghostnodes) { computeResOfCorrection(amrlev, mglev); }
1445 computeResOfCorrection(amrlev, mglev);
1447 amrex::Print() << print_ident <<
"AT LEVEL " << amrlev <<
" " << mglev
1448 <<
" UP: Norm after smooth " <<
norm <<
"\n";
1456template <
typename MF>
1463 auto* pf = linop.Factory(0);
1464 auto is_all_regular = [pf] () {
1473 AMREX_ASSERT(linop.isCellCentered() || is_all_regular());
1476 const int amrlev = 0;
1477 const int mg_bottom_lev = linop.NMGLevels(amrlev) - 1;
1479 if (cf_strategy == CFStrategy::ghostnodes) { nghost =
IntVect(linop.getNGrow(amrlev)); }
1481 for (
int mglev = 1; mglev <= mg_bottom_lev; ++mglev)
1483 linop.avgDownResMG(mglev, res[amrlev][mglev], res[amrlev][mglev-1]);
1488 for (
int mglev = mg_bottom_lev-1; mglev >= 0; --mglev)
1491 interpCorrection(amrlev, mglev);
1494 computeResOfCorrection(amrlev, mglev);
1496 LocalCopy(res[amrlev][mglev], rescor[amrlev][mglev], 0, 0, ncomp, nghost);
1499 std::swap(cor[amrlev][mglev], cor_hold[amrlev][mglev]);
1500 mgVcycle(amrlev, mglev);
1501 LocalAdd(cor[amrlev][mglev], cor_hold[amrlev][mglev], 0, 0, ncomp, nghost);
1508template <
typename MF>
1514 NSolve(*ns_mlmg, *ns_sol, *ns_rhs);
1518 actualBottomSolve();
1522template <
typename MF>
1530 MF
const& res_bottom = res[0].back();
1541 RT(-1.0),
RT(-1.0));
1543 linop.copyNSolveSolution(cor[0].back(), a_sol);
1546template <
typename MF>
1552 if (!linop.isBottomActive()) {
return; }
1558 const int amrlev = 0;
1559 const int mglev = linop.NMGLevels(amrlev) - 1;
1560 auto&
x = cor[amrlev][mglev];
1561 auto& b = res[amrlev][mglev];
1567 bool skip_fillboundary =
true;
1568 linop.smooth(amrlev, mglev,
x, b, skip_fillboundary, nuf);
1574 if (linop.isBottomSingular() && linop.getEnforceSingularSolvable())
1577 raii_b = linop.make(amrlev, mglev, ng);
1581 makeSolvable(amrlev,mglev,*bottom_b);
1586#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
1587 if constexpr (std::is_same<MF,MultiFab>()) {
1588 bottomSolveWithHypre(
x, *bottom_b);
1592 amrex::Abort(
"Using Hypre as bottom solver not supported in this case");
1597#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
1598 if constexpr (std::is_same<MF,MultiFab>()) {
1599 bottomSolveWithPETSc(
x, *bottom_b);
1603 amrex::Abort(
"Using PETSc as bottom solver not supported in this case");
1616 int ret = bottomSolveWithCG(
x, *bottom_b, cg_type);
1626 setVal(cor[amrlev][mglev],
RT(0.0));
1627 ret = bottomSolveWithCG(
x, *bottom_b, cg_type);
1638 if (ret != 0 && ret != 9) {
1639 setVal(cor[amrlev][mglev],
RT(0.0));
1641 const int n = (ret==0) ? nub : nuf;
1642 linop.smooth(amrlev, mglev,
x, b,
false, n);
1648 if (! timer.empty()) {
1653template <
typename MF>
1663 if (cf_strategy == CFStrategy::ghostnodes) { cg_solver.
setNGhost(linop.getNGrow()); }
1665 int ret = cg_solver.
solve(
x, b, bottom_reltol, bottom_abstol);
1666 if (ret != 0 && verbose > 1) {
1667 amrex::Print() << print_ident <<
"MLMG: Bottom solve failed.\n";
1674template <
typename MF>
1680 const int mglev = 0;
1681 for (
int alev = amrlevmax; alev >= 0; --alev) {
1682 const MF* crse_bcdata = (alev > 0) ? &(sol[alev-1]) :
nullptr;
1683 linop.solutionResidual(alev, res[alev][mglev], sol[alev], rhs[alev], crse_bcdata);
1684 if (alev < finest_amr_lev) {
1685 linop.reflux(alev, res[alev][mglev], sol[alev], rhs[alev],
1686 res[alev+1][mglev], sol[alev+1], rhs[alev+1]);
1692template <
typename MF>
1697 const MF* crse_bcdata = (alev > 0) ? &(sol[alev-1]) :
nullptr;
1698 linop.solutionResidual(alev, res[alev][0], sol[alev], rhs[alev], crse_bcdata);
1702template <
typename MF>
1706 BL_PROFILE(
"MLMG::computeResWithCrseSolFineCor()");
1709 if (cf_strategy == CFStrategy::ghostnodes) {
1710 nghost =
IntVect(std::min(linop.getNGrow(falev),linop.getNGrow(calev)));
1713 MF& crse_sol = sol[calev];
1714 const MF& crse_rhs = rhs[calev];
1715 MF& crse_res = res[calev][0];
1717 MF& fine_sol = sol[falev];
1718 const MF& fine_rhs = rhs[falev];
1719 MF& fine_cor = cor[falev][0];
1720 MF& fine_res = res[falev][0];
1721 MF& fine_rescor = rescor[falev][0];
1723 const MF* crse_bcdata = (calev > 0) ? &(sol[calev-1]) :
nullptr;
1724 linop.solutionResidual(calev, crse_res, crse_sol, crse_rhs, crse_bcdata);
1726 linop.correctionResidual(falev, 0, fine_rescor, fine_cor, fine_res, BCMode::Homogeneous);
1727 LocalCopy(fine_res, fine_rescor, 0, 0, ncomp, nghost);
1729 linop.reflux(calev, crse_res, crse_sol, crse_rhs, fine_res, fine_sol, fine_rhs);
1731 linop.avgDownResAmr(calev, crse_res, fine_res);
1735template <
typename MF>
1739 BL_PROFILE(
"MLMG::computeResWithCrseCorFineCor()");
1742 if (cf_strategy == CFStrategy::ghostnodes) {
1743 nghost =
IntVect(linop.getNGrow(falev));
1746 const MF& crse_cor = cor[falev-1][0];
1748 MF& fine_cor = cor [falev][0];
1749 MF& fine_res = res [falev][0];
1750 MF& fine_rescor = rescor[falev][0];
1753 linop.correctionResidual(falev, 0, fine_rescor, fine_cor, fine_res,
1754 BCMode::Inhomogeneous, &crse_cor);
1755 LocalCopy(fine_res, fine_rescor, 0, 0, ncomp, nghost);
1759template <
typename MF>
1766 if (cf_strategy == CFStrategy::ghostnodes) {
1767 nghost =
IntVect(linop.getNGrow(alev));
1770 MF & crse_cor = cor[alev-1][0];
1771 MF & fine_cor = cor[alev ][0];
1773 const Geometry& crse_geom = linop.Geom(alev-1,0);
1776 int ng_dst = linop.isCellCentered() ? 1 : 0;
1777 if (cf_strategy == CFStrategy::ghostnodes)
1779 ng_src = linop.getNGrow(alev-1);
1780 ng_dst = linop.getNGrow(alev-1);
1781 if constexpr (IsMultiFabLike_v<MF>) {
1784 amrex::Abort(
"MLMG: CFStrategy::ghostnodes not supported for non-MultiFab like types");
1788 MF cfine = linop.makeCoarseAmr(alev,
IntVect(ng_dst));
1793 linop.interpolationAmr(alev, fine_cor, cfine, nghost);
1799template <
typename MF>
1805 MF& crse_cor = cor[alev][mglev+1];
1806 MF& fine_cor = cor[alev][mglev ];
1807 linop.interpAssign(alev, mglev, fine_cor, crse_cor);
1811template <
typename MF>
1817 const MF& crse_cor = cor[alev][mglev+1];
1818 MF& fine_cor = cor[alev][mglev ];
1823 if (linop.isMFIterSafe(alev, mglev, mglev+1))
1829 cfine = linop.makeCoarseMG(alev, mglev,
IntVect(0));
1834 linop.interpolation(alev, mglev, fine_cor, *cmf);
1841template <
typename MF>
1846 MF &
x = cor[amrlev][mglev];
1847 const MF& b = res[amrlev][mglev];
1848 MF & r = rescor[amrlev][mglev];
1849 linop.correctionResidual(amrlev, mglev, r,
x, b, BCMode::Homogeneous);
1853template <
typename MF>
1858 return linop.normInf(alev, res[alev][0], local);
1862template <
typename MF>
1868 for (
int alev = 0; alev <= alevmax; ++alev)
1870 r = std::max(r, ResNormInf(alev,
true));
1877template <
typename MF>
1883 for (
int alev = 0; alev <= finest_amr_lev; ++alev) {
1884 auto t = linop.normInf(alev, rhs[alev],
true);
1891template <
typename MF>
1895 auto const&
offset = linop.getSolvabilityOffset(0, 0, rhs[0]);
1897 for (
int c = 0; c < ncomp; ++c) {
1898 amrex::Print() << print_ident <<
"MLMG: Subtracting " <<
offset[c] <<
" from rhs component "
1902 for (
int alev = 0; alev < namrlevs; ++alev) {
1903 linop.fixSolvabilityByOffset(alev, 0, rhs[alev],
offset);
1907template <
typename MF>
1911 auto const&
offset = linop.getSolvabilityOffset(amrlev, mglev, mf);
1913 for (
int c = 0; c < ncomp; ++c) {
1915 <<
" from mf component c = " << c
1916 <<
" on level (" << amrlev <<
", " << mglev <<
")\n";
1919 linop.fixSolvabilityByOffset(amrlev, mglev, mf,
offset);
1922#if defined(AMREX_USE_HYPRE) && (AMREX_SPACEDIM > 1)
1923template <
typename MF>
1924template <
class TMF,std::enable_if_t<std::is_same_v<TMF,MultiFab>,
int>>
1928 const int amrlev = 0;
1929 const int mglev = linop.NMGLevels(amrlev) - 1;
1933 if (linop.isCellCentered())
1935 if (hypre_solver ==
nullptr)
1937 hypre_solver = linop.makeHypre(hypre_interface);
1939 hypre_solver->setVerbose(bottom_verbose);
1941 hypre_solver->setHypreOptionsNamespace(hypre_options_namespace);
1943 hypre_solver->setHypreOldDefault(hypre_old_default);
1944 hypre_solver->setHypreRelaxType(hypre_relax_type);
1945 hypre_solver->setHypreRelaxOrder(hypre_relax_order);
1946 hypre_solver->setHypreNumSweeps(hypre_num_sweeps);
1947 hypre_solver->setHypreStrongThreshold(hypre_strong_threshold);
1950 const BoxArray& ba = linop.m_grids[amrlev].back();
1951 const DistributionMapping& dm = linop.m_dmap[amrlev].back();
1952 const Geometry& geom = linop.m_geom[amrlev].back();
1954 hypre_bndry = std::make_unique<MLMGBndryT<MF>>(ba, dm, ncomp, geom);
1955 hypre_bndry->setHomogValues();
1956 const Real* dx = linop.m_geom[0][0].CellSize();
1957 IntVect crse_ratio = linop.m_coarse_data_crse_ratio.
allGT(0) ? linop.m_coarse_data_crse_ratio :
IntVect(1);
1959 0.5*dx[1]*crse_ratio[1],
1960 0.5*dx[2]*crse_ratio[2]));
1961 hypre_bndry->setLOBndryConds(linop.m_lobc, linop.m_hibc,
IntVect(-1), bclocation,
1962 linop.m_coarse_fine_bc_type);
1968 ? bottom_abstol :
Real(-1.0);
1969 hypre_solver->solve(
1970 x, b, bottom_reltol, hypre_abstol, bottom_maxiter, *hypre_bndry,
1971 linop.getMaxOrder());
1975 if (hypre_node_solver ==
nullptr)
1978 linop.makeHypreNodeLap(bottom_verbose, hypre_options_namespace);
1980 hypre_node_solver->solve(
x, b, bottom_reltol, bottom_abstol, bottom_maxiter);
1985 if (linop.isSingular(amrlev) && linop.getEnforceSingularSolvable())
1987 makeSolvable(amrlev, mglev,
x);
1992#if defined(AMREX_USE_PETSC) && (AMREX_SPACEDIM > 1)
1993template <
typename MF>
1994template <
class TMF,std::enable_if_t<std::is_same_v<TMF,MultiFab>,
int>>
1996MLMGT<MF>::bottomSolveWithPETSc (MF&
x,
const MF& b)
2000 if(petsc_solver ==
nullptr)
2002 petsc_solver = linop.makePETSc();
2003 petsc_solver->setVerbose(bottom_verbose);
2005 const BoxArray& ba = linop.m_grids[0].back();
2006 const DistributionMapping& dm = linop.m_dmap[0].back();
2007 const Geometry& geom = linop.m_geom[0].back();
2009 petsc_bndry = std::make_unique<MLMGBndryT<MF>>(ba, dm, ncomp, geom);
2010 petsc_bndry->setHomogValues();
2011 const Real* dx = linop.m_geom[0][0].CellSize();
2012 auto crse_ratio = linop.m_coarse_data_crse_ratio.allGT(0) ? linop.m_coarse_data_crse_ratio :
IntVect(1);
2014 0.5*dx[1]*crse_ratio[1],
2015 0.5*dx[2]*crse_ratio[2]));
2016 petsc_bndry->setLOBndryConds(linop.m_lobc, linop.m_hibc,
IntVect(-1), bclocation,
2017 linop.m_coarse_fine_bc_type);
2019 petsc_solver->solve(
x, b, bottom_reltol,
Real(-1.), bottom_maxiter, *petsc_bndry,
2020 linop.getMaxOrder());
2024template <
typename MF>
2026MLMGT<MF>::checkPoint (
const Vector<MultiFab*>& a_sol,
2027 const Vector<MultiFab const*>& a_rhs,
2028 RT a_tol_rel, RT a_tol_abs,
const char* a_file_name)
const
2030 std::string file_name(a_file_name);
2035 std::string HeaderFileName(std::string(a_file_name)+
"/Header");
2036 std::ofstream HeaderFile;
2037 HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
2038 std::ofstream::trunc |
2039 std::ofstream::binary);
2040 if( ! HeaderFile.good()) {
2044 HeaderFile.precision(17);
2048 HeaderFile << linop.name() <<
"\n"
2049 <<
"a_tol_rel = " << a_tol_rel <<
"\n"
2050 <<
"a_tol_abs = " << a_tol_abs <<
"\n"
2051 <<
"verbose = " <<
verbose <<
"\n"
2052 <<
"max_iters = " << max_iters <<
"\n"
2053 <<
"nu1 = " << nu1 <<
"\n"
2054 <<
"nu2 = " << nu2 <<
"\n"
2055 <<
"nuf = " << nuf <<
"\n"
2056 <<
"nub = " << nub <<
"\n"
2057 <<
"max_fmg_iters = " << max_fmg_iters <<
"\n"
2058 <<
"bottom_solver = " <<
static_cast<int>(bottom_solver) <<
"\n"
2059 <<
"bottom_verbose = " << bottom_verbose <<
"\n"
2060 <<
"bottom_maxiter = " << bottom_maxiter <<
"\n"
2061 <<
"bottom_reltol = " << bottom_reltol <<
"\n"
2062 <<
"convergence_norm = " << norm_name <<
"\n"
2063 <<
"namrlevs = " << namrlevs <<
"\n"
2064 <<
"finest_amr_lev = " << finest_amr_lev <<
"\n"
2065 <<
"linop_prepared = " << linop_prepared <<
"\n"
2066 <<
"solve_called = " << solve_called <<
"\n";
2068 for (
int ilev = 0; ilev <= finest_amr_lev; ++ilev) {
2075 for (
int ilev = 0; ilev <= finest_amr_lev; ++ilev) {
2076 VisMF::Write(*a_sol[ilev], file_name+
"/Level_"+std::to_string(ilev)+
"/sol");
2077 VisMF::Write(*a_rhs[ilev], file_name+
"/Level_"+std::to_string(ilev)+
"/rhs");
2080 linop.checkPoint(file_name+
"/linop");
2083template <
typename MF>
2087 print_ident.resize(print_ident.size()+4,
' ');
2090template <
typename MF>
2094 if (print_ident.size() > 4) {
2095 print_ident.resize(print_ident.size()-4,
' ');
2097 print_ident.clear();
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:551
#define BL_PROFILE_VAR_STOP(vname)
Definition AMReX_BLProfiler.H:563
#define BL_PROFILE_VAR(fname, vname)
Definition AMReX_BLProfiler.H:560
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_ENUM(CLASS,...)
Definition AMReX_Enum.H:208
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1089
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
Print on all processors of the default communicator.
Definition AMReX_Print.H:117
A collection of Boxes stored in an Array.
Definition AMReX_BoxArray.H:567
static bool SameRefs(const BoxArray &lhs, const BoxArray &rhs)
whether two BoxArrays share the same data
Definition AMReX_BoxArray.H:840
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:43
static bool SameRefs(const DistributionMapping &lhs, const DistributionMapping &rhs)
Definition AMReX_DistributionMapping.H:189
Definition AMReX_EBFabFactory.H:25
bool isAllRegular() const noexcept
Definition AMReX_EBFabFactory.cpp:148
Solve using GMRES with multigrid as preconditioner.
Definition AMReX_GMRES_MLMG.H:22
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:74
Periodicity periodicity() const noexcept
Definition AMReX_Geometry.H:356
Interface
Definition AMReX_Hypre.H:21
__host__ __device__ constexpr bool allGT(const IntVectND< dim > &rhs) const noexcept
Returns true if this is greater than argument for all components. NOTE: This is NOT a strict weak ord...
Definition AMReX_IntVect.H:425
__host__ __device__ constexpr IntVectND< new_dim > resize(int fill_extra=0) const noexcept
Returns a new IntVectND of size new_dim by either shrinking or expanding this IntVectND.
Definition AMReX_IntVect.H:775
__host__ static __device__ constexpr IntVectND< dim > TheDimensionVector(int d) noexcept
This static member function returns a reference to a constant IntVectND object, all of whose dim argu...
Definition AMReX_IntVect.H:698
Definition AMReX_MLCGSolver.H:12
void setSolver(Type _typ) noexcept
Definition AMReX_MLCGSolver.H:28
void setVerbose(int _verbose)
Definition AMReX_MLCGSolver.H:39
int getNumIters() const noexcept
Definition AMReX_MLCGSolver.H:64
void setInitSolnZeroed(bool _sol_zeroed)
Definition AMReX_MLCGSolver.H:53
void setPrintIdentation(std::string s)
Definition AMReX_MLCGSolver.H:45
int solve(MF &solnL, const MF &rhsL, RT eps_rel, RT eps_abs)
Definition AMReX_MLCGSolver.H:89
Type
Definition AMReX_MLCGSolver.H:18
void setNGhost(int _nghost)
Definition AMReX_MLCGSolver.H:56
void setMaxIter(int _maxiter)
Definition AMReX_MLCGSolver.H:42
Definition AMReX_MLLinOp.H:102
typename FabDataType< MF >::fab_type FAB
Definition AMReX_MLLinOp.H:112
typename FabDataType< MF >::value_type RT
Definition AMReX_MLLinOp.H:113
Definition AMReX_MLMG.H:22
Definition AMReX_MLMG.H:17
void prepareForFluxes(Vector< MF const * > const &a_sol)
Definition AMReX_MLMG.H:630
void setBottomVerbose(int v) noexcept
Definition AMReX_MLMG.H:148
void setMaxFmgIter(int n) noexcept
Definition AMReX_MLMG.H:136
RT MLResNormInf(int alevmax, bool local=false)
Definition AMReX_MLMG.H:1864
RT MLRhsNormInf(bool local=false)
Definition AMReX_MLMG.H:1879
void setNoGpuSync(bool do_not_sync) noexcept
Definition AMReX_MLMG.H:166
MLMGT(MLMGT< MF > &&)=delete
void actualBottomSolve()
Definition AMReX_MLMG.H:1548
MF MFType
Definition AMReX_MLMG.H:30
BottomSolver getBottomSolver() const noexcept
Definition AMReX_MLMG.H:146
void setPreSmooth(int n) noexcept
Definition AMReX_MLMG.H:140
void setBottomToleranceAbs(RT t) noexcept
Definition AMReX_MLMG.H:151
RT getFinalResidual() const noexcept
Definition AMReX_MLMG.H:246
void interpCorrection(int alev)
Definition AMReX_MLMG.H:1761
void getEBFluxes(const Vector< MF * > &a_eb_flux)
Definition AMReX_MLMG.H:851
void getGradSolution(const Vector< Array< AMF *, 3 > > &a_grad_sol, Location a_loc=Location::FaceCenter)
Definition AMReX_MLMG.H:641
void setBottomSmooth(int n) noexcept
Definition AMReX_MLMG.H:143
void setNSolve(int flag) noexcept
Definition AMReX_MLMG.H:163
int getBottomVerbose() const
Definition AMReX_MLMG.H:128
void computeResOfCorrection(int amrlev, int mglev)
Definition AMReX_MLMG.H:1843
void applyPrecond(const Vector< MF * > &out, const Vector< MF * > &in)
out = L(in) as a preconditioner
Definition AMReX_MLMG.H:1021
void setCFStrategy(CFStrategy a_cf_strategy) noexcept
Definition AMReX_MLMG.H:147
void computeResWithCrseCorFineCor(int falev)
Definition AMReX_MLMG.H:1737
void NSolve(MLMGT< MF > &a_solver, MF &a_sol, MF &a_rhs)
Definition AMReX_MLMG.H:1524
typename MLLinOpT< MF >::Location Location
Definition AMReX_MLMG.H:35
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:945
void getFluxes(const Vector< Array< AMF *, 3 > > &a_flux, Location a_loc=Location::FaceCenter)
For (alpha * a - beta * (del dot b grad)) phi = rhs, flux means -b grad phi
Definition AMReX_MLMG.H:672
void setNSolveGridSize(int s) noexcept
Definition AMReX_MLMG.H:164
void setVerbose(int v) noexcept
Definition AMReX_MLMG.H:134
void computeMLResidual(int amrlevmax)
Definition AMReX_MLMG.H:1676
RT getInitResidual() const noexcept
Definition AMReX_MLMG.H:244
int getNumIters() const noexcept
Definition AMReX_MLMG.H:249
void setPostSmooth(int n) noexcept
Definition AMReX_MLMG.H:141
void mgVcycle(int amrlev, int mglev)
Definition AMReX_MLMG.H:1352
void prepareForNSolve()
Definition AMReX_MLMG.H:1239
RT precond(Vector< MF * > const &a_sol, Vector< MF const * > const &a_rhs, RT a_tol_rel, RT a_tol_abs)
Definition AMReX_MLMG.H:612
void makeSolvable()
Definition AMReX_MLMG.H:1893
void setBottomSolver(BottomSolver s) noexcept
Definition AMReX_MLMG.H:145
void preparePrecond()
Definition AMReX_MLMG.H:1231
void incPrintIdentation()
Definition AMReX_MLMG.H:2085
typename MLLinOpT< MF >::RT RT
Definition AMReX_MLMG.H:32
void setThrowException(bool t) noexcept
Definition AMReX_MLMG.H:133
void decPrintIdentation()
Definition AMReX_MLMG.H:2092
void setFixedIter(int nit) noexcept
Definition AMReX_MLMG.H:137
Vector< RT > const & getResidualHistory() const noexcept
Definition AMReX_MLMG.H:248
void prepareLinOp()
Definition AMReX_MLMG.H:1219
void setPrecondIter(int nit) noexcept
Definition AMReX_MLMG.H:138
CFStrategy
Definition AMReX_MLMG.H:38
void prepareForSolve(Vector< AMF * > const &a_sol, Vector< AMF const * > const &a_rhs)
Definition AMReX_MLMG.H:1033
int bottomSolveWithCG(MF &x, const MF &b, typename MLCGSolverT< MF >::Type type)
Definition AMReX_MLMG.H:1655
void setAlwaysUseBNorm(int flag) noexcept
Definition AMReX_MLMG.H:371
void compResidual(const Vector< MF * > &a_res, const Vector< MF * > &a_sol, const Vector< MF const * > &a_rhs)
Definition AMReX_MLMG.H:877
void miniCycle(int amrlev)
Definition AMReX_MLMG.H:1341
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)
void setFinalFillBC(int flag) noexcept
Definition AMReX_MLMG.H:159
typename MLLinOpT< MF >::BCMode BCMode
Definition AMReX_MLMG.H:34
void setConvergenceNormType(MLMGNormType norm) noexcept
Definition AMReX_MLMG.H:157
void computeResWithCrseSolFineCor(int calev, int falev)
Definition AMReX_MLMG.H:1704
MLMGT< MF > & operator=(MLMGT< MF > const &)=delete
MLMGT(MLLinOpT< MF > &a_lp)
Definition AMReX_MLMG.H:362
void computeResidual(int alev)
Definition AMReX_MLMG.H:1694
MLLinOpT< MF > & getLinOp()
Definition AMReX_MLMG.H:252
typename MLLinOpT< MF >::FAB FAB
Definition AMReX_MLMG.H:31
RT getBottomToleranceAbs() const noexcept
Definition AMReX_MLMG.H:152
int numAMRLevels() const noexcept
Definition AMReX_MLMG.H:161
MLMGT(MLMGT< MF > const &)=delete
void mgFcycle()
Definition AMReX_MLMG.H:1458
RT getInitRHS() const noexcept
Definition AMReX_MLMG.H:242
RT ResNormInf(int alev, bool local=false)
Definition AMReX_MLMG.H:1855
Vector< int > const & getNumCGIters() const noexcept
Definition AMReX_MLMG.H:250
void bottomSolve()
Definition AMReX_MLMG.H:1510
void setBottomTolerance(RT t) noexcept
Definition AMReX_MLMG.H:150
void setFinalSmooth(int n) noexcept
Definition AMReX_MLMG.H:142
void addInterpCorrection(int alev, int mglev)
Definition AMReX_MLMG.H:1813
int getVerbose() const
Definition AMReX_MLMG.H:127
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)
void setBottomMaxIter(int n) noexcept
Definition AMReX_MLMG.H:149
void oneIter(int iter)
Definition AMReX_MLMG.H:1272
void setMaxIter(int n) noexcept
Definition AMReX_MLMG.H:135
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:28
Long size() const noexcept
Definition AMReX_Vector.H:53
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:979
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:79
amrex_long Long
Definition AMReX_INT.H:30
std::array< T, N > Array
Definition AMReX_Array.H:26
void Max(KeyValuePair< K, V > &vi, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:133
bool setNoSyncRegion(bool b) noexcept
Definition AMReX_GpuControl.H:158
bool setSingleStreamRegion(bool b) noexcept
Definition AMReX_GpuControl.H:154
void push(MPI_Comm c)
Definition AMReX_ParallelContext.H:102
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:108
bool IOProcessorSub() noexcept
Am IO processor for current frame?
Definition AMReX_ParallelContext.H:80
int verbose
Definition AMReX.cpp:105
Definition AMReX_Amr.cpp:49
MF::value_type norminf(MF const &mf, int scomp, int ncomp, IntVect const &nghost, bool local=false)
Definition AMReX_FabArrayUtility.H:2029
__host__ __device__ void ignore_unused(const Ts &...)
This shuts up the compiler about unused variables.
Definition AMReX.H:138
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a BoxND with different type.
Definition AMReX_Box.H:1558
int nComp(FabArrayBase const &fa)
Definition AMReX_FabArrayBase.cpp:2854
void FileOpenFailed(const std::string &file)
Output a message and abort when couldn't open the file.
Definition AMReX_Utility.cpp:137
void EB_average_face_to_cellcenter(MultiFab &ccmf, int dcomp, const Array< MultiFab const *, 3 > &fmf)
Definition AMReX_EBMultiFabUtil.cpp:806
std::array< T const *, 3 > GetArrOfConstPtrs(const std::array< T, 3 > &a) noexcept
Definition AMReX_Array.H:1017
__host__ __device__ T norm(const GpuComplex< T > &a_z) noexcept
Return the norm (magnitude squared) of a complex number.
Definition AMReX_GpuComplex.H:349
DistributionMapping const & DistributionMap(FabArrayBase const &fa)
Definition AMReX_FabArrayBase.cpp:2869
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:336
std::string getEnumNameString(T const &v)
Definition AMReX_Enum.H:156
IntVect nGrowVect(FabArrayBase const &fa)
Definition AMReX_FabArrayBase.cpp:2859
void average_face_to_cellcenter(MultiFab &cc, int dcomp, const Vector< const MultiFab * > &fc, IntVect const &ng_vect)
Definition AMReX_MultiFabUtil.cpp:155
void LocalCopy(DMF &dst, SMF const &src, int scomp, int dcomp, int ncomp, IntVect const &nghost)
dst = src
Definition AMReX_FabArrayUtility.H:1950
void EB_set_covered(MultiFab &mf, Real val)
Definition AMReX_EBMultiFabUtil.cpp:21
void LocalAdd(MF &dst, MF const &src, int scomp, int dcomp, int ncomp, IntVect const &nghost)
dst += src
Definition AMReX_FabArrayUtility.H:1958
double second() noexcept
Definition AMReX_Utility.cpp:940
std::array< T *, 3 > GetArrOfPtrs(std::array< T, 3 > &a) noexcept
Definition AMReX_Array.H:1005
void UtilCreateCleanDirectory(const std::string &path, bool callbarrier=true)
Create a new directory, renaming the old one if it exists.
Definition AMReX_Utility.cpp:167
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)
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)
res = b - A*x
Definition AMReX_SpMV.H:226
BottomSolver
Definition AMReX_MLLinOp.H:31
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:33
RealVectND< 3 > RealVect
Definition AMReX_ParmParse.H:35
void setBndry(MF &dst, typename MF::value_type val, int scomp, int ncomp)
dst = val in ghost cells.
Definition AMReX_FabArrayUtility.H:1934
Vector< T * > GetVecOfPtrs(Vector< T > &a)
Definition AMReX_Vector.H:64
void Scale(MF &dst, typename MF::value_type val, int scomp, int ncomp, int nghost)
dst *= val
Definition AMReX_FabArrayUtility.H:1941
Vector< std::array< T *, 3 > > GetVecOfArrOfPtrs(const Vector< std::array< std::unique_ptr< T >, 3 > > &a)
Definition AMReX_Vector.H:141
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:230
MLMGNormType
Definition AMReX_MLMG.H:12
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:2019
void setVal(MF &dst, typename MF::value_type val)
dst = val
Definition AMReX_FabArrayUtility.H:1927
BoxArray const & boxArray(FabArrayBase const &fa)
Definition AMReX_FabArrayBase.cpp:2864
BCMode
Definition AMReX_MLLinOp.H:88
Location
Definition AMReX_MLLinOp.H:90
FabArray memory allocation information.
Definition AMReX_FabArray.H:66