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