76 "Newton solver with GMRES-based hook step.");
88 pSession->LoadParameter(
"TrustRegionRhoAccept",
m_rhoAccept, 1.0e-1);
89 pSession->LoadParameter(
"TrustRegionRhoShrink",
m_rhoShrink, 2.5e-1);
90 pSession->LoadParameter(
"TrustRegionRhoGrow",
m_rhoGrow, 7.5e-1);
91 pSession->LoadParameter(
"TrustRegionShrinkFactor",
m_shrinkFactor, 0.5);
92 pSession->LoadParameter(
"TrustRegionGrowFactor",
m_growFactor, 2.0);
95 pSession->LoadParameter(
"MaxTrustRegionGrowthSteps",
97 pSession->LoadParameter(
"TrustRegionMaxFallbackResidualGrowth",
116 auto gmres = std::dynamic_pointer_cast<NekLinSysIterGMRES>(
m_linsol);
117 ASSERTL0(gmres,
"NewtonHookStep requires LinSysIterSolver=GMRES.");
118 gmres->EnableHookStepExport(
true);
137 std::vector<std::vector<NekDouble>>
A, std::vector<NekDouble> b)
const
139 int n =
static_cast<int>(b.size());
141 for (
int k = 0; k < n; ++k)
145 for (
int i = k + 1; i < n; ++i)
147 if (std::abs(
A[i][k]) > amax)
149 amax = std::abs(
A[i][k]);
154 ASSERTL0(amax > 1.0e-14,
"Hook-step dense solve breakdown.");
158 std::swap(
A[piv],
A[k]);
159 std::swap(b[piv], b[k]);
163 for (
int j = k; j < n; ++j)
169 for (
int i = k + 1; i < n; ++i)
172 for (
int j = k; j < n; ++j)
174 A[i][j] -= fac *
A[k][j];
180 std::vector<NekDouble> x(n, 0.0);
181 for (
int i = n - 1; i >= 0; --i)
184 for (
int j = i + 1; j < n; ++j)
186 x[i] -=
A[i][j] * x[j];
203 std::vector<std::vector<NekDouble>> H(m + 1,
204 std::vector<NekDouble>(m, 0.0));
206 for (
int j = 0; j < m; ++j)
208 for (
int i = 0; i < m + 1; ++i)
210 H[i][j] = data.
H[j][i];
214 std::vector<std::vector<NekDouble>> AtA(m, std::vector<NekDouble>(m, 0.0));
215 std::vector<NekDouble> rhs(m, 0.0);
217 for (
int i = 0; i < m; ++i)
219 rhs[i] = H[0][i] * data.
beta;
220 for (
int j = 0; j < m; ++j)
223 for (
int k = 0; k < m + 1; ++k)
225 sum += H[k][i] * H[k][j];
232 std::vector<std::vector<NekDouble>>
A = AtA;
233 for (
int i = 0; i < m; ++i)
240 auto normY = [&](
const std::vector<NekDouble> &yv) {
249 std::vector<NekDouble> y0 = computeY(0.0);
250 if (normY(y0) <= Delta)
252 for (
int i = 0; i < m; ++i)
262 while (normY(computeY(muR)) > Delta)
265 ASSERTL0(muR < 1.0e20,
"Unable to bracket hook-step multiplier.");
269 for (
int it = 0; it < 40; ++it)
272 std::vector<NekDouble> ym = computeY(mu);
273 if (normY(ym) > Delta)
283 std::vector<NekDouble> yv = computeY(muR);
284 for (
int i = 0; i < m; ++i)
302 for (
int i = 0; i < data.
nswp; ++i)
309 auto gmres = std::dynamic_pointer_cast<NekLinSysIterGMRES>(
m_linsol);
310 if (gmres && gmres->UsingRightPrecon())
313 gmres->ApplyRightPrecon(delta, tmp);
334 for (
int j = 0; j < m; ++j)
336 for (
int i = 0; i < m + 1; ++i)
338 rred[i] -= data.
H[j][i] * y[j];
343 for (
int i = 0; i < m + 1; ++i)
345 nrm2 += rred[i] * rred[i];
351 const int ntotal,
const NekDouble oldResNorm)
353 auto gmres = std::dynamic_pointer_cast<NekLinSysIterGMRES>(
m_linsol);
354 ASSERTL0(gmres,
"NewtonHookStep requires GMRES.");
357 "Initial NewtonHookStep implementation does not support "
360 const auto &data = gmres->GetHookData();
361 ASSERTL0(data.valid,
"GMRES hook-step data not available.");
364 cout <<
" Attempting to apply Newton update with Hookstep "
365 <<
" Trust radius = " << trustRadiusTrial
366 <<
" GMRES beta = " << data.beta <<
" oldResNorm= " << oldResNorm
369 bool haveAcceptedCandidate =
false;
370 bool hadShrink =
false;
375 bool bestBoundaryStep =
false;
402 NekDouble ared = oldResNorm - newResNorm;
403 NekDouble pred = oldResNorm - predResNorm;
405 NekDouble rho = (pred > 1.0e-14 * oldResNorm) ? ared / pred : -1.0;
408 bool boundaryStep = std::abs(yNorm - trustRadiusTrial) <=
409 1.0e-2 * (trustRadiusTrial + 1.0e-14);
411 cout <<
" HookStep TrustRadius trial = " << trustRadiusTrial
412 <<
" yNorm = " << yNorm <<
" oldRes = " << oldResNorm
413 <<
" newRes = " << newResNorm <<
" predRes = " << predResNorm
414 <<
" ared = " << ared <<
" pred = " << pred <<
" rho = " << rho
421 cout <<
"Accepting HookStep with rho = " << rho <<
" > "
427 bestResNorm = newResNorm;
429 bestTrustRadius = trustRadiusTrial;
430 bestBoundaryStep = boundaryStep;
431 haveAcceptedCandidate =
true;
441 cout <<
" HookStep shrink trial radius to " << trustRadiusTrial
442 <<
" because current trial was not acceptable." << endl;
446 WARNINGL0(
false,
"Hook-step globalization failed at TrustRadiusMin "
447 "without meaningful residual decrease.");
453 cout <<
"HookStep finished the shrink phase with: "
454 <<
" hadShrink=" << hadShrink <<
" bestRho=" << bestRho
455 <<
" bestBoundaryStep=" << bestBoundaryStep << endl;
460 if (!haveAcceptedCandidate)
479 cout <<
" No acceptable hook-step found."
481 <<
" residual = " << fallbackResNorm << endl;
483 if (!std::isfinite(fallbackResNorm) ||
487 "Fallback hook-step caused non-finite or excessive "
506 if (!hadShrink && bestRho >
m_rhoGrow && bestBoundaryStep)
508 cout <<
" HookStep entering exploration phase from TrustRadius = "
509 << bestTrustRadius <<
" because bestRho = " << bestRho
510 <<
" > m_rhoGrow = " <<
m_rhoGrow << endl;
512 NekDouble exploreRadius = bestTrustRadius;
519 if (enlargedRadius <= exploreRadius + 1.0e-16)
543 NekDouble ared = oldResNorm - newResNorm;
544 NekDouble pred = oldResNorm - predResNorm;
545 NekDouble rho = (pred > 1.0e-14 * oldResNorm) ? ared / pred : -1.0;
548 bool boundaryStep = std::abs(yNorm - enlargedRadius) <=
549 1.0e-2 * (enlargedRadius + 1.0e-14);
551 cout <<
" HookStep exploration trial = " << enlargedRadius
552 <<
" yNorm = " << yNorm <<
" oldRes = " << oldResNorm
553 <<
" newRes = " << newResNorm <<
" predRes = " << predResNorm
554 <<
" ared = " << ared <<
" pred = " << pred <<
" rho = " << rho
557 bool meaningfulDecrease =
563 cout <<
" Exploration step rejected, stop growing radius."
569 if (newResNorm < bestResNorm)
571 cout <<
" Exploration improved residual from " << bestResNorm
572 <<
" to " << newResNorm <<
", keeping enlarged step."
578 bestResNorm = newResNorm;
580 bestTrustRadius = enlargedRadius;
581 bestBoundaryStep = boundaryStep;
583 exploreRadius = enlargedRadius;
585 if (!(bestRho >
m_rhoGrow && bestBoundaryStep))
587 cout <<
" Exploration stopping because enlarged step is "
588 <<
"no longer a strong boundary-limited candidate."
595 cout <<
" Exploration did not improve residual (best = "
596 << bestResNorm <<
", trial = " << newResNorm
597 <<
"), stopping." << endl;
614 cout <<
" Trust Radius shrink because rho < m_rhoShrink = "
620 else if (bestRho >
m_rhoGrow && bestBoundaryStep)
622 cout <<
" Trust Radius grow because rho > m_rhoGrow = " <<
m_rhoGrow
635 NekDouble ared = oldResNorm - newResNorm;
638 return ared > thresh;
#define ASSERTL0(condition, msg)
#define WARNINGL0(condition, msg)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Array< OneD, NekDouble > m_Residual
Array< OneD, NekDouble > m_Solution
NekLinSysIterSharedPtr m_linsol
NekDouble CalcL2Norm(const int ntotal, const Array< OneD, const NekDouble > &x) const
bool HasMeaningfulDecrease(const NekDouble oldResNorm, const NekDouble newResNorm) const
Array< OneD, NekDouble > m_residualTrial
Array< OneD, NekDouble > m_residualBest
bool v_ApplyNewtonUpdate(const int ntotal, const NekDouble oldResNorm) override
Array< OneD, NekDouble > m_solutionBest
Array< OneD, NekDouble > SolveReducedHookStep(const NekLinSysIterGMRES::GMRESHookData &data, const NekDouble Delta) const
NekDouble m_trustRadiusInit
std::vector< NekDouble > SolveDenseLinearSystem(std::vector< std::vector< NekDouble > > A, std::vector< NekDouble > b) const
Array< OneD, NekDouble > m_solutionTrial
Array< OneD, NekDouble > m_deltaTrial
NekDouble m_maxFallbackResidualGrowth
void BuildHookStepFromKrylovBasis(const NekLinSysIterGMRES::GMRESHookData &data, const Array< OneD, const NekDouble > &y, Array< OneD, NekDouble > &delta)
NekDouble m_meaningfulAredAbs
int m_maxTrustRegionSteps
static NekNonlinSysIterSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const LibUtilities::CommSharedPtr &vComm, const int nDimen, const NekSysKey &pKey)
NekDouble m_trustRadiusMin
NekDouble m_meaningfulAredRel
int m_maxTrustRegionGrowthSteps
NekNonlinSysIterNewtonHookStep(const LibUtilities::SessionReaderSharedPtr &pSession, const LibUtilities::CommSharedPtr &vComm, const int nDimen, const NekSysKey &pKey)
static std::string className
NekDouble ComputeReducedResidualNorm(const NekLinSysIterGMRES::GMRESHookData &data, const Array< OneD, const NekDouble > &y) const
NekDouble m_trustRadiusMax
void v_InitObject() override
void v_InitObject() override
bool m_haveUpdatedResidual
LibUtilities::CommSharedPtr m_rowComm
NekSysOperators m_operator
void DoNekSysResEval(InArrayType &inarray, OutArrayType &outarray, const bool &flag=false) const
NekNonlinSysIterFactory & GetNekNonlinSysIterFactory()
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Svtvp (scalar times vector plus vector): z = alpha*x + y.
T Dot(int n, const T *w, const T *x)
dot product
void Zero(int n, T *x, const int incx)
Zero vector.
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
scalarT< T > sqrt(scalarT< T > in)
Data exported from GMRES for use by the Newton hook-step solver. The data stored here correspond to t...
NekDouble beta
Initial residual norm beta used in || beta e_1 - H y ||_2.
Array< OneD, Array< OneD, NekDouble > > V
Arnoldi basis vectors V_0,...,V_m; contains nswp + 1 vectors of length nGlobal.
Array< OneD, Array< OneD, NekDouble > > H
Arnoldi Hessenberg matrix stored by columns: H[col][row]. H size is (nswp + 1) x nswp.
int nGlobal
Dimension of the system; length of each Krylov vector.
int nDir
Offset to the non-Dirichlet part of the vector; active size is nGlobal - nDir.
int nswp
Current Krylov subspace dimension, number of done Arnoldi sweeps.