xref: /petsc/src/snes/linesearch/impls/bt/linesearchbt.c (revision 5a9b6599d0ff68ab5f0ec64c3d9dcd7c90db1bfb)
1 #include <petsc-private/linesearchimpl.h> /*I  "petscsnes.h"  I*/
2 #include <petsc-private/snesimpl.h>
3 
4 typedef struct {
5   PetscReal        alpha; /* sufficient decrease parameter */
6 } SNESLineSearch_BT;
7 
8 #undef __FUNCT__
9 #define __FUNCT__ "SNESLineSearchBTSetAlpha"
10 /*@
11    SNESLineSearchBTSetAlpha - Sets the descent parameter, alpha, in the BT linesearch variant.
12 
13    Input Parameters:
14 +  linesearch - linesearch context
15 -  alpha - The descent parameter
16 
17    Level: intermediate
18 
19 .seealso: SNESLineSearchSetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT
20 @*/
21 PetscErrorCode SNESLineSearchBTSetAlpha(SNESLineSearch linesearch, PetscReal alpha)
22 {
23   SNESLineSearch_BT  *bt;
24   PetscFunctionBegin;
25   PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1);
26   bt = (SNESLineSearch_BT *)linesearch->data;
27   bt->alpha = alpha;
28   PetscFunctionReturn(0);
29 }
30 
31 
32 #undef __FUNCT__
33 #define __FUNCT__ "SNESLineSearchBTGetAlpha"
34 /*@
35    SNESLineSearchBTGetAlpha - Gets the descent parameter, alpha, in the BT linesearch variant.
36 
37    Input Parameters:
38 .  linesearch - linesearch context
39 
40    Output Parameters:
41 .  alpha - The descent parameter
42 
43    Level: intermediate
44 
45 .seealso: SNESLineSearchGetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT
46 @*/
47 PetscErrorCode SNESLineSearchBTGetAlpha(SNESLineSearch linesearch, PetscReal *alpha)
48 {
49   SNESLineSearch_BT  *bt;
50   PetscFunctionBegin;
51   PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1);
52   bt = (SNESLineSearch_BT *)linesearch->data;
53   *alpha = bt->alpha;
54   PetscFunctionReturn(0);
55 }
56 
57 #undef __FUNCT__
58 #define __FUNCT__ "SNESLineSearchApply_BT"
59 static PetscErrorCode  SNESLineSearchApply_BT(SNESLineSearch linesearch)
60 {
61   PetscBool      changed_y,changed_w;
62   PetscErrorCode ierr;
63   Vec            X,F,Y,W,G;
64   SNES           snes;
65   PetscReal      fnorm, xnorm, ynorm, gnorm, gnormprev;
66   PetscReal      lambda,lambdatemp,lambdaprev,minlambda,maxstep,initslope,alpha,stol;
67   PetscReal      t1,t2,a,b,d;
68 #if defined(PETSC_USE_COMPLEX)
69   PetscScalar    cinitslope;
70 #endif
71   PetscBool      domainerror;
72   PetscViewer    monitor;
73   PetscInt       max_its,count;
74   SNESLineSearch_BT  *bt;
75   Mat            jac;
76 
77 
78   PetscFunctionBegin;
79 
80   ierr = SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, &G);CHKERRQ(ierr);
81   ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
82   ierr = SNESLineSearchGetLambda(linesearch, &lambda);CHKERRQ(ierr);
83   ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
84   ierr = SNESLineSearchGetMonitor(linesearch, &monitor);CHKERRQ(ierr);
85   ierr = SNESLineSearchGetTolerances(linesearch,&minlambda,&maxstep,PETSC_NULL,PETSC_NULL,PETSC_NULL,&max_its);
86   ierr = SNESGetTolerances(snes,PETSC_NULL,PETSC_NULL,&stol,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
87   bt = (SNESLineSearch_BT *)linesearch->data;
88 
89   alpha = bt->alpha;
90 
91   ierr = SNESGetJacobian(snes, &jac, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
92   if (!jac) {
93     SETERRQ(((PetscObject)linesearch)->comm, PETSC_ERR_USER, "SNESLineSearchBT requires a Jacobian matrix");
94   }
95   /* precheck */
96   ierr = SNESLineSearchPreCheck(linesearch,X,Y,&changed_y);CHKERRQ(ierr);
97   ierr = SNESLineSearchSetSuccess(linesearch, PETSC_TRUE);CHKERRQ(ierr);
98 
99   ierr = VecNormBegin(Y, NORM_2, &ynorm);CHKERRQ(ierr);
100   ierr = VecNormBegin(X, NORM_2, &xnorm);CHKERRQ(ierr);
101   ierr = VecNormEnd(Y, NORM_2, &ynorm);CHKERRQ(ierr);
102   ierr = VecNormEnd(X, NORM_2, &xnorm);CHKERRQ(ierr);
103 
104   if (ynorm == 0.0) {
105     if (monitor) {
106       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
107       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
108       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
109     }
110     ierr   = VecCopy(X,W);CHKERRQ(ierr);
111     ierr   = VecCopy(F,G);CHKERRQ(ierr);
112     ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
113     PetscFunctionReturn(0);
114   }
115   if (ynorm > maxstep) {	/* Step too big, so scale back */
116     if (monitor) {
117       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
118       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Scaling step by %14.12e old ynorm %14.12e\n", (maxstep/ynorm),ynorm);CHKERRQ(ierr);
119       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
120     }
121     ierr = VecScale(Y,maxstep/(ynorm));CHKERRQ(ierr);
122     ynorm = maxstep;
123   }
124   ierr      = MatMult(jac,Y,W);CHKERRQ(ierr);
125 #if defined(PETSC_USE_COMPLEX)
126   ierr      = VecDot(F,W,&cinitslope);CHKERRQ(ierr);
127   initslope = PetscRealPart(cinitslope);
128 #else
129   ierr      = VecDot(F,W,&initslope);CHKERRQ(ierr);
130 #endif
131   if (initslope > 0.0)  initslope = -initslope;
132   if (initslope == 0.0) initslope = -1.0;
133 
134   ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
135   if (linesearch->ops->viproject) {
136     ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
137   }
138   if (snes->nfuncs >= snes->max_funcs) {
139     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
140     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
141     ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
142     PetscFunctionReturn(0);
143   }
144   ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr);
145   ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr);
146   if (domainerror) {
147     ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
148     PetscFunctionReturn(0);
149   }
150   if (linesearch->ops->vinorm) {
151     gnorm = fnorm;
152     ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
153   } else {
154     ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
155   }
156 
157   if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
158   ierr = PetscInfo2(snes,"Initial fnorm %14.12e gnorm %14.12e\n", fnorm, gnorm);CHKERRQ(ierr);
159   if (.5*gnorm*gnorm <= .5*fnorm*fnorm + lambda*alpha*initslope || ynorm < stol*xnorm) { /* Sufficient reduction or step tolerance convergence */
160     if (monitor) {
161       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
162       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", fnorm, gnorm);CHKERRQ(ierr);
163       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
164     }
165   } else {
166     /* Fit points with quadratic */
167     lambdatemp = -initslope/(gnorm*gnorm - fnorm*fnorm - 2.0*lambda*initslope);
168     lambdaprev = lambda;
169     gnormprev  = gnorm;
170     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
171     if (lambdatemp <= .1*lambda) lambda = .1*lambda;
172     else                         lambda = lambdatemp;
173 
174     ierr  = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
175     if (linesearch->ops->viproject) {
176       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
177     }
178     if (snes->nfuncs >= snes->max_funcs) {
179       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
180       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
181       ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
182       PetscFunctionReturn(0);
183     }
184     ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr);
185     ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr);
186     if (domainerror) {
187       PetscFunctionReturn(0);
188     }
189     if (linesearch->ops->vinorm) {
190       gnorm = fnorm;
191       ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
192     } else {
193       ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
194     }
195     if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
196     if (monitor) {
197       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
198       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: gnorm after quadratic fit %14.12e\n",gnorm);CHKERRQ(ierr);
199       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
200     }
201     if (.5*gnorm*gnorm < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
202       if (monitor) {
203         ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
204         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda);CHKERRQ(ierr);
205         ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
206       }
207     } else {
208       /* Fit points with cubic */
209       for (count = 0; count < max_its; count++) {
210         if (lambda <= minlambda) {
211           if (monitor) {
212             ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
213             ierr = PetscViewerASCIIPrintf(monitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
214             ierr = PetscViewerASCIIPrintf(monitor,
215                                           "    Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
216                                           fnorm, gnorm, ynorm, minlambda, lambda, initslope);CHKERRQ(ierr);
217             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
218           }
219           ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
220           PetscFunctionReturn(0);
221         }
222         if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
223           t1 = .5*(gnorm*gnorm - fnorm*fnorm) - lambda*initslope;
224           t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
225           a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
226           b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
227           d  = b*b - 3*a*initslope;
228           if (d < 0.0) d = 0.0;
229           if (a == 0.0) {
230             lambdatemp = -initslope/(2.0*b);
231           } else {
232             lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a);
233           }
234         } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
235           lambdatemp = -initslope/(gnorm*gnorm - fnorm*fnorm - 2.0*initslope);
236         } else {
237           SETERRQ(((PetscObject)linesearch)->comm, PETSC_ERR_SUP, "unsupported line search order for type bt");
238         }
239           lambdaprev = lambda;
240           gnormprev  = gnorm;
241         if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
242         if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
243         else                         lambda     = lambdatemp;
244         ierr  = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
245         if (linesearch->ops->viproject) {
246           ierr = (*linesearch->ops->viproject)(snes,W);CHKERRQ(ierr);
247         }
248         if (snes->nfuncs >= snes->max_funcs) {
249           ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
250           ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
251                             fnorm,gnorm,ynorm,lambda,initslope);CHKERRQ(ierr);
252           ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
253           snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
254           PetscFunctionReturn(0);
255         }
256         ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr);
257         ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr);
258         if (domainerror) {
259           ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
260           PetscFunctionReturn(0);
261         }
262         if (linesearch->ops->vinorm) {
263           gnorm = fnorm;
264           ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
265         } else {
266           ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
267         }
268         if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
269         if (.5*gnorm*gnorm < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */
270           if (monitor) {
271             ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
272             if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
273               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr);
274             } else {
275               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr);
276             }
277             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
278           }
279           break;
280         } else {
281           if (monitor) {
282             ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
283             if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
284               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr);
285             } else {
286               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr);
287             }
288             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
289           }
290         }
291       }
292     }
293   }
294 
295   /* postcheck */
296   ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr);
297   if (changed_y) {
298     ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
299     if (linesearch->ops->viproject) {
300       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
301     }
302   }
303   if (changed_y || changed_w) { /* recompute the function if the step has changed */
304     ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr);
305     ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr);
306     if (domainerror) {
307       ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr);
308       PetscFunctionReturn(0);
309     }
310     if (linesearch->ops->vinorm) {
311       gnorm = fnorm;
312       ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
313     } else {
314       ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
315     }
316     ierr = VecNorm(Y,NORM_2,&ynorm);CHKERRQ(ierr);
317     if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
318 
319   }
320 
321   /* copy the solution over */
322   ierr = VecCopy(W, X);CHKERRQ(ierr);
323   ierr = VecCopy(G, F);CHKERRQ(ierr);
324   ierr = VecNorm(X, NORM_2, &xnorm);CHKERRQ(ierr);
325   ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr);
326   ierr = SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm);CHKERRQ(ierr);
327   PetscFunctionReturn(0);
328 }
329 
330 #undef __FUNCT__
331 #define __FUNCT__ "SNESLineSearchView_BT"
332 PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer)
333 {
334   PetscErrorCode    ierr;
335   PetscBool         iascii;
336   SNESLineSearch_BT *bt;
337   PetscFunctionBegin;
338   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
339   bt = (SNESLineSearch_BT*)linesearch->data;
340   if (iascii) {
341     if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
342     ierr = PetscViewerASCIIPrintf(viewer, "  interpolation: cubic\n");CHKERRQ(ierr);
343     } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
344     ierr = PetscViewerASCIIPrintf(viewer, "  interpolation: quadratic\n");CHKERRQ(ierr);
345     }
346     ierr = PetscViewerASCIIPrintf(viewer, "  alpha=%e\n", bt->alpha);CHKERRQ(ierr);
347   }
348   PetscFunctionReturn(0);
349 }
350 
351 
352 #undef __FUNCT__
353 #define __FUNCT__ "SNESLineSearchDestroy_BT"
354 static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch)
355 {
356   PetscErrorCode ierr;
357 
358   PetscFunctionBegin;
359   ierr = PetscFree(linesearch->data);CHKERRQ(ierr);
360   PetscFunctionReturn(0);
361 }
362 
363 
364 #undef __FUNCT__
365 #define __FUNCT__ "SNESLineSearchSetFromOptions_BT"
366 static PetscErrorCode SNESLineSearchSetFromOptions_BT(SNESLineSearch linesearch)
367 {
368 
369   PetscErrorCode       ierr;
370   SNESLineSearch_BT    *bt;
371   PetscFunctionBegin;
372 
373   bt = (SNESLineSearch_BT*)linesearch->data;
374 
375   ierr = PetscOptionsHead("SNESLineSearch BT options");CHKERRQ(ierr);
376   ierr = PetscOptionsReal("-snes_linesearch_alpha",   "Descent tolerance",        "SNESLineSearchBT", bt->alpha, &bt->alpha, PETSC_NULL);CHKERRQ(ierr);
377 
378   ierr = PetscOptionsTail();CHKERRQ(ierr);
379   PetscFunctionReturn(0);
380 }
381 
382 
383 #undef __FUNCT__
384 #define __FUNCT__ "SNESLineSearchCreate_BT"
385 /*MC
386    SNESLINESEARCHBT - Backtracking line search.
387 
388    This line search finds the minimum of a polynomial fitting of the L2 norm of the
389    function. If this fit does not satisfy the conditions for progress, the interval shrinks
390    and the fit is reattempted at most max_it times or until lambda is below minlambda.
391 
392    Options Database Keys:
393 +  -snes_linesearch_alpha<1e-4> - slope descent parameter
394 .  -snes_linesearch_damping<1.0> - initial step length
395 .  -snes_linesearch_max_it<40> - maximum number of shrinking step
396 .  -snes_linesearch_minlambda<1e-12> - minimum step length allowed
397 -  -snes_linesearch_order<cubic,quadratic> - order of the approximation
398 
399    Level: advanced
400 
401    Notes:
402    This line search is taken from "Numerical Methods for Unconstrained
403    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
404 
405 .keywords: SNES, SNESLineSearch, damping
406 
407 .seealso: SNESLineSearchCreate(), SNESLineSearchSetType()
408 M*/
409 PETSC_EXTERN_C PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch)
410 {
411 
412   SNESLineSearch_BT  *bt;
413   PetscErrorCode ierr;
414 
415   PetscFunctionBegin;
416   linesearch->ops->apply          = SNESLineSearchApply_BT;
417   linesearch->ops->destroy        = SNESLineSearchDestroy_BT;
418   linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT;
419   linesearch->ops->reset          = PETSC_NULL;
420   linesearch->ops->view           = SNESLineSearchView_BT;
421   linesearch->ops->setup          = PETSC_NULL;
422 
423   ierr = PetscNewLog(linesearch, SNESLineSearch_BT, &bt);CHKERRQ(ierr);
424   linesearch->data = (void *)bt;
425   linesearch->max_its = 40;
426   linesearch->order = SNES_LINESEARCH_ORDER_CUBIC;
427   bt->alpha = 1e-4;
428 
429   PetscFunctionReturn(0);
430 }
431