xref: /petsc/src/snes/linesearch/impls/cp/linesearchcp.c (revision f2f0386234ddea0caaa348a15336041bab782f9e)
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;
7bbd5d0b3SPeter Brune   PetscErrorCode ierr;
86a388c36SPeter Brune   Vec            X, Y, F, W;
96a388c36SPeter Brune   SNES           snes;
10516fe3c3SPeter Brune   PetscReal      xnorm, ynorm, gnorm, steptol, atol, rtol, ltol, maxstep;
11bbd5d0b3SPeter Brune 
12bbd5d0b3SPeter Brune   PetscReal   lambda, lambda_old, lambda_update, delLambda;
13b8ac21a2SPeter Brune   PetscScalar fty, fty_init, fty_old, fty_mid1, fty_mid2, s;
146a388c36SPeter Brune   PetscInt    i, max_its;
156a388c36SPeter Brune 
166a388c36SPeter Brune   PetscViewer monitor;
17bbd5d0b3SPeter Brune 
18bbd5d0b3SPeter Brune   PetscFunctionBegin;
190298fd71SBarry Smith   ierr = SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, NULL);CHKERRQ(ierr);
20f1c6b773SPeter Brune   ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr);
21f1c6b773SPeter Brune   ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
22f1c6b773SPeter Brune   ierr = SNESLineSearchGetLambda(linesearch, &lambda);CHKERRQ(ierr);
23f1c6b773SPeter Brune   ierr = SNESLineSearchGetTolerances(linesearch, &steptol, &maxstep, &rtol, &atol, &ltol, &max_its);CHKERRQ(ierr);
24422a814eSBarry Smith   ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED);CHKERRQ(ierr);
25dcf2fd19SBarry Smith   ierr = SNESLineSearchGetDefaultMonitor(linesearch, &monitor);CHKERRQ(ierr);
266a388c36SPeter Brune 
27bbd5d0b3SPeter Brune   /* precheck */
287b1df9c1SPeter Brune   ierr       = SNESLineSearchPreCheck(linesearch,X,Y,&changed_y);CHKERRQ(ierr);
29bbd5d0b3SPeter Brune   lambda_old = 0.0;
3062893cf2SPeter Brune 
31e0e0c2afSPeter Brune   ierr = VecDot(F,Y,&fty_old);CHKERRQ(ierr);
329e0a2ef9SBarry Smith   if (PetscAbsScalar(fty_old) < atol) {
339e0a2ef9SBarry Smith     if (monitor) {
349e0a2ef9SBarry Smith       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3554cbc681SBarry Smith       ierr = PetscViewerASCIIPrintf(monitor,"    Line search terminated ended at initial point because dot(F,Y) = %g < atol = %g\n",(double)PetscAbsScalar(fty_old), (double)atol);CHKERRQ(ierr);
369e0a2ef9SBarry Smith       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
379e0a2ef9SBarry Smith     }
389e0a2ef9SBarry Smith     PetscFunctionReturn(0);
399e0a2ef9SBarry Smith   }
409e0a2ef9SBarry Smith 
4162893cf2SPeter Brune   fty_init = fty_old;
42c0b2db79SJed Brown 
43c0b2db79SJed Brown   for (i = 0; i < max_its; i++) {
44bbd5d0b3SPeter Brune     /* compute the norm at lambda */
45bbd5d0b3SPeter Brune     ierr = VecCopy(X, W);CHKERRQ(ierr);
46bbd5d0b3SPeter Brune     ierr = VecAXPY(W, -lambda, Y);CHKERRQ(ierr);
479bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
489bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
499bd66eb0SPeter Brune     }
50fb8e56e0SPeter Brune     ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr);
51e0e0c2afSPeter Brune     ierr = VecDot(F,Y,&fty);CHKERRQ(ierr);
52bbd5d0b3SPeter Brune 
53bbd5d0b3SPeter Brune     delLambda = lambda - lambda_old;
54b8ac21a2SPeter Brune 
55b8ac21a2SPeter Brune     /* check for convergence */
56b8ac21a2SPeter Brune     if (PetscAbsReal(delLambda) < steptol*lambda) break;
57b8ac21a2SPeter Brune     if (PetscAbsScalar(fty) / PetscAbsScalar(fty_init) < rtol) break;
58a7370c10SPeter Brune     if (PetscAbsScalar(fty) < atol && i > 0) break;
596a388c36SPeter Brune     if (monitor) {
606a388c36SPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
61c69d1a72SBarry 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);
626a388c36SPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
63bbd5d0b3SPeter Brune     }
64bbd5d0b3SPeter Brune 
65bbd5d0b3SPeter Brune     /* compute the search direction */
66b000cd8dSPeter Brune     if (linesearch->order == SNES_LINESEARCH_ORDER_LINEAR) {
67b8ac21a2SPeter Brune       s = (fty - fty_old) / delLambda;
68b000cd8dSPeter Brune     } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
69b8ac21a2SPeter Brune       ierr = VecCopy(X, W);CHKERRQ(ierr);
70b8ac21a2SPeter Brune       ierr = VecAXPY(W, -0.5*(lambda + lambda_old), Y);CHKERRQ(ierr);
71b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
72b8ac21a2SPeter Brune         ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
73b8ac21a2SPeter Brune       }
74fb8e56e0SPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr);
75b8ac21a2SPeter Brune       ierr = VecDot(F, Y, &fty_mid1);CHKERRQ(ierr);
76b8ac21a2SPeter Brune       s    = (3.*fty - 4.*fty_mid1 + fty_old) / delLambda;
77b8ac21a2SPeter Brune     } else {
78b8ac21a2SPeter Brune       ierr = VecCopy(X, W);CHKERRQ(ierr);
79b8ac21a2SPeter Brune       ierr = VecAXPY(W, -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_mid1);CHKERRQ(ierr);
85b8ac21a2SPeter Brune       ierr = VecCopy(X, W);CHKERRQ(ierr);
86b8ac21a2SPeter Brune       ierr = VecAXPY(W, -(lambda + 0.5*(lambda - lambda_old)), Y);CHKERRQ(ierr);
87b8ac21a2SPeter Brune       if (linesearch->ops->viproject) {
88b8ac21a2SPeter Brune         ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
89b8ac21a2SPeter Brune       }
90fb8e56e0SPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes, W, F);CHKERRQ(ierr);
91e0e0c2afSPeter Brune       ierr = VecDot(F, Y, &fty_mid2);CHKERRQ(ierr);
92b8ac21a2SPeter Brune       s    = (2.*fty_mid2 + 3.*fty - 6.*fty_mid1 + fty_old) / (3.*delLambda);
93b8ac21a2SPeter Brune     }
94b8ac21a2SPeter Brune     /* if the solve is going in the wrong direction, fix it */
95b8ac21a2SPeter Brune     if (PetscRealPart(s) > 0.) s = -s;
96*f2f03862SBarry Smith     if (s == 0.0) break;
97b8ac21a2SPeter Brune     lambda_update =  lambda - PetscRealPart(fty / s);
98b8ac21a2SPeter Brune 
99b8ac21a2SPeter Brune     /* switch directions if we stepped out of bounds */
100f5af7f23SKarl Rupp     if (lambda_update < steptol) lambda_update = lambda + PetscRealPart(fty / s);
101b8ac21a2SPeter Brune 
102620fc8aaSSatish Balay     if (PetscIsInfOrNanReal(lambda_update)) break;
103f5af7f23SKarl Rupp     if (lambda_update > maxstep) break;
104bbd5d0b3SPeter Brune 
105bbd5d0b3SPeter Brune     /* compute the new state of the line search */
106bbd5d0b3SPeter Brune     lambda_old = lambda;
107bbd5d0b3SPeter Brune     lambda     = lambda_update;
108bbd5d0b3SPeter Brune     fty_old    = fty;
109bbd5d0b3SPeter Brune   }
110bbd5d0b3SPeter Brune   /* construct the solution */
111bbd5d0b3SPeter Brune   ierr = VecCopy(X, W);CHKERRQ(ierr);
112bbd5d0b3SPeter Brune   ierr = VecAXPY(W, -lambda, Y);CHKERRQ(ierr);
1139bd66eb0SPeter Brune   if (linesearch->ops->viproject) {
1149bd66eb0SPeter Brune     ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
1159bd66eb0SPeter Brune   }
116bbd5d0b3SPeter Brune   /* postcheck */
1177b1df9c1SPeter Brune   ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr);
118bbd5d0b3SPeter Brune   if (changed_y) {
119bbd5d0b3SPeter Brune     ierr = VecAXPY(X, -lambda, Y);CHKERRQ(ierr);
1209bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
1219bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, X);CHKERRQ(ierr);
1229bd66eb0SPeter Brune     }
123bbd5d0b3SPeter Brune   } else {
124bbd5d0b3SPeter Brune     ierr = VecCopy(W, X);CHKERRQ(ierr);
125bbd5d0b3SPeter Brune   }
126fb8e56e0SPeter Brune   ierr = (*linesearch->ops->snesfunc)(snes,X,F);CHKERRQ(ierr);
127bbd5d0b3SPeter Brune 
128f1c6b773SPeter Brune   ierr = SNESLineSearchComputeNorms(linesearch);CHKERRQ(ierr);
129f1c6b773SPeter Brune   ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr);
130bbd5d0b3SPeter Brune 
131f1c6b773SPeter Brune   ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr);
1326a388c36SPeter Brune 
1336a388c36SPeter Brune   if (monitor) {
1346a388c36SPeter Brune     ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
135c69d1a72SBarry Smith     ierr = PetscViewerASCIIPrintf(monitor,"    Line search terminated: lambda = %g, fnorms = %g\n", (double)lambda, (double)gnorm);CHKERRQ(ierr);
1366a388c36SPeter Brune     ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
137bbd5d0b3SPeter Brune   }
1386a388c36SPeter Brune   if (lambda <= steptol) {
139e9b602ebSSatish Balay     ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
140bbd5d0b3SPeter Brune   }
141bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
142bbd5d0b3SPeter Brune }
143bbd5d0b3SPeter Brune 
144954494b2SJed Brown /*MC
1451a4f838cSPeter Brune    SNESLINESEARCHCP - Critical point line search. This line search assumes that there exists some
146cd7522eaSPeter Brune    artificial G(x) for which the SNESFunction F(x) = grad G(x).  Therefore, this line search seeks
147db609ea7SPeter Brune    to find roots of dot(F, Y) via a secant method.
148cd7522eaSPeter Brune 
149cd7522eaSPeter Brune    Options Database Keys:
150eb23ba39SBarry Smith +  -snes_linesearch_minlambda <minlambda> - the minimum acceptable lambda
151eb23ba39SBarry Smith .  -snes_linesearch_maxstep <length> - the algorithm insures that a step length is never longer than this value
152eb23ba39SBarry Smith .  -snes_linesearch_damping <damping> - initial trial step length is scaled by this factor, default is 1.0
153eb23ba39SBarry Smith -  -snes_linesearch_max_it <max_it> - the maximum number of secant steps performed.
154cd7522eaSPeter Brune 
155cd7522eaSPeter Brune    Notes:
156eb23ba39SBarry Smith    This method does NOT use the objective function if it is provided with SNESSetObjective().
157eb23ba39SBarry Smith 
158cd7522eaSPeter Brune    This method is the preferred line search for SNESQN and SNESNCG.
159954494b2SJed Brown 
160954494b2SJed Brown    Level: advanced
161954494b2SJed Brown 
162f1c6b773SPeter Brune .keywords: SNES, SNESLineSearch, damping
163954494b2SJed Brown 
164f1c6b773SPeter Brune .seealso: SNESLineSearchCreate(), SNESLineSearchSetType()
165954494b2SJed Brown M*/
1668cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_CP(SNESLineSearch linesearch)
167bbd5d0b3SPeter Brune {
168bbd5d0b3SPeter Brune   PetscFunctionBegin;
169f1c6b773SPeter Brune   linesearch->ops->apply          = SNESLineSearchApply_CP;
1700298fd71SBarry Smith   linesearch->ops->destroy        = NULL;
1710298fd71SBarry Smith   linesearch->ops->setfromoptions = NULL;
1720298fd71SBarry Smith   linesearch->ops->reset          = NULL;
1730298fd71SBarry Smith   linesearch->ops->view           = NULL;
1740298fd71SBarry Smith   linesearch->ops->setup          = NULL;
175b000cd8dSPeter Brune   linesearch->order               = SNES_LINESEARCH_ORDER_LINEAR;
176a491bab8SPeter Brune 
177a491bab8SPeter Brune   linesearch->max_its = 1;
178bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
179bbd5d0b3SPeter Brune }
180