Actual source code: linesearchbt.c
1: #include <petsc/private/linesearchimpl.h>
2: #include <petsc/private/snesimpl.h>
4: typedef struct {
5: PetscReal alpha; /* sufficient decrease parameter */
6: } SNESLineSearch_BT;
8: /*@
9: SNESLineSearchBTSetAlpha - Sets the descent parameter, alpha, in the `SNESLINESEARCHBT` variant.
11: Input Parameters:
12: + linesearch - linesearch context
13: - alpha - The descent parameter
15: Level: intermediate
17: .seealso: `SNESLineSearch`, `SNESLineSearchSetLambda()`, `SNESLineSearchGetTolerances()`, `SNESLINESEARCHBT`, `SNESLineSearchBTGetAlpha()`
18: @*/
19: PetscErrorCode SNESLineSearchBTSetAlpha(SNESLineSearch linesearch, PetscReal alpha)
20: {
21: SNESLineSearch_BT *bt = (SNESLineSearch_BT *)linesearch->data;
23: PetscFunctionBegin;
25: bt->alpha = alpha;
26: PetscFunctionReturn(PETSC_SUCCESS);
27: }
29: /*@
30: SNESLineSearchBTGetAlpha - Gets the descent parameter, alpha, in the `SNESLINESEARCHBT` variant.
32: Input Parameter:
33: . linesearch - linesearch context
35: Output Parameter:
36: . alpha - The descent parameter
38: Level: intermediate
40: .seealso: `SNESLineSearchGetLambda()`, `SNESLineSearchGetTolerances()` `SNESLINESEARCHBT`, `SNESLineSearchBTGetAlpha()`
41: @*/
42: PetscErrorCode SNESLineSearchBTGetAlpha(SNESLineSearch linesearch, PetscReal *alpha)
43: {
44: SNESLineSearch_BT *bt = (SNESLineSearch_BT *)linesearch->data;
46: PetscFunctionBegin;
48: *alpha = bt->alpha;
49: PetscFunctionReturn(PETSC_SUCCESS);
50: }
52: static PetscErrorCode SNESLineSearchApply_BT(SNESLineSearch linesearch)
53: {
54: PetscBool changed_y, changed_w;
55: Vec X, F, Y, W, G;
56: SNES snes;
57: PetscReal fnorm, xnorm, ynorm, gnorm;
58: PetscReal lambda, lambdatemp, lambdaprev, minlambda, maxstep, initslope, alpha, stol;
59: PetscReal t1, t2, a, b, d;
60: PetscReal f;
61: PetscReal g, gprev;
62: PetscViewer monitor;
63: PetscInt max_its, count;
64: SNESLineSearch_BT *bt = (SNESLineSearch_BT *)linesearch->data;
65: Mat jac;
66: PetscErrorCode (*objective)(SNES, Vec, PetscReal *, void *);
68: PetscFunctionBegin;
69: PetscCall(SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, &G));
70: PetscCall(SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm));
71: PetscCall(SNESLineSearchGetLambda(linesearch, &lambda));
72: PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
73: PetscCall(SNESLineSearchGetDefaultMonitor(linesearch, &monitor));
74: PetscCall(SNESLineSearchGetTolerances(linesearch, &minlambda, &maxstep, NULL, NULL, NULL, &max_its));
75: PetscCall(SNESGetTolerances(snes, NULL, NULL, &stol, NULL, NULL));
76: PetscCall(SNESGetObjective(snes, &objective, NULL));
77: alpha = bt->alpha;
79: PetscCall(SNESGetJacobian(snes, &jac, NULL, NULL, NULL));
80: PetscCheck(jac || objective, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "SNESLineSearchBT requires a Jacobian matrix");
82: PetscCall(SNESLineSearchPreCheck(linesearch, X, Y, &changed_y));
83: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED));
85: PetscCall(VecNormBegin(Y, NORM_2, &ynorm));
86: PetscCall(VecNormBegin(X, NORM_2, &xnorm));
87: PetscCall(VecNormEnd(Y, NORM_2, &ynorm));
88: PetscCall(VecNormEnd(X, NORM_2, &xnorm));
90: if (ynorm == 0.0) {
91: if (monitor) {
92: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
93: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Initial direction and size is 0\n"));
94: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
95: }
96: PetscCall(VecCopy(X, W));
97: PetscCall(VecCopy(F, G));
98: PetscCall(SNESLineSearchSetNorms(linesearch, xnorm, fnorm, ynorm));
99: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT));
100: PetscFunctionReturn(PETSC_SUCCESS);
101: }
102: if (ynorm > maxstep) { /* Step too big, so scale back */
103: if (monitor) {
104: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
105: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Scaling step by %14.12e old ynorm %14.12e\n", (double)(maxstep / ynorm), (double)ynorm));
106: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
107: }
108: PetscCall(VecScale(Y, maxstep / (ynorm)));
109: ynorm = maxstep;
110: }
112: /* if the SNES has an objective set, use that instead of the function value */
113: if (objective) {
114: PetscCall(SNESComputeObjective(snes, X, &f));
115: } else {
116: f = fnorm * fnorm;
117: }
119: /* compute the initial slope */
120: if (objective) {
121: /* slope comes from the function (assumed to be the gradient of the objective */
122: PetscCall(VecDotRealPart(Y, F, &initslope));
123: } else {
124: /* slope comes from the normal equations */
125: PetscCall(MatMult(jac, Y, W));
126: PetscCall(VecDotRealPart(F, W, &initslope));
127: if (initslope > 0.0) initslope = -initslope;
128: if (initslope == 0.0) initslope = -1.0;
129: }
131: while (PETSC_TRUE) {
132: PetscCall(VecWAXPY(W, -lambda, Y, X));
133: if (linesearch->ops->viproject) PetscCall((*linesearch->ops->viproject)(snes, W));
134: if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
135: PetscCall(PetscInfo(snes, "Exceeded maximum function evaluations, while checking full step length!\n"));
136: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
137: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION));
138: PetscFunctionReturn(PETSC_SUCCESS);
139: }
141: if (objective) {
142: PetscCall(SNESComputeObjective(snes, W, &g));
143: } else {
144: PetscCall((*linesearch->ops->snesfunc)(snes, W, G));
145: if (linesearch->ops->vinorm) {
146: gnorm = fnorm;
147: PetscCall((*linesearch->ops->vinorm)(snes, G, W, &gnorm));
148: } else {
149: PetscCall(VecNorm(G, NORM_2, &gnorm));
150: }
151: g = PetscSqr(gnorm);
152: }
153: PetscCall(SNESLineSearchMonitor(linesearch));
155: if (!PetscIsInfOrNanReal(g)) break;
156: if (monitor) {
157: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
158: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: objective function at lambdas = %g is Inf or Nan, cutting lambda\n", (double)lambda));
159: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
160: }
161: if (lambda <= minlambda) SNESCheckFunctionNorm(snes, g);
162: lambda = .5 * lambda;
163: }
165: if (!objective) PetscCall(PetscInfo(snes, "Initial fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm));
166: if (.5 * g <= .5 * f + lambda * alpha * initslope) { /* Sufficient reduction or step tolerance convergence */
167: if (monitor) {
168: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
169: if (!objective) {
170: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm));
171: } else {
172: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Using full step: obj %14.12e obj %14.12e\n", (double)f, (double)g));
173: }
174: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
175: }
176: } else {
177: /* Since the full step didn't work and the step is tiny, quit */
178: if (stol * xnorm > ynorm) {
179: PetscCall(SNESLineSearchSetNorms(linesearch, xnorm, fnorm, ynorm));
180: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED));
181: if (monitor) {
182: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
183: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Ended due to ynorm < stol*xnorm (%14.12e < %14.12e).\n", (double)ynorm, (double)(stol * xnorm)));
184: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
185: }
186: PetscFunctionReturn(PETSC_SUCCESS);
187: }
188: /* Fit points with quadratic */
189: lambdatemp = -initslope / (g - f - 2.0 * lambda * initslope);
190: lambdaprev = lambda;
191: gprev = g;
192: if (lambdatemp > .5 * lambda) lambdatemp = .5 * lambda;
193: if (lambdatemp <= .1 * lambda) lambda = .1 * lambda;
194: else lambda = lambdatemp;
196: PetscCall(VecWAXPY(W, -lambda, Y, X));
197: if (linesearch->ops->viproject) PetscCall((*linesearch->ops->viproject)(snes, W));
198: if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
199: PetscCall(PetscInfo(snes, "Exceeded maximum function evaluations, while attempting quadratic backtracking! %" PetscInt_FMT " \n", snes->nfuncs));
200: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
201: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION));
202: PetscFunctionReturn(PETSC_SUCCESS);
203: }
204: if (objective) {
205: PetscCall(SNESComputeObjective(snes, W, &g));
206: } else {
207: PetscCall((*linesearch->ops->snesfunc)(snes, W, G));
208: if (linesearch->ops->vinorm) {
209: gnorm = fnorm;
210: PetscCall((*linesearch->ops->vinorm)(snes, G, W, &gnorm));
211: } else {
212: PetscCall(VecNorm(G, NORM_2, &gnorm));
213: }
214: g = PetscSqr(gnorm);
215: }
216: if (PetscIsInfOrNanReal(g)) {
217: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF));
218: PetscCall(PetscInfo(snes, "Aborted due to Nan or Inf in function evaluation\n"));
219: PetscFunctionReturn(PETSC_SUCCESS);
220: }
221: if (monitor) {
222: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
223: if (!objective) {
224: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: gnorm after quadratic fit %14.12e\n", (double)gnorm));
225: } else {
226: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: obj after quadratic fit %14.12e\n", (double)g));
227: }
228: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
229: }
230: if (.5 * g < .5 * f + lambda * alpha * initslope) { /* sufficient reduction */
231: if (monitor) {
232: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
233: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Quadratically determined step, lambda=%18.16e\n", (double)lambda));
234: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
235: }
236: } else {
237: /* Fit points with cubic */
238: for (count = 0; count < max_its; count++) {
239: if (lambda <= minlambda) {
240: if (monitor) {
241: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
242: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: unable to find good step length! After %" PetscInt_FMT " tries \n", count));
243: if (!objective) {
244: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", (double)fnorm, (double)gnorm, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope));
245: } else {
246: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: obj(0)=%18.16e, obj=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", (double)f, (double)g, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope));
247: }
248: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
249: }
250: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT));
251: PetscFunctionReturn(PETSC_SUCCESS);
252: }
253: if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
254: t1 = .5 * (g - f) - lambda * initslope;
255: t2 = .5 * (gprev - f) - lambdaprev * initslope;
256: a = (t1 / (lambda * lambda) - t2 / (lambdaprev * lambdaprev)) / (lambda - lambdaprev);
257: b = (-lambdaprev * t1 / (lambda * lambda) + lambda * t2 / (lambdaprev * lambdaprev)) / (lambda - lambdaprev);
258: d = b * b - 3 * a * initslope;
259: if (d < 0.0) d = 0.0;
260: if (a == 0.0) lambdatemp = -initslope / (2.0 * b);
261: else lambdatemp = (-b + PetscSqrtReal(d)) / (3.0 * a);
263: } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
264: lambdatemp = -initslope / (g - f - 2.0 * initslope);
265: } else SETERRQ(PetscObjectComm((PetscObject)linesearch), PETSC_ERR_SUP, "unsupported line search order for type bt");
266: lambdaprev = lambda;
267: gprev = g;
268: if (lambdatemp > .5 * lambda) lambdatemp = .5 * lambda;
269: if (lambdatemp <= .1 * lambda) lambda = .1 * lambda;
270: else lambda = lambdatemp;
271: PetscCall(VecWAXPY(W, -lambda, Y, X));
272: if (linesearch->ops->viproject) PetscCall((*linesearch->ops->viproject)(snes, W));
273: if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
274: PetscCall(PetscInfo(snes, "Exceeded maximum function evaluations, while looking for good step length! %" PetscInt_FMT " \n", count));
275: if (!objective) PetscCall(PetscInfo(snes, "fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", (double)fnorm, (double)gnorm, (double)ynorm, (double)lambda, (double)initslope));
276: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION));
277: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
278: PetscFunctionReturn(PETSC_SUCCESS);
279: }
280: if (objective) {
281: PetscCall(SNESComputeObjective(snes, W, &g));
282: } else {
283: PetscCall((*linesearch->ops->snesfunc)(snes, W, G));
284: if (linesearch->ops->vinorm) {
285: gnorm = fnorm;
286: PetscCall((*linesearch->ops->vinorm)(snes, G, W, &gnorm));
287: } else {
288: PetscCall(VecNorm(G, NORM_2, &gnorm));
289: }
290: g = PetscSqr(gnorm);
291: }
292: if (PetscIsInfOrNanReal(g)) {
293: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF));
294: PetscCall(PetscInfo(snes, "Aborted due to Nan or Inf in function evaluation\n"));
295: PetscFunctionReturn(PETSC_SUCCESS);
296: }
297: if (.5 * g < .5 * f + lambda * alpha * initslope) { /* is reduction enough? */
298: if (monitor) {
299: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
300: if (!objective) {
301: if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
302: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n", (double)gnorm, (double)lambda));
303: } else {
304: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n", (double)gnorm, (double)lambda));
305: }
306: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
307: } else {
308: if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
309: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Cubically determined step, obj %14.12e lambda=%18.16e\n", (double)g, (double)lambda));
310: } else {
311: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Quadratically determined step, obj %14.12e lambda=%18.16e\n", (double)g, (double)lambda));
312: }
313: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
314: }
315: }
316: break;
317: } else if (monitor) {
318: PetscCall(PetscViewerASCIIAddTab(monitor, ((PetscObject)linesearch)->tablevel));
319: if (!objective) {
320: if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
321: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Cubic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n", (double)gnorm, (double)lambda));
322: } else {
323: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Quadratic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n", (double)gnorm, (double)lambda));
324: }
325: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
326: } else {
327: if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
328: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Cubic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n", (double)g, (double)lambda));
329: } else {
330: PetscCall(PetscViewerASCIIPrintf(monitor, " Line search: Quadratic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n", (double)g, (double)lambda));
331: }
332: PetscCall(PetscViewerASCIISubtractTab(monitor, ((PetscObject)linesearch)->tablevel));
333: }
334: }
335: }
336: }
337: }
339: /* postcheck */
340: /* update Y to lambda*Y so that W is consistent with X - lambda*Y */
341: PetscCall(VecScale(Y, lambda));
342: PetscCall(SNESLineSearchPostCheck(linesearch, X, Y, W, &changed_y, &changed_w));
343: if (changed_y) {
344: PetscCall(VecWAXPY(W, -1.0, Y, X));
345: if (linesearch->ops->viproject) PetscCall((*linesearch->ops->viproject)(snes, W));
346: }
347: if (changed_y || changed_w || objective) { /* recompute the function norm if the step has changed or the objective isn't the norm */
348: PetscCall((*linesearch->ops->snesfunc)(snes, W, G));
349: if (linesearch->ops->vinorm) {
350: gnorm = fnorm;
351: PetscCall((*linesearch->ops->vinorm)(snes, G, W, &gnorm));
352: } else {
353: PetscCall(VecNorm(G, NORM_2, &gnorm));
354: }
355: PetscCall(VecNorm(Y, NORM_2, &ynorm));
356: if (PetscIsInfOrNanReal(gnorm)) {
357: PetscCall(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF));
358: PetscCall(PetscInfo(snes, "Aborted due to Nan or Inf in function evaluation\n"));
359: PetscFunctionReturn(PETSC_SUCCESS);
360: }
361: }
363: /* copy the solution over */
364: PetscCall(VecCopy(W, X));
365: PetscCall(VecCopy(G, F));
366: PetscCall(VecNorm(X, NORM_2, &xnorm));
367: PetscCall(SNESLineSearchSetLambda(linesearch, lambda));
368: PetscCall(SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm));
369: PetscFunctionReturn(PETSC_SUCCESS);
370: }
372: PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer)
373: {
374: PetscBool iascii;
375: SNESLineSearch_BT *bt = (SNESLineSearch_BT *)linesearch->data;
377: PetscFunctionBegin;
378: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
379: if (iascii) {
380: if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
381: PetscCall(PetscViewerASCIIPrintf(viewer, " interpolation: cubic\n"));
382: } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
383: PetscCall(PetscViewerASCIIPrintf(viewer, " interpolation: quadratic\n"));
384: }
385: PetscCall(PetscViewerASCIIPrintf(viewer, " alpha=%e\n", (double)bt->alpha));
386: }
387: PetscFunctionReturn(PETSC_SUCCESS);
388: }
390: static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch)
391: {
392: PetscFunctionBegin;
393: PetscCall(PetscFree(linesearch->data));
394: PetscFunctionReturn(PETSC_SUCCESS);
395: }
397: static PetscErrorCode SNESLineSearchSetFromOptions_BT(SNESLineSearch linesearch, PetscOptionItems *PetscOptionsObject)
398: {
399: SNESLineSearch_BT *bt = (SNESLineSearch_BT *)linesearch->data;
401: PetscFunctionBegin;
402: PetscOptionsHeadBegin(PetscOptionsObject, "SNESLineSearch BT options");
403: PetscCall(PetscOptionsReal("-snes_linesearch_alpha", "Descent tolerance", "SNESLineSearchBT", bt->alpha, &bt->alpha, NULL));
404: PetscOptionsHeadEnd();
405: PetscFunctionReturn(PETSC_SUCCESS);
406: }
408: /*MC
409: SNESLINESEARCHBT - Backtracking line search.
411: This line search finds the minimum of a polynomial fitting of the L2 norm of the
412: function or the objective function if it is provided with `SNESSetObjective()`. If this fit does not satisfy the conditions for progress, the interval shrinks
413: and the fit is reattempted at most max_it times or until lambda is below minlambda.
415: Options Database Keys:
416: + -snes_linesearch_alpha <1e\-4> - slope descent parameter
417: . -snes_linesearch_damping <1.0> - initial step length
418: . -snes_linesearch_maxstep <length> - if the length the initial step is larger than this then the
419: step is scaled back to be of this length at the beginning of the line search
420: . -snes_linesearch_max_it <40> - maximum number of shrinking step
421: . -snes_linesearch_minlambda <1e\-12> - minimum step length allowed
422: - -snes_linesearch_order <cubic,quadratic> - order of the approximation
424: Level: advanced
426: Note:
427: This line search will always produce a step that is less than or equal to, in length, the full step size.
429: Reference:
430: . - * - "Numerical Methods for Unconstrained Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
432: .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetType()`
433: M*/
434: PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch)
435: {
436: SNESLineSearch_BT *bt;
438: PetscFunctionBegin;
439: linesearch->ops->apply = SNESLineSearchApply_BT;
440: linesearch->ops->destroy = SNESLineSearchDestroy_BT;
441: linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT;
442: linesearch->ops->reset = NULL;
443: linesearch->ops->view = SNESLineSearchView_BT;
444: linesearch->ops->setup = NULL;
446: PetscCall(PetscNew(&bt));
448: linesearch->data = (void *)bt;
449: linesearch->max_its = 40;
450: linesearch->order = SNES_LINESEARCH_ORDER_CUBIC;
451: bt->alpha = 1e-4;
452: PetscFunctionReturn(PETSC_SUCCESS);
453: }