xref: /petsc/src/snes/linesearch/impls/nleqerr/linesearchnleqerr.c (revision 57508ece14a6b1339c0bbf016ecd72f673a062b0)
1af0996ceSBarry Smith #include <petsc/private/linesearchimpl.h> /*I  "petscsnes.h"  I*/
2af0996ceSBarry Smith #include <petsc/private/snesimpl.h>
3d4c6564cSPatrick Farrell 
4d4c6564cSPatrick Farrell typedef struct {
5d4c6564cSPatrick Farrell   PetscReal norm_delta_x_prev;     /* norm of previous update */
6d4c6564cSPatrick Farrell   PetscReal norm_bar_delta_x_prev; /* norm of previous bar update */
7d4c6564cSPatrick Farrell   PetscReal mu_curr;               /* current local Lipschitz estimate */
8d4c6564cSPatrick Farrell   PetscReal lambda_prev;           /* previous step length: for some reason SNESLineSearchGetLambda returns 1 instead of the previous step length */
9d4c6564cSPatrick Farrell } SNESLineSearch_NLEQERR;
10d4c6564cSPatrick Farrell 
1157a6bf86SPatrick Farrell static PetscBool  NLEQERR_cited      = PETSC_FALSE;
1257a6bf86SPatrick Farrell static const char NLEQERR_citation[] = "@book{deuflhard2011,\n"
13d4c6564cSPatrick Farrell                                        "  title = {Newton Methods for Nonlinear Problems},\n"
14d4c6564cSPatrick Farrell                                        "  author = {Peter Deuflhard},\n"
15d4c6564cSPatrick Farrell                                        "  volume = 35,\n"
16d4c6564cSPatrick Farrell                                        "  year = 2011,\n"
17d4c6564cSPatrick Farrell                                        "  isbn = {978-3-642-23898-7},\n"
18d4c6564cSPatrick Farrell                                        "  doi  = {10.1007/978-3-642-23899-4},\n"
19d4c6564cSPatrick Farrell                                        "  publisher = {Springer-Verlag},\n"
20d4c6564cSPatrick Farrell                                        "  address = {Berlin, Heidelberg}\n}\n";
21d4c6564cSPatrick Farrell 
22d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESLineSearchReset_NLEQERR(SNESLineSearch linesearch)
23d71ae5a4SJacob Faibussowitsch {
2470d8d27cSBarry Smith   SNESLineSearch_NLEQERR *nleqerr = (SNESLineSearch_NLEQERR *)linesearch->data;
257cbffc34SPatrick Farrell 
2670d8d27cSBarry Smith   PetscFunctionBegin;
277cbffc34SPatrick Farrell   nleqerr->mu_curr               = 0.0;
287cbffc34SPatrick Farrell   nleqerr->norm_delta_x_prev     = -1.0;
297cbffc34SPatrick Farrell   nleqerr->norm_bar_delta_x_prev = -1.0;
303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
317cbffc34SPatrick Farrell }
327cbffc34SPatrick Farrell 
33d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESLineSearchApply_NLEQERR(SNESLineSearch linesearch)
34d71ae5a4SJacob Faibussowitsch {
35d4c6564cSPatrick Farrell   PetscBool               changed_y, changed_w;
36d4c6564cSPatrick Farrell   Vec                     X, F, Y, W, G;
37d4c6564cSPatrick Farrell   SNES                    snes;
38d4c6564cSPatrick Farrell   PetscReal               fnorm, xnorm, ynorm, gnorm, wnorm;
39d4c6564cSPatrick Farrell   PetscReal               lambda, minlambda, stol;
40d4c6564cSPatrick Farrell   PetscViewer             monitor;
417cbffc34SPatrick Farrell   PetscInt                max_its, count, snes_iteration;
42d4c6564cSPatrick Farrell   PetscReal               theta, mudash, lambdadash;
4370d8d27cSBarry Smith   SNESLineSearch_NLEQERR *nleqerr = (SNESLineSearch_NLEQERR *)linesearch->data;
44d4c6564cSPatrick Farrell   KSPConvergedReason      kspreason;
45d4c6564cSPatrick Farrell 
46d4c6564cSPatrick Farrell   PetscFunctionBegin;
479566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(NLEQERR_citation, &NLEQERR_cited));
48d4c6564cSPatrick Farrell 
499566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, &G));
509566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm));
519566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetLambda(linesearch, &lambda));
529566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
539566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetDefaultMonitor(linesearch, &monitor));
549566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetTolerances(linesearch, &minlambda, NULL, NULL, NULL, NULL, &max_its));
559566063dSJacob Faibussowitsch   PetscCall(SNESGetTolerances(snes, NULL, NULL, &stol, NULL, NULL));
56d4c6564cSPatrick Farrell 
577cbffc34SPatrick Farrell   /* reset the state of the Lipschitz estimates */
589566063dSJacob Faibussowitsch   PetscCall(SNESGetIterationNumber(snes, &snes_iteration));
5948a46eb9SPierre Jolivet   if (!snes_iteration) PetscCall(SNESLineSearchReset_NLEQERR(linesearch));
607cbffc34SPatrick Farrell 
61d4c6564cSPatrick Farrell   /* precheck */
629566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchPreCheck(linesearch, X, Y, &changed_y));
639566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED));
64d4c6564cSPatrick Farrell 
659566063dSJacob Faibussowitsch   PetscCall(VecNormBegin(Y, NORM_2, &ynorm));
669566063dSJacob Faibussowitsch   PetscCall(VecNormBegin(X, NORM_2, &xnorm));
679566063dSJacob Faibussowitsch   PetscCall(VecNormEnd(Y, NORM_2, &ynorm));
689566063dSJacob Faibussowitsch   PetscCall(VecNormEnd(X, NORM_2, &xnorm));
69d4c6564cSPatrick Farrell 
7070d8d27cSBarry Smith   /* Note: Y is *minus* the Newton step. For whatever reason PETSc doesn't solve with the minus on  the RHS. */
71d4c6564cSPatrick Farrell 
72d4c6564cSPatrick Farrell   if (ynorm == 0.0) {
73d4c6564cSPatrick Farrell     if (monitor) {
749566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
759566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: Initial direction and size is 0\n"));
769566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
77d4c6564cSPatrick Farrell     }
789566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, W));
799566063dSJacob Faibussowitsch     PetscCall(VecCopy(F, G));
809566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetNorms(linesearch, xnorm, fnorm, ynorm));
819566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT));
823ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
83d4c6564cSPatrick Farrell   }
84d4c6564cSPatrick Farrell 
85d4c6564cSPatrick Farrell   /* At this point, we've solved the Newton system for delta_x, and we assume that
86d4c6564cSPatrick Farrell      its norm is greater than the solution tolerance (otherwise we wouldn't be in
87d4c6564cSPatrick Farrell      here). So let's go ahead and estimate the Lipschitz constant.
88d4c6564cSPatrick Farrell 
89d4c6564cSPatrick Farrell      W contains bar_delta_x_prev at this point. */
90d4c6564cSPatrick Farrell 
91d4c6564cSPatrick Farrell   if (monitor) {
929566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: norm of Newton step: %14.12e\n", (double)ynorm));
949566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
95d4c6564cSPatrick Farrell   }
96d4c6564cSPatrick Farrell 
97d4c6564cSPatrick Farrell   /* this needs information from a previous iteration, so can't do it on the first one */
98d4c6564cSPatrick Farrell   if (nleqerr->norm_delta_x_prev > 0 && nleqerr->norm_bar_delta_x_prev > 0) {
999566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(G, +1.0, Y, W)); /* bar_delta_x - delta_x; +1 because Y is -delta_x */
1009566063dSJacob Faibussowitsch     PetscCall(VecNormBegin(G, NORM_2, &gnorm));
1019566063dSJacob Faibussowitsch     PetscCall(VecNormEnd(G, NORM_2, &gnorm));
102d4c6564cSPatrick Farrell 
103d4c6564cSPatrick Farrell     nleqerr->mu_curr = nleqerr->lambda_prev * (nleqerr->norm_delta_x_prev * nleqerr->norm_bar_delta_x_prev) / (gnorm * ynorm);
104d4c6564cSPatrick Farrell     lambda           = PetscMin(1.0, nleqerr->mu_curr);
105d4c6564cSPatrick Farrell 
106d4c6564cSPatrick Farrell     if (monitor) {
1079566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
1089566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: Lipschitz estimate: %14.12e; lambda: %14.12e\n", (double)nleqerr->mu_curr, (double)lambda));
1099566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
110d4c6564cSPatrick Farrell     }
111bf8ddb9bSPatrick Farrell   } else {
112d4c6564cSPatrick Farrell     lambda = linesearch->damping;
113d4c6564cSPatrick Farrell   }
114d4c6564cSPatrick Farrell 
115d4c6564cSPatrick Farrell   /* The main while loop of the algorithm.
116d4c6564cSPatrick Farrell      At the end of this while loop, G should have the accepted new X in it. */
117d4c6564cSPatrick Farrell 
118d4c6564cSPatrick Farrell   count = 0;
11959ea5d13SPatrick Farrell   while (PETSC_TRUE) {
120d4c6564cSPatrick Farrell     if (monitor) {
1219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
12263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: entering iteration with lambda: %14.12e\n", (double)lambda));
1239566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
124d4c6564cSPatrick Farrell     }
125d4c6564cSPatrick Farrell 
126d4c6564cSPatrick Farrell     /* Check that we haven't performed too many iterations */
127d4c6564cSPatrick Farrell     count += 1;
128bf8ddb9bSPatrick Farrell     if (count >= max_its) {
129d4c6564cSPatrick Farrell       if (monitor) {
1309566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
1319566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: maximum iterations reached\n"));
1329566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
133d4c6564cSPatrick Farrell       }
1349566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT));
1353ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
136d4c6564cSPatrick Farrell     }
137d4c6564cSPatrick Farrell 
138d4c6564cSPatrick Farrell     /* Now comes the Regularity Test. */
139d4c6564cSPatrick Farrell     if (lambda <= minlambda) {
140d4c6564cSPatrick Farrell       /* This isn't what is suggested by Deuflhard, but it works better in my experience */
141d4c6564cSPatrick Farrell       if (monitor) {
1429566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
1439566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: lambda has reached lambdamin, taking full Newton step\n"));
1449566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
145d4c6564cSPatrick Farrell       }
146d4c6564cSPatrick Farrell       lambda = 1.0;
1479566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(G, -lambda, Y, X));
1487cbffc34SPatrick Farrell 
1497cbffc34SPatrick Farrell       /* and clean up the state for next time */
1509566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchReset_NLEQERR(linesearch));
15170d8d27cSBarry Smith       /*
15270d8d27cSBarry Smith          The clang static analyzer detected a problem here; once the loop is broken the values
15370d8d27cSBarry Smith          nleqerr->norm_delta_x_prev     = ynorm;
15470d8d27cSBarry Smith          nleqerr->norm_bar_delta_x_prev = wnorm;
15570d8d27cSBarry Smith          are set, but wnorm has not even been computed.
15670d8d27cSBarry Smith          I don't know if this is the correct fix but by setting ynorm and wnorm to -1.0 at
15770d8d27cSBarry Smith          least the linesearch object is kept in the state set by the SNESLineSearchReset_NLEQERR() call above
15870d8d27cSBarry Smith       */
15970d8d27cSBarry Smith       ynorm = wnorm = -1.0;
160d4c6564cSPatrick Farrell       break;
161d4c6564cSPatrick Farrell     }
162d4c6564cSPatrick Farrell 
163d4c6564cSPatrick Farrell     /* Compute new trial iterate */
1649566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(W, -lambda, Y, X));
1659566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, W, G));
166d4c6564cSPatrick Farrell 
167d4c6564cSPatrick Farrell     /* Solve linear system for bar_delta_x_curr: old Jacobian, new RHS. Note absence of minus sign, compared to Deuflhard, in keeping with PETSc convention */
1689566063dSJacob Faibussowitsch     PetscCall(KSPSolve(snes->ksp, G, W));
1699566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason(snes->ksp, &kspreason));
1709d3446b2SPierre Jolivet     if (kspreason < 0) PetscCall(PetscInfo(snes, "Solution for \\bar{delta x}^{k+1} failed.\n"));
171d4c6564cSPatrick Farrell 
172d4c6564cSPatrick Farrell     /* W now contains -bar_delta_x_curr. */
173d4c6564cSPatrick Farrell 
1749566063dSJacob Faibussowitsch     PetscCall(VecNorm(W, NORM_2, &wnorm));
175d4c6564cSPatrick Farrell     if (monitor) {
1769566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
1779566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: norm of simplified Newton update: %14.12e\n", (double)wnorm));
1789566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
179d4c6564cSPatrick Farrell     }
180d4c6564cSPatrick Farrell 
181d4c6564cSPatrick Farrell     /* compute the monitoring quantities theta and mudash. */
182d4c6564cSPatrick Farrell 
183d4c6564cSPatrick Farrell     theta = wnorm / ynorm;
184d4c6564cSPatrick Farrell 
1859566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(G, -(1.0 - lambda), Y, W));
1869566063dSJacob Faibussowitsch     PetscCall(VecNorm(G, NORM_2, &gnorm));
187d4c6564cSPatrick Farrell 
188d4c6564cSPatrick Farrell     mudash = (0.5 * ynorm * lambda * lambda) / gnorm;
189d4c6564cSPatrick Farrell 
190d4c6564cSPatrick Farrell     /* Check for termination of the linesearch */
191d4c6564cSPatrick Farrell     if (theta >= 1.0) {
192d4c6564cSPatrick Farrell       /* need to go around again with smaller lambda */
193d4c6564cSPatrick Farrell       if (monitor) {
1949566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
1959566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(monitor, "    Line search: monotonicity check failed, ratio: %14.12e\n", (double)theta));
1969566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
197d4c6564cSPatrick Farrell       }
198d4c6564cSPatrick Farrell       lambda = PetscMin(mudash, 0.5 * lambda);
199d4c6564cSPatrick Farrell       lambda = PetscMax(lambda, minlambda);
200d4c6564cSPatrick Farrell       /* continue through the loop, i.e. go back to regularity test */
201bf8ddb9bSPatrick Farrell     } else {
202d4c6564cSPatrick Farrell       /* linesearch terminated */
203d4c6564cSPatrick Farrell       lambdadash = PetscMin(1.0, mudash);
204d4c6564cSPatrick Farrell 
205d4c6564cSPatrick Farrell       if (lambdadash == 1.0 && lambda == 1.0 && wnorm <= stol) {
206d4c6564cSPatrick Farrell         /* store the updated state, X - Y - W, in G:
207d4c6564cSPatrick Farrell            I need to keep W for the next linesearch */
208ef46b1a6SStefano Zampini         PetscCall(VecWAXPY(G, -1.0, Y, X));
2099566063dSJacob Faibussowitsch         PetscCall(VecAXPY(G, -1.0, W));
210d4c6564cSPatrick Farrell         break;
211d4c6564cSPatrick Farrell       }
212d4c6564cSPatrick Farrell 
213d4c6564cSPatrick Farrell       /* Deuflhard suggests to add the following:
214d4c6564cSPatrick Farrell       else if (lambdadash >= 4.0 * lambda) {
215d4c6564cSPatrick Farrell         lambda = lambdadash;
216d4c6564cSPatrick Farrell       }
217d4c6564cSPatrick Farrell       to continue through the loop, i.e. go back to regularity test.
218d4c6564cSPatrick Farrell       I deliberately exclude this, as I have practical experience of this
219d4c6564cSPatrick Farrell       getting stuck in infinite loops (on e.g. an Allen--Cahn problem). */
220d4c6564cSPatrick Farrell 
221d4c6564cSPatrick Farrell       else {
222d4c6564cSPatrick Farrell         /* accept iterate without adding on, i.e. don't use bar_delta_x;
223d4c6564cSPatrick Farrell            again, I need to keep W for the next linesearch */
2249566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(G, -lambda, Y, X));
225d4c6564cSPatrick Farrell         break;
226d4c6564cSPatrick Farrell       }
227d4c6564cSPatrick Farrell     }
228d4c6564cSPatrick Farrell   }
229d4c6564cSPatrick Farrell 
2301baa6e33SBarry Smith   if (linesearch->ops->viproject) PetscCall((*linesearch->ops->viproject)(snes, G));
231d4c6564cSPatrick Farrell 
232d4c6564cSPatrick Farrell   /* W currently contains -bar_delta_u. Scale it so that it contains bar_delta_u. */
2339566063dSJacob Faibussowitsch   PetscCall(VecScale(W, -1.0));
234d4c6564cSPatrick Farrell 
235d4c6564cSPatrick Farrell   /* postcheck */
2369566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchPostCheck(linesearch, X, Y, G, &changed_y, &changed_w));
237d4c6564cSPatrick Farrell   if (changed_y || changed_w) {
2389566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_USER));
2399566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Changing the search direction here doesn't make sense.\n"));
2403ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
241d4c6564cSPatrick Farrell   }
242d4c6564cSPatrick Farrell 
243d4c6564cSPatrick Farrell   /* copy the solution and information from this iteration over */
244d4c6564cSPatrick Farrell   nleqerr->norm_delta_x_prev     = ynorm;
245d4c6564cSPatrick Farrell   nleqerr->norm_bar_delta_x_prev = wnorm;
246d4c6564cSPatrick Farrell   nleqerr->lambda_prev           = lambda;
247d4c6564cSPatrick Farrell 
2489566063dSJacob Faibussowitsch   PetscCall(VecCopy(G, X));
2499566063dSJacob Faibussowitsch   PetscCall(SNESComputeFunction(snes, X, F));
2509566063dSJacob Faibussowitsch   PetscCall(VecNorm(X, NORM_2, &xnorm));
2519566063dSJacob Faibussowitsch   PetscCall(VecNorm(F, NORM_2, &fnorm));
2529566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetLambda(linesearch, lambda));
253*57508eceSPierre Jolivet   PetscCall(SNESLineSearchSetNorms(linesearch, xnorm, fnorm, ynorm < 0 ? PETSC_INFINITY : ynorm));
2543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
255d4c6564cSPatrick Farrell }
256d4c6564cSPatrick Farrell 
25766976f2fSJacob Faibussowitsch static PetscErrorCode SNESLineSearchView_NLEQERR(SNESLineSearch linesearch, PetscViewer viewer)
258d71ae5a4SJacob Faibussowitsch {
259d4c6564cSPatrick Farrell   PetscBool               iascii;
260d4c6564cSPatrick Farrell   SNESLineSearch_NLEQERR *nleqerr;
261d4c6564cSPatrick Farrell 
262d4c6564cSPatrick Farrell   PetscFunctionBegin;
2639566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
264d4c6564cSPatrick Farrell   nleqerr = (SNESLineSearch_NLEQERR *)linesearch->data;
265d4c6564cSPatrick Farrell   if (iascii) {
2669566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  NLEQ-ERR affine-covariant linesearch"));
2679566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  current local Lipschitz estimate omega=%e\n", (double)nleqerr->mu_curr));
268d4c6564cSPatrick Farrell   }
2693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
270d4c6564cSPatrick Farrell }
271d4c6564cSPatrick Farrell 
272d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESLineSearchDestroy_NLEQERR(SNESLineSearch linesearch)
273d71ae5a4SJacob Faibussowitsch {
274d4c6564cSPatrick Farrell   PetscFunctionBegin;
2759566063dSJacob Faibussowitsch   PetscCall(PetscFree(linesearch->data));
2763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
277d4c6564cSPatrick Farrell }
278d4c6564cSPatrick Farrell 
279d4c6564cSPatrick Farrell /*MC
280420bcc1bSBarry Smith    SNESLINESEARCHNLEQERR - Error-oriented affine-covariant globalised Newton algorithm of Deuflhard {cite}`deuflhard2011`
281d4c6564cSPatrick Farrell 
282d4c6564cSPatrick Farrell    This linesearch is intended for Newton-type methods which are affine covariant. Affine covariance
283420bcc1bSBarry Smith    means that Newton's method will give the same iterations for F(x) = 0 and AF(x) = 0 for any nonsingular
284d4c6564cSPatrick Farrell    matrix A. This is a fundamental property; the philosophy of this linesearch is that globalisations
285d4c6564cSPatrick Farrell    of Newton's method should carefully preserve it.
286d4c6564cSPatrick Farrell 
287d4c6564cSPatrick Farrell    Options Database Keys:
288d4c6564cSPatrick Farrell +  -snes_linesearch_damping<1.0> - initial step length
289d4c6564cSPatrick Farrell -  -snes_linesearch_minlambda<1e-12> - minimum step length allowed
290d4c6564cSPatrick Farrell 
291d4c6564cSPatrick Farrell    Level: advanced
292d4c6564cSPatrick Farrell 
293f6dfbefdSBarry Smith    Note:
294f6dfbefdSBarry Smith    Contributed by Patrick Farrell <patrick.farrell@maths.ox.ac.uk>
295f6dfbefdSBarry Smith 
296420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESLineSearch`, `SNES`, `SNESLineSearchCreate()`, `SNESLineSearchSetType()`
297d4c6564cSPatrick Farrell M*/
298d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_NLEQERR(SNESLineSearch linesearch)
299d71ae5a4SJacob Faibussowitsch {
300d4c6564cSPatrick Farrell   SNESLineSearch_NLEQERR *nleqerr;
301d4c6564cSPatrick Farrell 
302d4c6564cSPatrick Farrell   PetscFunctionBegin;
303d4c6564cSPatrick Farrell   linesearch->ops->apply          = SNESLineSearchApply_NLEQERR;
304d4c6564cSPatrick Farrell   linesearch->ops->destroy        = SNESLineSearchDestroy_NLEQERR;
305d4c6564cSPatrick Farrell   linesearch->ops->setfromoptions = NULL;
306d4c6564cSPatrick Farrell   linesearch->ops->reset          = SNESLineSearchReset_NLEQERR;
307d4c6564cSPatrick Farrell   linesearch->ops->view           = SNESLineSearchView_NLEQERR;
308d4c6564cSPatrick Farrell   linesearch->ops->setup          = NULL;
309d4c6564cSPatrick Farrell 
3104dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&nleqerr));
311d4c6564cSPatrick Farrell 
312d4c6564cSPatrick Farrell   linesearch->data    = (void *)nleqerr;
313d4c6564cSPatrick Farrell   linesearch->max_its = 40;
3143ba16761SJacob Faibussowitsch   PetscCall(SNESLineSearchReset_NLEQERR(linesearch));
3153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
316d4c6564cSPatrick Farrell }
317