xref: /petsc/src/snes/linesearch/impls/cp/linesearchcp.c (revision dcf2fd19addf68f961057cf0cf7f6217b6b499d5)
1af0996ceSBarry Smith #include <petsc/private/linesearchimpl.h>
26a388c36SPeter Brune #include <petscsnes.h>
3bbd5d0b3SPeter Brune 
4bbd5d0b3SPeter Brune #undef __FUNCT__
5f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchApply_CP"
6f1c6b773SPeter Brune static PetscErrorCode SNESLineSearchApply_CP(SNESLineSearch linesearch)
7bbd5d0b3SPeter Brune {
8422a814eSBarry Smith   PetscBool      changed_y, changed_w;
9bbd5d0b3SPeter Brune   PetscErrorCode ierr;
106a388c36SPeter Brune   Vec            X, Y, F, W;
116a388c36SPeter Brune   SNES           snes;
12516fe3c3SPeter Brune   PetscReal      xnorm, ynorm, gnorm, steptol, atol, rtol, ltol, maxstep;
13bbd5d0b3SPeter Brune 
14bbd5d0b3SPeter Brune   PetscReal   lambda, lambda_old, lambda_update, delLambda;
15b8ac21a2SPeter Brune   PetscScalar fty, fty_init, fty_old, fty_mid1, fty_mid2, s;
166a388c36SPeter Brune   PetscInt    i, max_its;
176a388c36SPeter Brune 
186a388c36SPeter Brune   PetscViewer monitor;
19bbd5d0b3SPeter Brune 
20bbd5d0b3SPeter Brune   PetscFunctionBegin;
210298fd71SBarry Smith   ierr = SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, NULL);CHKERRQ(ierr);
22f1c6b773SPeter Brune   ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr);
23f1c6b773SPeter Brune   ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
24f1c6b773SPeter Brune   ierr = SNESLineSearchGetLambda(linesearch, &lambda);CHKERRQ(ierr);
25f1c6b773SPeter Brune   ierr = SNESLineSearchGetTolerances(linesearch, &steptol, &maxstep, &rtol, &atol, &ltol, &max_its);CHKERRQ(ierr);
26422a814eSBarry Smith   ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED);CHKERRQ(ierr);
27*dcf2fd19SBarry Smith   ierr = SNESLineSearchGetDefaultMonitor(linesearch, &monitor);CHKERRQ(ierr);
286a388c36SPeter Brune 
29bbd5d0b3SPeter Brune   /* precheck */
307b1df9c1SPeter Brune   ierr       = SNESLineSearchPreCheck(linesearch,X,Y,&changed_y);CHKERRQ(ierr);
31bbd5d0b3SPeter Brune   lambda_old = 0.0;
3262893cf2SPeter Brune 
33e0e0c2afSPeter Brune   ierr = VecDot(F,Y,&fty_old);CHKERRQ(ierr);
3462893cf2SPeter Brune   fty_init = fty_old;
35c0b2db79SJed Brown 
36c0b2db79SJed Brown   for (i = 0; i < max_its; i++) {
37bbd5d0b3SPeter Brune     /* compute the norm at lambda */
38bbd5d0b3SPeter Brune     ierr = VecCopy(X, W);CHKERRQ(ierr);
39bbd5d0b3SPeter Brune     ierr = VecAXPY(W, -lambda, Y);CHKERRQ(ierr);
409bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
419bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
429bd66eb0SPeter Brune     }
43fb8e56e0SPeter Brune     ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr);
44e0e0c2afSPeter Brune     ierr = VecDot(F,Y,&fty);CHKERRQ(ierr);
45bbd5d0b3SPeter Brune 
46bbd5d0b3SPeter Brune     delLambda = lambda - lambda_old;
47b8ac21a2SPeter Brune 
48b8ac21a2SPeter Brune     /* check for convergence */
49b8ac21a2SPeter Brune     if (PetscAbsReal(delLambda) < steptol*lambda) break;
50b8ac21a2SPeter Brune     if (PetscAbsScalar(fty) / PetscAbsScalar(fty_init) < rtol) break;
51a7370c10SPeter Brune     if (PetscAbsScalar(fty) < atol && i > 0) break;
526a388c36SPeter Brune     if (monitor) {
536a388c36SPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
54c69d1a72SBarry Smith       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: lambdas = [%g, %g], ftys = [%g, %g]\n",(double)lambda, (double)lambda_old, (double)PetscRealPart(fty), (double)PetscRealPart(fty_old));CHKERRQ(ierr);
556a388c36SPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
56bbd5d0b3SPeter Brune     }
57bbd5d0b3SPeter Brune 
58bbd5d0b3SPeter Brune     /* compute the search direction */
59b000cd8dSPeter Brune     if (linesearch->order == SNES_LINESEARCH_ORDER_LINEAR) {
60b8ac21a2SPeter Brune       s = (fty - fty_old) / delLambda;
61b000cd8dSPeter Brune     } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
62b8ac21a2SPeter Brune       ierr = VecCopy(X, W);CHKERRQ(ierr);
63b8ac21a2SPeter Brune       ierr = VecAXPY(W, -0.5*(lambda + lambda_old), Y);CHKERRQ(ierr);
64b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
65b8ac21a2SPeter Brune         ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
66b8ac21a2SPeter Brune       }
67fb8e56e0SPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr);
68b8ac21a2SPeter Brune       ierr = VecDot(F, Y, &fty_mid1);CHKERRQ(ierr);
69b8ac21a2SPeter Brune       s    = (3.*fty - 4.*fty_mid1 + fty_old) / delLambda;
70b8ac21a2SPeter Brune     } else {
71b8ac21a2SPeter Brune       ierr = VecCopy(X, W);CHKERRQ(ierr);
72b8ac21a2SPeter Brune       ierr = VecAXPY(W, -0.5*(lambda + lambda_old), Y);CHKERRQ(ierr);
73b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
74b8ac21a2SPeter Brune         ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
75b8ac21a2SPeter Brune       }
76fb8e56e0SPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr);
77e0e0c2afSPeter Brune       ierr = VecDot(F, Y, &fty_mid1);CHKERRQ(ierr);
78b8ac21a2SPeter Brune       ierr = VecCopy(X, W);CHKERRQ(ierr);
79b8ac21a2SPeter Brune       ierr = VecAXPY(W, -(lambda + 0.5*(lambda - lambda_old)), Y);CHKERRQ(ierr);
80b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
81b8ac21a2SPeter Brune         ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
82b8ac21a2SPeter Brune       }
83fb8e56e0SPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes, W, F);CHKERRQ(ierr);
84e0e0c2afSPeter Brune       ierr = VecDot(F, Y, &fty_mid2);CHKERRQ(ierr);
85b8ac21a2SPeter Brune       s    = (2.*fty_mid2 + 3.*fty - 6.*fty_mid1 + fty_old) / (3.*delLambda);
86b8ac21a2SPeter Brune     }
87b8ac21a2SPeter Brune     /* if the solve is going in the wrong direction, fix it */
88b8ac21a2SPeter Brune     if (PetscRealPart(s) > 0.) s = -s;
89b8ac21a2SPeter Brune     lambda_update =  lambda - PetscRealPart(fty / s);
90b8ac21a2SPeter Brune 
91b8ac21a2SPeter Brune     /* switch directions if we stepped out of bounds */
92f5af7f23SKarl Rupp     if (lambda_update < steptol) lambda_update = lambda + PetscRealPart(fty / s);
93b8ac21a2SPeter Brune 
94620fc8aaSSatish Balay     if (PetscIsInfOrNanReal(lambda_update)) break;
95f5af7f23SKarl Rupp     if (lambda_update > maxstep) break;
96bbd5d0b3SPeter Brune 
97bbd5d0b3SPeter Brune     /* compute the new state of the line search */
98bbd5d0b3SPeter Brune     lambda_old = lambda;
99bbd5d0b3SPeter Brune     lambda     = lambda_update;
100bbd5d0b3SPeter Brune     fty_old    = fty;
101bbd5d0b3SPeter Brune   }
102bbd5d0b3SPeter Brune   /* construct the solution */
103bbd5d0b3SPeter Brune   ierr = VecCopy(X, W);CHKERRQ(ierr);
104bbd5d0b3SPeter Brune   ierr = VecAXPY(W, -lambda, Y);CHKERRQ(ierr);
1059bd66eb0SPeter Brune   if (linesearch->ops->viproject) {
1069bd66eb0SPeter Brune     ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
1079bd66eb0SPeter Brune   }
108bbd5d0b3SPeter Brune   /* postcheck */
1097b1df9c1SPeter Brune   ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr);
110bbd5d0b3SPeter Brune   if (changed_y) {
111bbd5d0b3SPeter Brune     ierr = VecAXPY(X, -lambda, Y);CHKERRQ(ierr);
1129bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
1139bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, X);CHKERRQ(ierr);
1149bd66eb0SPeter Brune     }
115bbd5d0b3SPeter Brune   } else {
116bbd5d0b3SPeter Brune     ierr = VecCopy(W, X);CHKERRQ(ierr);
117bbd5d0b3SPeter Brune   }
118fb8e56e0SPeter Brune   ierr = (*linesearch->ops->snesfunc)(snes,X,F);CHKERRQ(ierr);
119bbd5d0b3SPeter Brune 
120f1c6b773SPeter Brune   ierr = SNESLineSearchComputeNorms(linesearch);CHKERRQ(ierr);
121f1c6b773SPeter Brune   ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr);
122bbd5d0b3SPeter Brune 
123f1c6b773SPeter Brune   ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr);
1246a388c36SPeter Brune 
1256a388c36SPeter Brune   if (monitor) {
1266a388c36SPeter Brune     ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
127c69d1a72SBarry Smith     ierr = PetscViewerASCIIPrintf(monitor,"    Line search terminated: lambda = %g, fnorms = %g\n", (double)lambda, (double)gnorm);CHKERRQ(ierr);
1286a388c36SPeter Brune     ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
129bbd5d0b3SPeter Brune   }
1306a388c36SPeter Brune   if (lambda <= steptol) {
131e9b602ebSSatish Balay     ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
132bbd5d0b3SPeter Brune   }
133bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
134bbd5d0b3SPeter Brune }
135bbd5d0b3SPeter Brune 
136bbd5d0b3SPeter Brune #undef __FUNCT__
137f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchCreate_CP"
138954494b2SJed Brown /*MC
1391a4f838cSPeter Brune    SNESLINESEARCHCP - Critical point line search. This line search assumes that there exists some
140cd7522eaSPeter Brune    artificial G(x) for which the SNESFunction F(x) = grad G(x).  Therefore, this line search seeks
141db609ea7SPeter Brune    to find roots of dot(F, Y) via a secant method.
142cd7522eaSPeter Brune 
143cd7522eaSPeter Brune    Options Database Keys:
144eb23ba39SBarry Smith +  -snes_linesearch_minlambda <minlambda> - the minimum acceptable lambda
145eb23ba39SBarry Smith .  -snes_linesearch_maxstep <length> - the algorithm insures that a step length is never longer than this value
146eb23ba39SBarry Smith .  -snes_linesearch_damping <damping> - initial trial step length is scaled by this factor, default is 1.0
147eb23ba39SBarry Smith -  -snes_linesearch_max_it <max_it> - the maximum number of secant steps performed.
148cd7522eaSPeter Brune 
149cd7522eaSPeter Brune    Notes:
150eb23ba39SBarry Smith    This method does NOT use the objective function if it is provided with SNESSetObjective().
151eb23ba39SBarry Smith 
152cd7522eaSPeter Brune    This method is the preferred line search for SNESQN and SNESNCG.
153954494b2SJed Brown 
154954494b2SJed Brown    Level: advanced
155954494b2SJed Brown 
156f1c6b773SPeter Brune .keywords: SNES, SNESLineSearch, damping
157954494b2SJed Brown 
158f1c6b773SPeter Brune .seealso: SNESLineSearchCreate(), SNESLineSearchSetType()
159954494b2SJed Brown M*/
1608cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_CP(SNESLineSearch linesearch)
161bbd5d0b3SPeter Brune {
162bbd5d0b3SPeter Brune   PetscFunctionBegin;
163f1c6b773SPeter Brune   linesearch->ops->apply          = SNESLineSearchApply_CP;
1640298fd71SBarry Smith   linesearch->ops->destroy        = NULL;
1650298fd71SBarry Smith   linesearch->ops->setfromoptions = NULL;
1660298fd71SBarry Smith   linesearch->ops->reset          = NULL;
1670298fd71SBarry Smith   linesearch->ops->view           = NULL;
1680298fd71SBarry Smith   linesearch->ops->setup          = NULL;
169b000cd8dSPeter Brune   linesearch->order               = SNES_LINESEARCH_ORDER_LINEAR;
170a491bab8SPeter Brune 
171a491bab8SPeter Brune   linesearch->max_its = 1;
172bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
173bbd5d0b3SPeter Brune }
174