xref: /petsc/src/snes/linesearch/impls/cp/linesearchcp.c (revision 9566063d113dddea24716c546802770db7481bc0)
1af0996ceSBarry Smith #include <petsc/private/linesearchimpl.h>
26a388c36SPeter Brune #include <petscsnes.h>
3bbd5d0b3SPeter Brune 
4f1c6b773SPeter Brune static PetscErrorCode SNESLineSearchApply_CP(SNESLineSearch linesearch)
5bbd5d0b3SPeter Brune {
6422a814eSBarry Smith   PetscBool      changed_y, changed_w;
76a388c36SPeter Brune   Vec            X, Y, F, W;
86a388c36SPeter Brune   SNES           snes;
9516fe3c3SPeter Brune   PetscReal      xnorm, ynorm, gnorm, steptol, atol, rtol, ltol, maxstep;
10bbd5d0b3SPeter Brune   PetscReal      lambda, lambda_old, lambda_update, delLambda;
11b8ac21a2SPeter Brune   PetscScalar    fty, fty_init, fty_old, fty_mid1, fty_mid2, s;
126a388c36SPeter Brune   PetscInt       i, max_its;
136a388c36SPeter Brune   PetscViewer    monitor;
14bbd5d0b3SPeter Brune 
15bbd5d0b3SPeter Brune   PetscFunctionBegin;
16*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, NULL));
17*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm));
18*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
19*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetLambda(linesearch, &lambda));
20*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetTolerances(linesearch, &steptol, &maxstep, &rtol, &atol, &ltol, &max_its));
21*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED));
22*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetDefaultMonitor(linesearch, &monitor));
236a388c36SPeter Brune 
24bbd5d0b3SPeter Brune   /* precheck */
25*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchPreCheck(linesearch,X,Y,&changed_y));
26bbd5d0b3SPeter Brune   lambda_old = 0.0;
2762893cf2SPeter Brune 
28*9566063dSJacob Faibussowitsch   PetscCall(VecDot(F,Y,&fty_old));
2996b7d5c2SJed Brown   if (PetscAbsScalar(fty_old) < atol * ynorm) {
309e0a2ef9SBarry Smith     if (monitor) {
31*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel));
32*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(monitor,"    Line search terminated at initial point because dot(F,Y) = %g < atol*||y|| = %g\n",(double)PetscAbsScalar(fty_old), (double)atol*ynorm));
33*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel));
349e0a2ef9SBarry Smith     }
35*9566063dSJacob Faibussowitsch     PetscCall(SNESSetConvergedReason(linesearch->snes,SNES_CONVERGED_FNORM_ABS));
369e0a2ef9SBarry Smith     PetscFunctionReturn(0);
379e0a2ef9SBarry Smith   }
389e0a2ef9SBarry Smith 
3962893cf2SPeter Brune   fty_init = fty_old;
40c0b2db79SJed Brown 
41c0b2db79SJed Brown   for (i = 0; i < max_its; i++) {
42bbd5d0b3SPeter Brune     /* compute the norm at lambda */
43*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, W));
44*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(W, -lambda, Y));
459bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
46*9566063dSJacob Faibussowitsch       PetscCall((*linesearch->ops->viproject)(snes, W));
479bd66eb0SPeter Brune     }
48*9566063dSJacob Faibussowitsch     PetscCall((*linesearch->ops->snesfunc)(snes,W,F));
49*9566063dSJacob Faibussowitsch     PetscCall(VecDot(F,Y,&fty));
50bbd5d0b3SPeter Brune 
51bbd5d0b3SPeter Brune     delLambda = lambda - lambda_old;
52b8ac21a2SPeter Brune 
53b8ac21a2SPeter Brune     /* check for convergence */
54b8ac21a2SPeter Brune     if (PetscAbsReal(delLambda) < steptol*lambda) break;
55b8ac21a2SPeter Brune     if (PetscAbsScalar(fty) / PetscAbsScalar(fty_init) < rtol) break;
5696b7d5c2SJed Brown     if (PetscAbsScalar(fty) < atol * ynorm && i > 0) break;
576a388c36SPeter Brune     if (monitor) {
58*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel));
59*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(monitor,"    Line search: lambdas = [%g, %g], ftys = [%g, %g]\n",(double)lambda, (double)lambda_old, (double)PetscRealPart(fty), (double)PetscRealPart(fty_old)));
60*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel));
61bbd5d0b3SPeter Brune     }
62bbd5d0b3SPeter Brune 
63bbd5d0b3SPeter Brune     /* compute the search direction */
64b000cd8dSPeter Brune     if (linesearch->order == SNES_LINESEARCH_ORDER_LINEAR) {
65b8ac21a2SPeter Brune       s = (fty - fty_old) / delLambda;
66b000cd8dSPeter Brune     } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
67*9566063dSJacob Faibussowitsch       PetscCall(VecCopy(X, W));
68*9566063dSJacob Faibussowitsch       PetscCall(VecAXPY(W, -0.5*(lambda + lambda_old), Y));
69b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
70*9566063dSJacob Faibussowitsch         PetscCall((*linesearch->ops->viproject)(snes, W));
71b8ac21a2SPeter Brune       }
72*9566063dSJacob Faibussowitsch       PetscCall((*linesearch->ops->snesfunc)(snes,W,F));
73*9566063dSJacob Faibussowitsch       PetscCall(VecDot(F, Y, &fty_mid1));
74b8ac21a2SPeter Brune       s    = (3.*fty - 4.*fty_mid1 + fty_old) / delLambda;
75b8ac21a2SPeter Brune     } else {
76*9566063dSJacob Faibussowitsch       PetscCall(VecCopy(X, W));
77*9566063dSJacob Faibussowitsch       PetscCall(VecAXPY(W, -0.5*(lambda + lambda_old), Y));
78b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
79*9566063dSJacob Faibussowitsch         PetscCall((*linesearch->ops->viproject)(snes, W));
80b8ac21a2SPeter Brune       }
81*9566063dSJacob Faibussowitsch       PetscCall((*linesearch->ops->snesfunc)(snes,W,F));
82*9566063dSJacob Faibussowitsch       PetscCall(VecDot(F, Y, &fty_mid1));
83*9566063dSJacob Faibussowitsch       PetscCall(VecCopy(X, W));
84*9566063dSJacob Faibussowitsch       PetscCall(VecAXPY(W, -(lambda + 0.5*(lambda - lambda_old)), Y));
85b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
86*9566063dSJacob Faibussowitsch         PetscCall((*linesearch->ops->viproject)(snes, W));
87b8ac21a2SPeter Brune       }
88*9566063dSJacob Faibussowitsch       PetscCall((*linesearch->ops->snesfunc)(snes, W, F));
89*9566063dSJacob Faibussowitsch       PetscCall(VecDot(F, Y, &fty_mid2));
90b8ac21a2SPeter Brune       s    = (2.*fty_mid2 + 3.*fty - 6.*fty_mid1 + fty_old) / (3.*delLambda);
91b8ac21a2SPeter Brune     }
92b8ac21a2SPeter Brune     /* if the solve is going in the wrong direction, fix it */
93b8ac21a2SPeter Brune     if (PetscRealPart(s) > 0.) s = -s;
94f2f03862SBarry Smith     if (s == 0.0) break;
95b8ac21a2SPeter Brune     lambda_update =  lambda - PetscRealPart(fty / s);
96b8ac21a2SPeter Brune 
97b8ac21a2SPeter Brune     /* switch directions if we stepped out of bounds */
98f5af7f23SKarl Rupp     if (lambda_update < steptol) lambda_update = lambda + PetscRealPart(fty / s);
99b8ac21a2SPeter Brune 
100620fc8aaSSatish Balay     if (PetscIsInfOrNanReal(lambda_update)) break;
101f5af7f23SKarl Rupp     if (lambda_update > maxstep) break;
102bbd5d0b3SPeter Brune 
103bbd5d0b3SPeter Brune     /* compute the new state of the line search */
104bbd5d0b3SPeter Brune     lambda_old = lambda;
105bbd5d0b3SPeter Brune     lambda     = lambda_update;
106bbd5d0b3SPeter Brune     fty_old    = fty;
107bbd5d0b3SPeter Brune   }
108bbd5d0b3SPeter Brune   /* construct the solution */
109*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(X, W));
110*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(W, -lambda, Y));
1119bd66eb0SPeter Brune   if (linesearch->ops->viproject) {
112*9566063dSJacob Faibussowitsch     PetscCall((*linesearch->ops->viproject)(snes, W));
1139bd66eb0SPeter Brune   }
114bbd5d0b3SPeter Brune   /* postcheck */
115*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w));
116bbd5d0b3SPeter Brune   if (changed_y) {
117*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(X, -lambda, Y));
1189bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
119*9566063dSJacob Faibussowitsch       PetscCall((*linesearch->ops->viproject)(snes, X));
1209bd66eb0SPeter Brune     }
121bbd5d0b3SPeter Brune   } else {
122*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(W, X));
123bbd5d0b3SPeter Brune   }
124*9566063dSJacob Faibussowitsch   PetscCall((*linesearch->ops->snesfunc)(snes,X,F));
125bbd5d0b3SPeter Brune 
126*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchComputeNorms(linesearch));
127*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm));
128bbd5d0b3SPeter Brune 
129*9566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchSetLambda(linesearch, lambda));
1306a388c36SPeter Brune 
1316a388c36SPeter Brune   if (monitor) {
132*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel));
133*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(monitor,"    Line search terminated: lambda = %g, fnorms = %g\n", (double)lambda, (double)gnorm));
134*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel));
135bbd5d0b3SPeter Brune   }
1366a388c36SPeter Brune   if (lambda <= steptol) {
137*9566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT));
138bbd5d0b3SPeter Brune   }
139bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
140bbd5d0b3SPeter Brune }
141bbd5d0b3SPeter Brune 
142954494b2SJed Brown /*MC
1431a4f838cSPeter Brune    SNESLINESEARCHCP - Critical point line search. This line search assumes that there exists some
144cd7522eaSPeter Brune    artificial G(x) for which the SNESFunction F(x) = grad G(x).  Therefore, this line search seeks
145db609ea7SPeter Brune    to find roots of dot(F, Y) via a secant method.
146cd7522eaSPeter Brune 
147cd7522eaSPeter Brune    Options Database Keys:
148eb23ba39SBarry Smith +  -snes_linesearch_minlambda <minlambda> - the minimum acceptable lambda
149eb23ba39SBarry Smith .  -snes_linesearch_maxstep <length> - the algorithm insures that a step length is never longer than this value
150eb23ba39SBarry Smith .  -snes_linesearch_damping <damping> - initial trial step length is scaled by this factor, default is 1.0
151eb23ba39SBarry Smith -  -snes_linesearch_max_it <max_it> - the maximum number of secant steps performed.
152cd7522eaSPeter Brune 
153cd7522eaSPeter Brune    Notes:
154eb23ba39SBarry Smith    This method does NOT use the objective function if it is provided with SNESSetObjective().
155eb23ba39SBarry Smith 
156cd7522eaSPeter Brune    This method is the preferred line search for SNESQN and SNESNCG.
157954494b2SJed Brown 
158954494b2SJed Brown    Level: advanced
159954494b2SJed Brown 
160f1c6b773SPeter Brune .seealso: SNESLineSearchCreate(), SNESLineSearchSetType()
161954494b2SJed Brown M*/
1628cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_CP(SNESLineSearch linesearch)
163bbd5d0b3SPeter Brune {
164bbd5d0b3SPeter Brune   PetscFunctionBegin;
165f1c6b773SPeter Brune   linesearch->ops->apply          = SNESLineSearchApply_CP;
1660298fd71SBarry Smith   linesearch->ops->destroy        = NULL;
1670298fd71SBarry Smith   linesearch->ops->setfromoptions = NULL;
1680298fd71SBarry Smith   linesearch->ops->reset          = NULL;
1690298fd71SBarry Smith   linesearch->ops->view           = NULL;
1700298fd71SBarry Smith   linesearch->ops->setup          = NULL;
171b000cd8dSPeter Brune   linesearch->order               = SNES_LINESEARCH_ORDER_LINEAR;
172a491bab8SPeter Brune 
173a491bab8SPeter Brune   linesearch->max_its = 1;
174bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
175bbd5d0b3SPeter Brune }
176