13#ifndef CD_ELLIPTICSOLVERCHAINIMPLEM_H
14#define CD_ELLIPTICSOLVERCHAINIMPLEM_H
25#include <CD_NamespaceHeader.H>
42 if (m_workAllocated) {
45 m_op.clear(m_phiInit);
46 m_workAllocated =
false;
54 m_op.create(m_r0, a_template);
55 m_op.create(m_dphi, a_template);
56 m_op.create(m_phiInit, a_template);
57 m_workAllocated =
true;
64 CH_TIME(
"EllipticSolverChain::KrylovSolver::snapshotGuess");
66 if (!m_workAllocated) {
67 this->allocateWork(a_phi);
70 m_op.assign(m_phiInit, a_phi);
71 m_initResidual = m_mg->computeAMRResidual(a_phi, a_rhs, m_lmax, m_lbase);
78 CH_TIME(
"EllipticSolverChain::KrylovSolver::keepOrRestore");
80 const Real r = m_mg->computeAMRResidual(a_phi, a_rhs, m_lmax, m_lbase);
84 if (r >= m_initResidual) {
85 m_op.assign(a_phi, m_phiInit);
96 const Vector<RefCountedPtr<LevelData<BaseFab<bool>>>>& a_validCells,
97 const Vector<Real>& a_dx,
100 const int a_numVCycles)
102 CH_TIME(
"EllipticSolverChain::KrylovSolver::define");
112 m_op.define(a_mg, a_validCells, a_dx, a_lbase, a_lmax, a_numVCycles);
121 const bool a_zeroPhi,
125 CH_TIME(
"EllipticSolverChain::KrylovSolver::solve");
127 CH_assert(m_isDefined);
130 if (!m_workAllocated) {
131 this->allocateWork(a_rhs);
135 m_op.setToZero(a_phi);
142 m_mg->init(a_phi, a_rhs, m_lmax, m_lbase);
143 m_mg->setBottomSolver(m_lmax, m_lbase);
148 m_op.setToZero(m_dphi);
149 m_mg->computeAMRResidual(m_r0, m_dphi, a_rhs, m_lmax, m_lbase,
false,
false);
151 const Real zeroResid = m_op.norm(m_r0, 2);
152 const Real residualScale = (zeroResid > 0.0) ? zeroResid : 1.0;
157 m_mg->computeAMRResidual(m_r0, a_phi, a_rhs, m_lmax, m_lbase,
false,
false);
159 const Real rNorm0 = m_op.norm(m_r0, 2);
161 bool converged =
false;
163 Real residualNorm = rNorm0;
167 const int restart = std::max(1, a_settings.
restart);
169 if (!m_gmres.isDefined() || m_gmres.m_restart != restart) {
170 m_gmres.m_restart = restart;
171 m_gmres.define(&m_op, a_rhs);
174 m_gmres.m_eps = a_settings.
eps;
175 m_gmres.m_maxIter = a_settings.
maxIter;
176 m_gmres.m_verbosity = a_settings.
verbosity;
177 m_gmres.m_residualScale = residualScale;
179 converged = m_gmres.solve(m_dphi, m_r0);
180 exitStatus = m_gmres.m_exitStatus;
181 residualNorm = m_gmres.m_residualNorm;
182 m_lastKrylovIters = m_gmres.m_iterations;
187 if (!m_bicg.isDefined()) {
188 m_bicg.define(&m_op, a_rhs);
191 m_bicg.m_eps = a_settings.
eps;
192 m_bicg.m_maxIter = a_settings.
maxIter;
193 m_bicg.m_verbosity = a_settings.
verbosity;
194 m_bicg.m_residualScale = residualScale;
196 converged = m_bicg.solve(m_dphi, m_r0);
197 exitStatus = m_bicg.m_exitStatus;
198 residualNorm = m_bicg.m_residualNorm;
199 m_lastKrylovIters = m_bicg.m_iterations;
204 MayDay::Error(
"EllipticSolverChain::KrylovSolver::solve - SolverType must be GMRES or BiCGStab");
215 const Real relRes = residualNorm / residualScale;
217 pout() <<
"EllipticSolverChain - " <<
solverTypeName(a_type) << (converged ?
" converged" :
" did NOT converge")
218 <<
" (rel.res = " << relRes <<
", |r| = " << residualNorm <<
", |r_zero| = " << zeroResid
219 <<
", iters = " << m_lastKrylovIters <<
", status = " << exitStatus <<
")" << endl;
223 m_op.incr(a_phi, m_dphi, 1.0);
230#include <CD_NamespaceFooter.H>
Declaration of outer Krylov solves (GMRES/BiCGStab) preconditioned by an AMR-multigrid cycle.
bool keepOrRestore(Vec &a_phi, const Vec &a_rhs)
Warm-start rule applied between fallback attempts.
Definition CD_EllipticSolverChainImplem.H:76
bool solve(Vec &a_phi, const Vec &a_rhs, const bool a_zeroPhi, const SolverType a_type, const Settings &a_settings)
Solve L(phi) = rhs with the chosen outer Krylov method preconditioned by the multigrid cycle.
Definition CD_EllipticSolverChainImplem.H:119
~KrylovSolver() noexcept
Destructor. Frees the persistent work vectors and custom solvers.
Definition CD_EllipticSolverChainImplem.H:30
void snapshotGuess(Vec &a_phi, const Vec &a_rhs)
Snapshot the chain's starting guess and its residual for the fallback warm-start rule.
Definition CD_EllipticSolverChainImplem.H:62
Vector< LevelData< T > * > Vec
Multilevel data type.
Definition CD_EllipticSolverChain.H:317
void define(AMRMultiGrid< LevelData< T > > *a_mg, const Vector< RefCountedPtr< LevelData< BaseFab< bool > > > > &a_validCells, const Vector< Real > &a_dx, const int a_lbase, const int a_lmax, const int a_numVCycles)
Define the multigrid-preconditioner adapter and reset the persistent work. Call once per regrid.
Definition CD_EllipticSolverChainImplem.H:95
void allocateWork(const Vec &a_template)
Lazily allocate the persistent residual-correction vectors r0/dphi from a template hierarchy.
Definition CD_EllipticSolverChainImplem.H:52
void freeWork()
Free the persistent work vectors and undefine the custom solvers.
Definition CD_EllipticSolverChainImplem.H:37
Support code for using an AMR-multigrid cycle as a preconditioner for an outer Krylov solver.
Definition CD_EllipticSolverChain.H:37
std::string solverTypeName(const SolverType a_type)
Human-readable name for a solver type, for diagnostic output.
Definition CD_EllipticSolverChain.H:283
SolverType
Top-level solve method.
Definition CD_EllipticSolverChain.H:43
@ BiCGStab
BiCGStab preconditioned by the multigrid cycle.
@ GMRES
GMRES preconditioned by the multigrid cycle.
Outer-Krylov configuration. Defaults reproduce stand-alone multigrid (solvers == {GMG}).
Definition CD_EllipticSolverChain.H:64
Real eps
Relative residual tolerance.
Definition CD_EllipticSolverChain.H:74
int restart
GMRES restart length (unused for BiCGStab).
Definition CD_EllipticSolverChain.H:84
int maxIter
Maximum outer iterations.
Definition CD_EllipticSolverChain.H:79
int verbosity
Outer Krylov verbosity.
Definition CD_EllipticSolverChain.H:95