Actual source code: linesearch.c
1: #include <petsc/private/linesearchimpl.h>
3: PetscBool SNESLineSearchRegisterAllCalled = PETSC_FALSE;
4: PetscFunctionList SNESLineSearchList = NULL;
6: PetscClassId SNESLINESEARCH_CLASSID;
7: PetscLogEvent SNESLINESEARCH_Apply;
9: /*@
10: SNESLineSearchMonitorCancel - Clears all the monitor functions for a `SNESLineSearch` object.
12: Logically Collective
14: Input Parameter:
15: . ls - the `SNESLineSearch` context
17: Options Database Key:
18: . -snes_linesearch_monitor_cancel - cancels all monitors that have been hardwired
19: into a code by calls to `SNESLineSearchMonitorSet()`, but does not cancel those
20: set via the options database
22: Level: advanced
24: Notes:
25: There is no way to clear one specific monitor from a `SNESLineSearch` object.
27: This does not clear the monitor set with `SNESLineSearchSetDefaultMonitor()` use `SNESLineSearchSetDefaultMonitor`(ls,NULL) to cancel
28: that one.
30: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorDefault()`, `SNESLineSearchMonitorSet()`
31: @*/
32: PetscErrorCode SNESLineSearchMonitorCancel(SNESLineSearch ls)
33: {
34: PetscInt i;
36: PetscFunctionBegin;
38: for (i = 0; i < ls->numbermonitors; i++) {
39: if (ls->monitordestroy[i]) PetscCall((*ls->monitordestroy[i])(&ls->monitorcontext[i]));
40: }
41: ls->numbermonitors = 0;
42: PetscFunctionReturn(PETSC_SUCCESS);
43: }
45: /*@
46: SNESLineSearchMonitor - runs the user provided monitor routines, if they exist
48: Collective
50: Input Parameter:
51: . ls - the linesearch object
53: Level: developer
55: Note:
56: This routine is called by the `SNES` implementations.
57: It does not typically need to be called by the user.
59: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorSet()`
60: @*/
61: PetscErrorCode SNESLineSearchMonitor(SNESLineSearch ls)
62: {
63: PetscInt i, n = ls->numbermonitors;
65: PetscFunctionBegin;
66: for (i = 0; i < n; i++) PetscCall((*ls->monitorftns[i])(ls, ls->monitorcontext[i]));
67: PetscFunctionReturn(PETSC_SUCCESS);
68: }
70: /*@C
71: SNESLineSearchMonitorSet - Sets an ADDITIONAL function that is to be used at every
72: iteration of the nonlinear solver to display the iteration's
73: progress.
75: Logically Collective
77: Input Parameters:
78: + ls - the `SNESLineSearch` context
79: . f - the monitor function
80: . mctx - [optional] user-defined context for private data for the
81: monitor routine (use `NULL` if no context is desired)
82: - monitordestroy - [optional] routine that frees monitor context
83: (may be `NULL`)
85: Level: intermediate
87: Note:
88: Several different monitoring routines may be set by calling
89: `SNESLineSearchMonitorSet()` multiple times; all will be called in the
90: order in which they were set.
92: Fortran Note:
93: Only a single monitor function can be set for each `SNESLineSearch` object
95: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorDefault()`, `SNESLineSearchMonitorCancel()`
96: @*/
97: PetscErrorCode SNESLineSearchMonitorSet(SNESLineSearch ls, PetscErrorCode (*f)(SNESLineSearch, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
98: {
99: PetscInt i;
100: PetscBool identical;
102: PetscFunctionBegin;
104: for (i = 0; i < ls->numbermonitors; i++) {
105: PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))ls->monitorftns[i], ls->monitorcontext[i], ls->monitordestroy[i], &identical));
106: if (identical) PetscFunctionReturn(PETSC_SUCCESS);
107: }
108: PetscCheck(ls->numbermonitors < MAXSNESLSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
109: ls->monitorftns[ls->numbermonitors] = f;
110: ls->monitordestroy[ls->numbermonitors] = monitordestroy;
111: ls->monitorcontext[ls->numbermonitors++] = (void *)mctx;
112: PetscFunctionReturn(PETSC_SUCCESS);
113: }
115: /*@C
116: SNESLineSearchMonitorSolutionUpdate - Monitors each update of the function value the linesearch tries
118: Collective
120: Input Parameters:
121: + ls - the `SNES` linesearch object
122: - vf - the context for the monitor, in this case it is an `PetscViewerAndFormat`
124: Level: intermediate
126: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESMonitorSet()`, `SNESMonitorSolution()`
127: @*/
128: PetscErrorCode SNESLineSearchMonitorSolutionUpdate(SNESLineSearch ls, PetscViewerAndFormat *vf)
129: {
130: PetscViewer viewer = vf->viewer;
131: Vec Y, W, G;
133: PetscFunctionBegin;
134: PetscCall(SNESLineSearchGetVecs(ls, NULL, NULL, &Y, &W, &G));
135: PetscCall(PetscViewerPushFormat(viewer, vf->format));
136: PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted update to solution \n"));
137: PetscCall(VecView(Y, viewer));
138: PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted new solution \n"));
139: PetscCall(VecView(W, viewer));
140: PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted updated function value\n"));
141: PetscCall(VecView(G, viewer));
142: PetscCall(PetscViewerPopFormat(viewer));
143: PetscFunctionReturn(PETSC_SUCCESS);
144: }
146: /*@
147: SNESLineSearchCreate - Creates the line search context.
149: Logically Collective
151: Input Parameter:
152: . comm - MPI communicator for the line search (typically from the associated `SNES` context).
154: Output Parameter:
155: . outlinesearch - the new linesearch context
157: Level: developer
159: Note:
160: The preferred calling sequence for users is to use `SNESGetLineSearch()` to acquire the `SNESLineSearch` instance
161: already associated with the `SNES`.
163: .seealso: `SNESLineSearch`, `LineSearchDestroy()`, `SNESGetLineSearch()`
164: @*/
165: PetscErrorCode SNESLineSearchCreate(MPI_Comm comm, SNESLineSearch *outlinesearch)
166: {
167: SNESLineSearch linesearch;
169: PetscFunctionBegin;
171: PetscCall(SNESInitializePackage());
172: *outlinesearch = NULL;
174: PetscCall(PetscHeaderCreate(linesearch, SNESLINESEARCH_CLASSID, "SNESLineSearch", "Linesearch", "SNESLineSearch", comm, SNESLineSearchDestroy, SNESLineSearchView));
176: linesearch->vec_sol_new = NULL;
177: linesearch->vec_func_new = NULL;
178: linesearch->vec_sol = NULL;
179: linesearch->vec_func = NULL;
180: linesearch->vec_update = NULL;
182: linesearch->lambda = 1.0;
183: linesearch->fnorm = 1.0;
184: linesearch->ynorm = 1.0;
185: linesearch->xnorm = 1.0;
186: linesearch->result = SNES_LINESEARCH_SUCCEEDED;
187: linesearch->norms = PETSC_TRUE;
188: linesearch->keeplambda = PETSC_FALSE;
189: linesearch->damping = 1.0;
190: linesearch->maxstep = 1e8;
191: linesearch->steptol = 1e-12;
192: linesearch->rtol = 1e-8;
193: linesearch->atol = 1e-15;
194: linesearch->ltol = 1e-8;
195: linesearch->precheckctx = NULL;
196: linesearch->postcheckctx = NULL;
197: linesearch->max_its = 1;
198: linesearch->setupcalled = PETSC_FALSE;
199: linesearch->monitor = NULL;
200: *outlinesearch = linesearch;
201: PetscFunctionReturn(PETSC_SUCCESS);
202: }
204: /*@
205: SNESLineSearchSetUp - Prepares the line search for being applied by allocating
206: any required vectors.
208: Collective
210: Input Parameter:
211: . linesearch - The `SNESLineSearch` instance.
213: Level: advanced
215: Note:
216: For most cases, this needn't be called by users or outside of `SNESLineSearchApply()`.
217: The only current case where this is called outside of this is for the VI
218: solvers, which modify the solution and work vectors before the first call
219: of `SNESLineSearchApply()`, requiring the `SNESLineSearch` work vectors to be
220: allocated upfront.
222: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchReset()`
223: @*/
225: PetscErrorCode SNESLineSearchSetUp(SNESLineSearch linesearch)
226: {
227: PetscFunctionBegin;
228: if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC));
229: if (!linesearch->setupcalled) {
230: if (!linesearch->vec_sol_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_sol_new));
231: if (!linesearch->vec_func_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_func_new));
232: if (linesearch->ops->setup) PetscUseTypeMethod(linesearch, setup);
233: if (!linesearch->ops->snesfunc) PetscCall(SNESLineSearchSetFunction(linesearch, SNESComputeFunction));
234: linesearch->lambda = linesearch->damping;
235: linesearch->setupcalled = PETSC_TRUE;
236: }
237: PetscFunctionReturn(PETSC_SUCCESS);
238: }
240: /*@
241: SNESLineSearchReset - Undoes the `SNESLineSearchSetUp()` and deletes any `Vec`s or `Mat`s allocated by the line search.
243: Collective
245: Input Parameter:
246: . linesearch - The `SNESLineSearch` instance.
248: Level: developer
250: Note:
251: Usually only called by `SNESReset()`
253: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetUp()`
254: @*/
256: PetscErrorCode SNESLineSearchReset(SNESLineSearch linesearch)
257: {
258: PetscFunctionBegin;
259: if (linesearch->ops->reset) PetscUseTypeMethod(linesearch, reset);
261: PetscCall(VecDestroy(&linesearch->vec_sol_new));
262: PetscCall(VecDestroy(&linesearch->vec_func_new));
264: PetscCall(VecDestroyVecs(linesearch->nwork, &linesearch->work));
266: linesearch->nwork = 0;
267: linesearch->setupcalled = PETSC_FALSE;
268: PetscFunctionReturn(PETSC_SUCCESS);
269: }
271: /*@C
272: SNESLineSearchSetFunction - Sets the function evaluation used by the `SNES` line search
273: `
274: Input Parameters:
275: . linesearch - the `SNESLineSearch` context
276: + func - function evaluation routine, this is usually the function provided with `SNESSetFunction()`
278: Level: developer
280: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESSetFunction()`
281: @*/
282: PetscErrorCode SNESLineSearchSetFunction(SNESLineSearch linesearch, PetscErrorCode (*func)(SNES, Vec, Vec))
283: {
284: PetscFunctionBegin;
286: linesearch->ops->snesfunc = func;
287: PetscFunctionReturn(PETSC_SUCCESS);
288: }
290: /*@C
291: SNESLineSearchSetPreCheck - Sets a user function that is called after the initial search direction has been computed but
292: before the line search routine has been applied. Allows the user to adjust the result of (usually a linear solve) that
293: determined the search direction.
295: Logically Collective
297: Input Parameters:
298: + linesearch - the `SNESLineSearch` context
299: . func - [optional] function evaluation routine, for the calling sequence see `SNESLineSearchPreCheck()`
300: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
302: Level: intermediate
304: Note:
305: Use `SNESLineSearchSetPostCheck()` to change the step after the line search.
306: search is complete.
308: Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.
310: .seealso: `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
311: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()`
313: @*/
314: PetscErrorCode SNESLineSearchSetPreCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch, Vec, Vec, PetscBool *, void *), void *ctx)
315: {
316: PetscFunctionBegin;
318: if (func) linesearch->ops->precheck = func;
319: if (ctx) linesearch->precheckctx = ctx;
320: PetscFunctionReturn(PETSC_SUCCESS);
321: }
323: /*@C
324: SNESLineSearchGetPreCheck - Gets the pre-check function for the line search routine.
326: Input Parameter:
327: . linesearch - the `SNESLineSearch` context
329: Output Parameters:
330: + func - [optional] function evaluation routine, for calling sequence see `SNESLineSearchPreCheck`
331: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
333: Level: intermediate
335: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
336: @*/
337: PetscErrorCode SNESLineSearchGetPreCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, PetscBool *, void *), void **ctx)
338: {
339: PetscFunctionBegin;
341: if (func) *func = linesearch->ops->precheck;
342: if (ctx) *ctx = linesearch->precheckctx;
343: PetscFunctionReturn(PETSC_SUCCESS);
344: }
346: /*@C
347: SNESLineSearchSetPostCheck - Sets a user function that is called after the line search has been applied to determine the step
348: direction and length. Allows the user a chance to change or override the decision of the line search routine
350: Logically Collective
352: Input Parameters:
353: + linesearch - the `SNESLineSearch` context
354: . func - [optional] function evaluation routine, for the calling sequence see `SNESLineSearchPostCheck`
355: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
357: Level: intermediate
359: Notes:
360: Use `SNESLineSearchSetPreCheck()` to change the step before the line search.
361: search is complete.
363: Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.
365: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchGetPostCheck()`,
366: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()
367: @*/
368: PetscErrorCode SNESLineSearchSetPostCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void *ctx)
369: {
370: PetscFunctionBegin;
372: if (func) linesearch->ops->postcheck = func;
373: if (ctx) linesearch->postcheckctx = ctx;
374: PetscFunctionReturn(PETSC_SUCCESS);
375: }
377: /*@C
378: SNESLineSearchGetPostCheck - Gets the post-check function for the line search routine.
380: Input Parameter:
381: . linesearch - the `SNESLineSearch` context
383: Output Parameters:
384: + func - [optional] function evaluation routine, see for the calling sequence `SNESLineSearchPostCheck`
385: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
387: Level: intermediate
389: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`
390: @*/
391: PetscErrorCode SNESLineSearchGetPostCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void **ctx)
392: {
393: PetscFunctionBegin;
395: if (func) *func = linesearch->ops->postcheck;
396: if (ctx) *ctx = linesearch->postcheckctx;
397: PetscFunctionReturn(PETSC_SUCCESS);
398: }
400: /*@
401: SNESLineSearchPreCheck - Prepares the line search for being applied.
403: Logically Collective
405: Input Parameters:
406: + linesearch - The linesearch instance.
407: . X - The current solution
408: - Y - The step direction
410: Output Parameter:
411: . changed - Indicator that the precheck routine has changed anything
413: Level: advanced
415: Note:
416: This calls any function provided with `SNESLineSearchSetPreCheck()`
418: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`,
419: `SNESLineSearchGetPostCheck()``
420: @*/
421: PetscErrorCode SNESLineSearchPreCheck(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed)
422: {
423: PetscFunctionBegin;
424: *changed = PETSC_FALSE;
425: if (linesearch->ops->precheck) {
426: PetscUseTypeMethod(linesearch, precheck, X, Y, changed, linesearch->precheckctx);
428: }
429: PetscFunctionReturn(PETSC_SUCCESS);
430: }
432: /*@
433: SNESLineSearchPostCheck - Hook to modify step direction or updated solution after a successful linesearch
435: Logically Collective
437: Input Parameters:
438: + linesearch - The linesearch context
439: . X - The last solution
440: . Y - The step direction
441: - W - The updated solution, W = X + lambda*Y for some lambda
443: Output Parameters:
444: + changed_Y - Indicator if the direction Y has been changed.
445: - changed_W - Indicator if the new candidate solution W has been changed.
447: Level: developer
449: Note:
450: This calls any function provided with `SNESLineSearchSetPreCheck()`
452: .seealso: `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPrecheck()`, `SNESLineSearchGetPrecheck()`
453: @*/
454: PetscErrorCode SNESLineSearchPostCheck(SNESLineSearch linesearch, Vec X, Vec Y, Vec W, PetscBool *changed_Y, PetscBool *changed_W)
455: {
456: PetscFunctionBegin;
457: *changed_Y = PETSC_FALSE;
458: *changed_W = PETSC_FALSE;
459: if (linesearch->ops->postcheck) {
460: PetscUseTypeMethod(linesearch, postcheck, X, Y, W, changed_Y, changed_W, linesearch->postcheckctx);
463: }
464: PetscFunctionReturn(PETSC_SUCCESS);
465: }
467: /*@C
468: SNESLineSearchPreCheckPicard - Implements a correction that is sometimes useful to improve the convergence rate of Picard iteration
470: Logically Collective
472: Input Parameters:
473: + linesearch - linesearch context
474: . X - base state for this step
475: - ctx - context for this function
477: Input/Output Parameter:
478: . Y - correction, possibly modified
480: Output Parameter:
481: . changed - flag indicating that Y was modified
483: Options Database Key:
484: + -snes_linesearch_precheck_picard - activate this routine
485: - -snes_linesearch_precheck_picard_angle - angle
487: Level: advanced
489: Notes:
490: This function should be passed to `SNESLineSearchSetPreCheck()`
492: The justification for this method involves the linear convergence of a Picard iteration
493: so the Picard linearization should be provided in place of the "Jacobian". This correction
494: is generally not useful when using a Newton linearization.
496: Reference:
497: . - * - Hindmarsh and Payne (1996) Time step limits for stable solutions of the ice sheet equation, Annals of Glaciology.
499: .seealso: `SNESLineSearch`, `SNESSetPicard()`, `SNESGetLineSearch()`, `SNESLineSearchSetPreCheck()`
500: @*/
501: PetscErrorCode SNESLineSearchPreCheckPicard(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed, void *ctx)
502: {
503: PetscReal angle = *(PetscReal *)linesearch->precheckctx;
504: Vec Ylast;
505: PetscScalar dot;
506: PetscInt iter;
507: PetscReal ynorm, ylastnorm, theta, angle_radians;
508: SNES snes;
510: PetscFunctionBegin;
511: PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
512: PetscCall(PetscObjectQuery((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject *)&Ylast));
513: if (!Ylast) {
514: PetscCall(VecDuplicate(Y, &Ylast));
515: PetscCall(PetscObjectCompose((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject)Ylast));
516: PetscCall(PetscObjectDereference((PetscObject)Ylast));
517: }
518: PetscCall(SNESGetIterationNumber(snes, &iter));
519: if (iter < 2) {
520: PetscCall(VecCopy(Y, Ylast));
521: *changed = PETSC_FALSE;
522: PetscFunctionReturn(PETSC_SUCCESS);
523: }
525: PetscCall(VecDot(Y, Ylast, &dot));
526: PetscCall(VecNorm(Y, NORM_2, &ynorm));
527: PetscCall(VecNorm(Ylast, NORM_2, &ylastnorm));
528: /* Compute the angle between the vectors Y and Ylast, clip to keep inside the domain of acos() */
529: theta = PetscAcosReal((PetscReal)PetscClipInterval(PetscAbsScalar(dot) / (ynorm * ylastnorm), -1.0, 1.0));
530: angle_radians = angle * PETSC_PI / 180.;
531: if (PetscAbsReal(theta) < angle_radians || PetscAbsReal(theta - PETSC_PI) < angle_radians) {
532: /* Modify the step Y */
533: PetscReal alpha, ydiffnorm;
534: PetscCall(VecAXPY(Ylast, -1.0, Y));
535: PetscCall(VecNorm(Ylast, NORM_2, &ydiffnorm));
536: alpha = (ydiffnorm > .001 * ylastnorm) ? ylastnorm / ydiffnorm : 1000.0;
537: PetscCall(VecCopy(Y, Ylast));
538: PetscCall(VecScale(Y, alpha));
539: PetscCall(PetscInfo(snes, "Angle %14.12e degrees less than threshold %14.12e, corrected step by alpha=%14.12e\n", (double)(theta * 180. / PETSC_PI), (double)angle, (double)alpha));
540: *changed = PETSC_TRUE;
541: } else {
542: PetscCall(PetscInfo(snes, "Angle %14.12e degrees exceeds threshold %14.12e, no correction applied\n", (double)(theta * 180. / PETSC_PI), (double)angle));
543: PetscCall(VecCopy(Y, Ylast));
544: *changed = PETSC_FALSE;
545: }
546: PetscFunctionReturn(PETSC_SUCCESS);
547: }
549: /*@
550: SNESLineSearchApply - Computes the line-search update.
552: Collective
554: Input Parameters:
555: + linesearch - The linesearch context
556: - Y - The search direction
558: Input/Output Parameters:
559: + X - The current solution, on output the new solution
560: . F - The current function, on output the new function
561: - fnorm - The current norm, on output the new function norm
563: Options Database Keys:
564: + -snes_linesearch_type - basic (or equivalently none), bt, l2, cp, nleqerr, shell
565: . -snes_linesearch_monitor [:filename] - Print progress of line searches
566: . -snes_linesearch_damping - The linesearch damping parameter, default is 1.0 (no damping)
567: . -snes_linesearch_norms - Turn on/off the linesearch norms computation (SNESLineSearchSetComputeNorms())
568: . -snes_linesearch_keeplambda - Keep the previous search length as the initial guess
569: - -snes_linesearch_max_it - The number of iterations for iterative line searches
571: Level: Intermediate
573: Notes:
574: This is typically called from within a `SNESSolve()` implementation in order to
575: help with convergence of the nonlinear method. Various `SNES` types use line searches
576: in different ways, but the overarching theme is that a line search is used to determine
577: an optimal damping parameter of a step at each iteration of the method. Each
578: application of the line search may invoke `SNESComputeFunction()` several times, and
579: therefore may be fairly expensive.
581: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchPreCheck()`, `SNESLineSearchPostCheck()`, `SNESSolve()`, `SNESComputeFunction()`, `SNESLineSearchSetComputeNorms()`,
582: `SNESLineSearchType`, `SNESLineSearchSetType()`
583: @*/
584: PetscErrorCode SNESLineSearchApply(SNESLineSearch linesearch, Vec X, Vec F, PetscReal *fnorm, Vec Y)
585: {
586: PetscFunctionBegin;
592: linesearch->result = SNES_LINESEARCH_SUCCEEDED;
594: linesearch->vec_sol = X;
595: linesearch->vec_update = Y;
596: linesearch->vec_func = F;
598: PetscCall(SNESLineSearchSetUp(linesearch));
600: if (!linesearch->keeplambda) linesearch->lambda = linesearch->damping; /* set the initial guess to lambda */
602: if (fnorm) linesearch->fnorm = *fnorm;
603: else PetscCall(VecNorm(F, NORM_2, &linesearch->fnorm));
605: PetscCall(PetscLogEventBegin(SNESLINESEARCH_Apply, linesearch, X, F, Y));
607: PetscUseTypeMethod(linesearch, apply);
609: PetscCall(PetscLogEventEnd(SNESLINESEARCH_Apply, linesearch, X, F, Y));
611: if (fnorm) *fnorm = linesearch->fnorm;
612: PetscFunctionReturn(PETSC_SUCCESS);
613: }
615: /*@
616: SNESLineSearchDestroy - Destroys the line search instance.
618: Collective
620: Input Parameter:
621: . linesearch - The linesearch context
623: Level: developer
625: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchReset()`, `SNESDestroy()`
626: @*/
627: PetscErrorCode SNESLineSearchDestroy(SNESLineSearch *linesearch)
628: {
629: PetscFunctionBegin;
630: if (!*linesearch) PetscFunctionReturn(PETSC_SUCCESS);
632: if (--((PetscObject)(*linesearch))->refct > 0) {
633: *linesearch = NULL;
634: PetscFunctionReturn(PETSC_SUCCESS);
635: }
636: PetscCall(PetscObjectSAWsViewOff((PetscObject)*linesearch));
637: PetscCall(SNESLineSearchReset(*linesearch));
638: PetscTryTypeMethod(*linesearch, destroy);
639: PetscCall(PetscViewerDestroy(&(*linesearch)->monitor));
640: PetscCall(SNESLineSearchMonitorCancel((*linesearch)));
641: PetscCall(PetscHeaderDestroy(linesearch));
642: PetscFunctionReturn(PETSC_SUCCESS);
643: }
645: /*@
646: SNESLineSearchSetDefaultMonitor - Turns on/off printing useful information and debugging output about the line search.
648: Logically Collective
650: Input Parameters:
651: + linesearch - the linesearch object
652: - viewer - an `PETSCVIEWERASCII` `PetscViewer` or `NULL` to turn off monitor
654: Options Database Key:
655: . -snes_linesearch_monitor [:filename] - enables the monitor
657: Level: intermediate
659: Developer Note:
660: This monitor is implemented differently than the other line search monitors that are set with
661: `SNESLineSearchMonitorSet()` since it is called in many locations of the line search routines to display aspects of the
662: line search that are not visible to the other monitors.
664: .seealso: `SNESLineSearch`, `PETSCVIEWERASCII`, `SNESGetLineSearch()`, `SNESLineSearchGetDefaultMonitor()`, `PetscViewer`, `SNESLineSearchSetMonitor()`,
665: `SNESLineSearchMonitorSetFromOptions()`
666: @*/
667: PetscErrorCode SNESLineSearchSetDefaultMonitor(SNESLineSearch linesearch, PetscViewer viewer)
668: {
669: PetscFunctionBegin;
670: if (viewer) PetscCall(PetscObjectReference((PetscObject)viewer));
671: PetscCall(PetscViewerDestroy(&linesearch->monitor));
672: linesearch->monitor = viewer;
673: PetscFunctionReturn(PETSC_SUCCESS);
674: }
676: /*@
677: SNESLineSearchGetDefaultMonitor - Gets the `PetscViewer` instance for the line search monitor.
679: Logically Collective
681: Input Parameter:
682: . linesearch - linesearch context
684: Output Parameter:
685: . monitor - monitor context
687: Level: intermediate
689: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetDefaultMonitor()`, `PetscViewer`
690: @*/
691: PetscErrorCode SNESLineSearchGetDefaultMonitor(SNESLineSearch linesearch, PetscViewer *monitor)
692: {
693: PetscFunctionBegin;
695: *monitor = linesearch->monitor;
696: PetscFunctionReturn(PETSC_SUCCESS);
697: }
699: /*@C
700: SNESLineSearchMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
702: Collective
704: Input Parameters:
705: + ls - `SNESLineSearch` object you wish to monitor
706: . name - the monitor type one is seeking
707: . help - message indicating what monitoring is done
708: . manual - manual page for the monitor
709: . monitor - the monitor function
710: - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `SNESLineSearch` or `PetscViewer`
712: Level: developer
714: .seealso: `SNESLineSearch`, `SNESLineSearchSetMonitor()`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
715: `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
716: `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
717: `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
718: `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
719: `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
720: `PetscOptionsFList()`, `PetscOptionsEList()`
721: @*/
722: PetscErrorCode SNESLineSearchMonitorSetFromOptions(SNESLineSearch ls, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(SNESLineSearch, PetscViewerAndFormat *), PetscErrorCode (*monitorsetup)(SNESLineSearch, PetscViewerAndFormat *))
723: {
724: PetscViewer viewer;
725: PetscViewerFormat format;
726: PetscBool flg;
728: PetscFunctionBegin;
729: PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)ls), ((PetscObject)ls)->options, ((PetscObject)ls)->prefix, name, &viewer, &format, &flg));
730: if (flg) {
731: PetscViewerAndFormat *vf;
732: PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
733: PetscCall(PetscObjectDereference((PetscObject)viewer));
734: if (monitorsetup) PetscCall((*monitorsetup)(ls, vf));
735: PetscCall(SNESLineSearchMonitorSet(ls, (PetscErrorCode(*)(SNESLineSearch, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
736: }
737: PetscFunctionReturn(PETSC_SUCCESS);
738: }
740: /*@
741: SNESLineSearchSetFromOptions - Sets options for the line search
743: Logically Collective
745: Input Parameter:
746: . linesearch - linesearch context
748: Options Database Keys:
749: + -snes_linesearch_type <type> - basic (or equivalently none), bt, l2, cp, nleqerr, shell
750: . -snes_linesearch_order <order> - 1, 2, 3. Most types only support certain orders (bt supports 2 or 3)
751: . -snes_linesearch_norms - Turn on/off the linesearch norms for the basic linesearch typem (`SNESLineSearchSetComputeNorms()`)
752: . -snes_linesearch_minlambda - The minimum step length
753: . -snes_linesearch_maxstep - The maximum step size
754: . -snes_linesearch_rtol - Relative tolerance for iterative line searches
755: . -snes_linesearch_atol - Absolute tolerance for iterative line searches
756: . -snes_linesearch_ltol - Change in lambda tolerance for iterative line searches
757: . -snes_linesearch_max_it - The number of iterations for iterative line searches
758: . -snes_linesearch_monitor [:filename] - Print progress of line searches
759: . -snes_linesearch_monitor_solution_update [viewer:filename:format] - view each update tried by line search routine
760: . -snes_linesearch_damping - The linesearch damping parameter
761: . -snes_linesearch_keeplambda - Keep the previous search length as the initial guess.
762: . -snes_linesearch_precheck_picard - Use precheck that speeds up convergence of picard method
763: - -snes_linesearch_precheck_picard_angle - Angle used in Picard precheck method
765: Level: intermediate
767: .seealso: `SNESLineSearch`, `SNESLineSearchCreate()`, `SNESLineSearchSetOrder()`, `SNESLineSearchSetType()`, `SNESLineSearchSetTolerances()`, `SNESLineSearchSetDamping()`, `SNESLineSearchPreCheckPicard()`,
768: `SNESLineSearchType`, `SNESLineSearchSetComputeNorms()`
769: @*/
770: PetscErrorCode SNESLineSearchSetFromOptions(SNESLineSearch linesearch)
771: {
772: const char *deft = SNESLINESEARCHBASIC;
773: char type[256];
774: PetscBool flg, set;
775: PetscViewer viewer;
777: PetscFunctionBegin;
778: PetscCall(SNESLineSearchRegisterAll());
780: PetscObjectOptionsBegin((PetscObject)linesearch);
781: if (((PetscObject)linesearch)->type_name) deft = ((PetscObject)linesearch)->type_name;
782: PetscCall(PetscOptionsFList("-snes_linesearch_type", "Linesearch type", "SNESLineSearchSetType", SNESLineSearchList, deft, type, 256, &flg));
783: if (flg) {
784: PetscCall(SNESLineSearchSetType(linesearch, type));
785: } else if (!((PetscObject)linesearch)->type_name) {
786: PetscCall(SNESLineSearchSetType(linesearch, deft));
787: }
789: PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)linesearch), ((PetscObject)linesearch)->options, ((PetscObject)linesearch)->prefix, "-snes_linesearch_monitor", &viewer, NULL, &set));
790: if (set) {
791: PetscCall(SNESLineSearchSetDefaultMonitor(linesearch, viewer));
792: PetscCall(PetscViewerDestroy(&viewer));
793: }
794: PetscCall(SNESLineSearchMonitorSetFromOptions(linesearch, "-snes_linesearch_monitor_solution_update", "View correction at each iteration", "SNESLineSearchMonitorSolutionUpdate", SNESLineSearchMonitorSolutionUpdate, NULL));
796: /* tolerances */
797: PetscCall(PetscOptionsReal("-snes_linesearch_minlambda", "Minimum step length", "SNESLineSearchSetTolerances", linesearch->steptol, &linesearch->steptol, NULL));
798: PetscCall(PetscOptionsReal("-snes_linesearch_maxstep", "Maximum step size", "SNESLineSearchSetTolerances", linesearch->maxstep, &linesearch->maxstep, NULL));
799: PetscCall(PetscOptionsReal("-snes_linesearch_rtol", "Relative tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->rtol, &linesearch->rtol, NULL));
800: PetscCall(PetscOptionsReal("-snes_linesearch_atol", "Absolute tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->atol, &linesearch->atol, NULL));
801: PetscCall(PetscOptionsReal("-snes_linesearch_ltol", "Change in lambda tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->ltol, &linesearch->ltol, NULL));
802: PetscCall(PetscOptionsInt("-snes_linesearch_max_it", "Maximum iterations for iterative line searches", "SNESLineSearchSetTolerances", linesearch->max_its, &linesearch->max_its, NULL));
804: /* damping parameters */
805: PetscCall(PetscOptionsReal("-snes_linesearch_damping", "Line search damping and initial step guess", "SNESLineSearchSetDamping", linesearch->damping, &linesearch->damping, NULL));
807: PetscCall(PetscOptionsBool("-snes_linesearch_keeplambda", "Use previous lambda as damping", "SNESLineSearchSetKeepLambda", linesearch->keeplambda, &linesearch->keeplambda, NULL));
809: /* precheck */
810: PetscCall(PetscOptionsBool("-snes_linesearch_precheck_picard", "Use a correction that sometimes improves convergence of Picard iteration", "SNESLineSearchPreCheckPicard", flg, &flg, &set));
811: if (set) {
812: if (flg) {
813: linesearch->precheck_picard_angle = 10.; /* correction only active if angle is less than 10 degrees */
815: PetscCall(PetscOptionsReal("-snes_linesearch_precheck_picard_angle", "Maximum angle at which to activate the correction", "none", linesearch->precheck_picard_angle, &linesearch->precheck_picard_angle, NULL));
816: PetscCall(SNESLineSearchSetPreCheck(linesearch, SNESLineSearchPreCheckPicard, &linesearch->precheck_picard_angle));
817: } else {
818: PetscCall(SNESLineSearchSetPreCheck(linesearch, NULL, NULL));
819: }
820: }
821: PetscCall(PetscOptionsInt("-snes_linesearch_order", "Order of approximation used in the line search", "SNESLineSearchSetOrder", linesearch->order, &linesearch->order, NULL));
822: PetscCall(PetscOptionsBool("-snes_linesearch_norms", "Compute final norms in line search", "SNESLineSearchSetComputeNorms", linesearch->norms, &linesearch->norms, NULL));
824: PetscTryTypeMethod(linesearch, setfromoptions, PetscOptionsObject);
826: PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)linesearch, PetscOptionsObject));
827: PetscOptionsEnd();
828: PetscFunctionReturn(PETSC_SUCCESS);
829: }
831: /*@
832: SNESLineSearchView - Prints useful information about the line search
834: Logically Collective
836: Input Parameters:
837: + linesearch - linesearch context
838: - viewer - the viewer to display the line search information
840: Level: intermediate
842: .seealso: `SNESLineSearch`, `PetscViewer`, `SNESLineSearchCreate()`
843: @*/
844: PetscErrorCode SNESLineSearchView(SNESLineSearch linesearch, PetscViewer viewer)
845: {
846: PetscBool iascii;
848: PetscFunctionBegin;
850: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)linesearch), &viewer));
852: PetscCheckSameComm(linesearch, 1, viewer, 2);
854: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
855: if (iascii) {
856: PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)linesearch, viewer));
857: PetscCall(PetscViewerASCIIPushTab(viewer));
858: PetscTryTypeMethod(linesearch, view, viewer);
859: PetscCall(PetscViewerASCIIPopTab(viewer));
860: PetscCall(PetscViewerASCIIPrintf(viewer, " maxstep=%e, minlambda=%e\n", (double)linesearch->maxstep, (double)linesearch->steptol));
861: PetscCall(PetscViewerASCIIPrintf(viewer, " tolerances: relative=%e, absolute=%e, lambda=%e\n", (double)linesearch->rtol, (double)linesearch->atol, (double)linesearch->ltol));
862: PetscCall(PetscViewerASCIIPrintf(viewer, " maximum iterations=%" PetscInt_FMT "\n", linesearch->max_its));
863: if (linesearch->ops->precheck) {
864: if (linesearch->ops->precheck == SNESLineSearchPreCheckPicard) {
865: PetscCall(PetscViewerASCIIPrintf(viewer, " using precheck step to speed up Picard convergence\n"));
866: } else {
867: PetscCall(PetscViewerASCIIPrintf(viewer, " using user-defined precheck step\n"));
868: }
869: }
870: if (linesearch->ops->postcheck) PetscCall(PetscViewerASCIIPrintf(viewer, " using user-defined postcheck step\n"));
871: }
872: PetscFunctionReturn(PETSC_SUCCESS);
873: }
875: /*@C
876: SNESLineSearchGetType - Gets the linesearch type
878: Logically Collective
880: Input Parameter:
881: . linesearch - linesearch context
883: Output Parameter:
884: . type - The type of line search, or `NULL` if not set
886: Level: intermediate
888: .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchType`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchSetType()`
889: @*/
890: PetscErrorCode SNESLineSearchGetType(SNESLineSearch linesearch, SNESLineSearchType *type)
891: {
892: PetscFunctionBegin;
895: *type = ((PetscObject)linesearch)->type_name;
896: PetscFunctionReturn(PETSC_SUCCESS);
897: }
899: /*@C
900: SNESLineSearchSetType - Sets the linesearch type
902: Logically Collective
904: Input Parameters:
905: + linesearch - linesearch context
906: - type - The type of line search to be used
908: Available Types:
909: + `SNESLINESEARCHBASIC` - (or equivalently `SNESLINESEARCHNONE`) Simple damping line search, defaults to using the full Newton step
910: . `SNESLINESEARCHBT` - Backtracking line search over the L2 norm of the function
911: . `SNESLINESEARCHL2` - Secant line search over the L2 norm of the function
912: . `SNESLINESEARCHCP` - Critical point secant line search assuming F(x) = grad G(x) for some unknown G(x)
913: . `SNESLINESEARCHNLEQERR` - Affine-covariant error-oriented linesearch
914: - `SNESLINESEARCHSHELL` - User provided `SNESLineSearch` implementation
916: Options Database Key:
917: . -snes_linesearch_type <type> - basic (or equivalently none), bt, l2, cp, nleqerr, shell
919: Level: intermediate
921: .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchType`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchGetType()`
922: @*/
923: PetscErrorCode SNESLineSearchSetType(SNESLineSearch linesearch, SNESLineSearchType type)
924: {
925: PetscBool match;
926: PetscErrorCode (*r)(SNESLineSearch);
928: PetscFunctionBegin;
932: PetscCall(PetscObjectTypeCompare((PetscObject)linesearch, type, &match));
933: if (match) PetscFunctionReturn(PETSC_SUCCESS);
935: PetscCall(PetscFunctionListFind(SNESLineSearchList, type, &r));
936: PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Line Search type %s", type);
937: /* Destroy the previous private linesearch context */
938: if (linesearch->ops->destroy) {
939: PetscCall((*(linesearch)->ops->destroy)(linesearch));
940: linesearch->ops->destroy = NULL;
941: }
942: /* Reinitialize function pointers in SNESLineSearchOps structure */
943: linesearch->ops->apply = NULL;
944: linesearch->ops->view = NULL;
945: linesearch->ops->setfromoptions = NULL;
946: linesearch->ops->destroy = NULL;
948: PetscCall(PetscObjectChangeTypeName((PetscObject)linesearch, type));
949: PetscCall((*r)(linesearch));
950: PetscFunctionReturn(PETSC_SUCCESS);
951: }
953: /*@
954: SNESLineSearchSetSNES - Sets the `SNES` for the linesearch for function evaluation.
956: Input Parameters:
957: + linesearch - linesearch context
958: - snes - The snes instance
960: Level: developer
962: Note:
963: This happens automatically when the line search is obtained/created with
964: `SNESGetLineSearch()`. This routine is therefore mainly called within `SNES`
965: implementations.
967: .seealso: `SNESLineSearch`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`, `SNES`
968: @*/
969: PetscErrorCode SNESLineSearchSetSNES(SNESLineSearch linesearch, SNES snes)
970: {
971: PetscFunctionBegin;
974: linesearch->snes = snes;
975: PetscFunctionReturn(PETSC_SUCCESS);
976: }
978: /*@
979: SNESLineSearchGetSNES - Gets the `SNES` instance associated with the line search.
980: Having an associated `SNES` is necessary because most line search implementations must be able to
981: evaluate the function using `SNESComputeFunction()` for the associated `SNES`. This routine
982: is used in the line search implementations when one must get this associated `SNES` instance.
984: Not Collective
986: Input Parameter:
987: . linesearch - linesearch context
989: Output Parameter:
990: . snes - The `SNES` instance
992: Level: developer
994: .seealso: `SNESLineSearch`, `SNESType`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`, `SNES`
995: @*/
996: PetscErrorCode SNESLineSearchGetSNES(SNESLineSearch linesearch, SNES *snes)
997: {
998: PetscFunctionBegin;
1001: *snes = linesearch->snes;
1002: PetscFunctionReturn(PETSC_SUCCESS);
1003: }
1005: /*@
1006: SNESLineSearchGetLambda - Gets the last linesearch steplength discovered.
1008: Not Collective
1010: Input Parameter:
1011: . linesearch - linesearch context
1013: Output Parameter:
1014: . lambda - The last steplength computed during `SNESLineSearchApply()`
1016: Level: advanced
1018: Note:
1019: This is useful in methods where the solver is ill-scaled and
1020: requires some adaptive notion of the difference in scale between the
1021: solution and the function. For instance, `SNESQN` may be scaled by the
1022: line search lambda using the argument -snes_qn_scaling ls.
1024: .seealso: `SNESLineSearch`, `SNESLineSearchSetLambda()`, `SNESLineSearchGetDamping()`, `SNESLineSearchApply()`
1025: @*/
1026: PetscErrorCode SNESLineSearchGetLambda(SNESLineSearch linesearch, PetscReal *lambda)
1027: {
1028: PetscFunctionBegin;
1031: *lambda = linesearch->lambda;
1032: PetscFunctionReturn(PETSC_SUCCESS);
1033: }
1035: /*@
1036: SNESLineSearchSetLambda - Sets the linesearch steplength
1038: Input Parameters:
1039: + linesearch - linesearch context
1040: - lambda - The last steplength.
1042: Level: advanced
1044: Note:
1045: This routine is typically used within implementations of `SNESLineSearchApply()`
1046: to set the final steplength. This routine (and `SNESLineSearchGetLambda()`) were
1047: added in order to facilitate Quasi-Newton methods that use the previous steplength
1048: as an inner scaling parameter.
1050: .seealso: `SNESLineSearch`, `SNESLineSearchGetLambda()`
1051: @*/
1052: PetscErrorCode SNESLineSearchSetLambda(SNESLineSearch linesearch, PetscReal lambda)
1053: {
1054: PetscFunctionBegin;
1056: linesearch->lambda = lambda;
1057: PetscFunctionReturn(PETSC_SUCCESS);
1058: }
1060: /*@
1061: SNESLineSearchGetTolerances - Gets the tolerances for the linesearch. These include
1062: tolerances for the relative and absolute change in the function norm, the change
1063: in lambda for iterative line searches, the minimum steplength, the maximum steplength,
1064: and the maximum number of iterations the line search procedure may take.
1066: Not Collective
1068: Input Parameter:
1069: . linesearch - linesearch context
1071: Output Parameters:
1072: + steptol - The minimum steplength
1073: . maxstep - The maximum steplength
1074: . rtol - The relative tolerance for iterative line searches
1075: . atol - The absolute tolerance for iterative line searches
1076: . ltol - The change in lambda tolerance for iterative line searches
1077: - max_it - The maximum number of iterations of the line search
1079: Level: intermediate
1081: Note:
1082: Different line searches may implement these parameters slightly differently as
1083: the type requires.
1085: .seealso: `SNESLineSearch`, `SNESLineSearchSetTolerances()`
1086: @*/
1087: PetscErrorCode SNESLineSearchGetTolerances(SNESLineSearch linesearch, PetscReal *steptol, PetscReal *maxstep, PetscReal *rtol, PetscReal *atol, PetscReal *ltol, PetscInt *max_its)
1088: {
1089: PetscFunctionBegin;
1091: if (steptol) {
1093: *steptol = linesearch->steptol;
1094: }
1095: if (maxstep) {
1097: *maxstep = linesearch->maxstep;
1098: }
1099: if (rtol) {
1101: *rtol = linesearch->rtol;
1102: }
1103: if (atol) {
1105: *atol = linesearch->atol;
1106: }
1107: if (ltol) {
1109: *ltol = linesearch->ltol;
1110: }
1111: if (max_its) {
1113: *max_its = linesearch->max_its;
1114: }
1115: PetscFunctionReturn(PETSC_SUCCESS);
1116: }
1118: /*@
1119: SNESLineSearchSetTolerances - Gets the tolerances for the linesearch. These include
1120: tolerances for the relative and absolute change in the function norm, the change
1121: in lambda for iterative line searches, the minimum steplength, the maximum steplength,
1122: and the maximum number of iterations the line search procedure may take.
1124: Collective
1126: Input Parameters:
1127: + linesearch - linesearch context
1128: . steptol - The minimum steplength
1129: . maxstep - The maximum steplength
1130: . rtol - The relative tolerance for iterative line searches
1131: . atol - The absolute tolerance for iterative line searches
1132: . ltol - The change in lambda tolerance for iterative line searches
1133: - max_it - The maximum number of iterations of the line search
1135: Level: intermediate
1137: Note:
1138: The user may choose to not set any of the tolerances using `PETSC_DEFAULT` in
1139: place of an argument.
1141: .seealso: `SNESLineSearch`, `SNESLineSearchGetTolerances()`
1142: @*/
1143: PetscErrorCode SNESLineSearchSetTolerances(SNESLineSearch linesearch, PetscReal steptol, PetscReal maxstep, PetscReal rtol, PetscReal atol, PetscReal ltol, PetscInt max_its)
1144: {
1145: PetscFunctionBegin;
1154: if (steptol != (PetscReal)PETSC_DEFAULT) {
1155: PetscCheck(steptol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Minimum step length %14.12e must be non-negative", (double)steptol);
1156: linesearch->steptol = steptol;
1157: }
1159: if (maxstep != (PetscReal)PETSC_DEFAULT) {
1160: PetscCheck(maxstep >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum step length %14.12e must be non-negative", (double)maxstep);
1161: linesearch->maxstep = maxstep;
1162: }
1164: if (rtol != (PetscReal)PETSC_DEFAULT) {
1165: PetscCheck(rtol >= 0.0 && rtol < 1.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Relative tolerance %14.12e must be non-negative and less than 1.0", (double)rtol);
1166: linesearch->rtol = rtol;
1167: }
1169: if (atol != (PetscReal)PETSC_DEFAULT) {
1170: PetscCheck(atol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %14.12e must be non-negative", (double)atol);
1171: linesearch->atol = atol;
1172: }
1174: if (ltol != (PetscReal)PETSC_DEFAULT) {
1175: PetscCheck(ltol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Lambda tolerance %14.12e must be non-negative", (double)ltol);
1176: linesearch->ltol = ltol;
1177: }
1179: if (max_its != PETSC_DEFAULT) {
1180: PetscCheck(max_its >= 0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations %" PetscInt_FMT " must be non-negative", max_its);
1181: linesearch->max_its = max_its;
1182: }
1183: PetscFunctionReturn(PETSC_SUCCESS);
1184: }
1186: /*@
1187: SNESLineSearchGetDamping - Gets the line search damping parameter.
1189: Input Parameter:
1190: . linesearch - linesearch context
1192: Output Parameter:
1193: . damping - The damping parameter
1195: Level: advanced
1197: .seealso: `SNESLineSearchGetStepTolerance()`, `SNESQN`
1198: @*/
1200: PetscErrorCode SNESLineSearchGetDamping(SNESLineSearch linesearch, PetscReal *damping)
1201: {
1202: PetscFunctionBegin;
1205: *damping = linesearch->damping;
1206: PetscFunctionReturn(PETSC_SUCCESS);
1207: }
1209: /*@
1210: SNESLineSearchSetDamping - Sets the line search damping parameter.
1212: Input Parameters:
1213: + linesearch - linesearch context
1214: - damping - The damping parameter
1216: Options Database Key:
1217: . -snes_linesearch_damping <damping> - the damping value
1219: Level: intermediate
1221: Note:
1222: The `SNESLINESEARCHNONE` line search merely takes the update step scaled by the damping parameter.
1223: The use of the damping parameter in the l2 and cp line searches is much more subtle;
1224: it is used as a starting point in calculating the secant step. However, the eventual
1225: step may be of greater length than the damping parameter. In the bt line search it is
1226: used as the maximum possible step length, as the bt line search only backtracks.
1228: .seealso: `SNESLineSearch`, `SNESLineSearchGetDamping()`
1229: @*/
1230: PetscErrorCode SNESLineSearchSetDamping(SNESLineSearch linesearch, PetscReal damping)
1231: {
1232: PetscFunctionBegin;
1234: linesearch->damping = damping;
1235: PetscFunctionReturn(PETSC_SUCCESS);
1236: }
1238: /*@
1239: SNESLineSearchGetOrder - Gets the line search approximation order.
1241: Input Parameter:
1242: . linesearch - linesearch context
1244: Output Parameter:
1245: . order - The order
1247: Possible Values for order:
1248: + 1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
1249: . 2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
1250: - 3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order
1252: Level: intermediate
1254: .seealso: `SNESLineSearch`, `SNESLineSearchSetOrder()`
1255: @*/
1257: PetscErrorCode SNESLineSearchGetOrder(SNESLineSearch linesearch, PetscInt *order)
1258: {
1259: PetscFunctionBegin;
1262: *order = linesearch->order;
1263: PetscFunctionReturn(PETSC_SUCCESS);
1264: }
1266: /*@
1267: SNESLineSearchSetOrder - Sets the maximum order of the polynomial fit used in the line search
1269: Input Parameters:
1270: + linesearch - linesearch context
1271: - order - The damping parameter
1273: Level: intermediate
1275: Possible Values for order:
1276: + 1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
1277: . 2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
1278: - 3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order
1280: Notes:
1281: Variable orders are supported by the following line searches:
1282: + bt - cubic and quadratic
1283: - cp - linear and quadratic
1285: .seealso: `SNESLineSearch`, `SNESLineSearchGetOrder()`, `SNESLineSearchSetDamping()`
1286: @*/
1287: PetscErrorCode SNESLineSearchSetOrder(SNESLineSearch linesearch, PetscInt order)
1288: {
1289: PetscFunctionBegin;
1291: linesearch->order = order;
1292: PetscFunctionReturn(PETSC_SUCCESS);
1293: }
1295: /*@
1296: SNESLineSearchGetNorms - Gets the norms for for X, Y, and F.
1298: Not Collective
1300: Input Parameter:
1301: . linesearch - linesearch context
1303: Output Parameters:
1304: + xnorm - The norm of the current solution
1305: . fnorm - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution.
1306: - ynorm - The norm of the current update
1308: Level: developer
1310: Note:
1311: Some values may not be up to date at particular points in the code.
1313: This, in combination with `SNESLineSearchSetNorms()`, allow the line search and the `SNESSolve_XXX()` to share
1314: computed values.
1316: .seealso: `SNESLineSearch`, `SNESLineSearchSetNorms()` `SNESLineSearchGetVecs()`
1317: @*/
1318: PetscErrorCode SNESLineSearchGetNorms(SNESLineSearch linesearch, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm)
1319: {
1320: PetscFunctionBegin;
1322: if (xnorm) *xnorm = linesearch->xnorm;
1323: if (fnorm) *fnorm = linesearch->fnorm;
1324: if (ynorm) *ynorm = linesearch->ynorm;
1325: PetscFunctionReturn(PETSC_SUCCESS);
1326: }
1328: /*@
1329: SNESLineSearchSetNorms - Gets the computed norms for for X, Y, and F.
1331: Collective
1333: Input Parameters:
1334: + linesearch - linesearch context
1335: . xnorm - The norm of the current solution
1336: . fnorm - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution
1337: - ynorm - The norm of the current update
1339: Level: developer
1341: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1342: @*/
1343: PetscErrorCode SNESLineSearchSetNorms(SNESLineSearch linesearch, PetscReal xnorm, PetscReal fnorm, PetscReal ynorm)
1344: {
1345: PetscFunctionBegin;
1347: linesearch->xnorm = xnorm;
1348: linesearch->fnorm = fnorm;
1349: linesearch->ynorm = ynorm;
1350: PetscFunctionReturn(PETSC_SUCCESS);
1351: }
1353: /*@
1354: SNESLineSearchComputeNorms - Computes the norms of X, F, and Y.
1356: Input Parameter:
1357: . linesearch - linesearch context
1359: Options Database Key:
1360: . -snes_linesearch_norms - turn norm computation on or off
1362: Level: intermediate
1364: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms`, `SNESLineSearchSetNorms()`, `SNESLineSearchSetComputeNorms()`
1365: @*/
1366: PetscErrorCode SNESLineSearchComputeNorms(SNESLineSearch linesearch)
1367: {
1368: SNES snes;
1370: PetscFunctionBegin;
1371: if (linesearch->norms) {
1372: if (linesearch->ops->vinorm) {
1373: PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
1374: PetscCall(VecNorm(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1375: PetscCall(VecNorm(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1376: PetscCall((*linesearch->ops->vinorm)(snes, linesearch->vec_func, linesearch->vec_sol, &linesearch->fnorm));
1377: } else {
1378: PetscCall(VecNormBegin(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1379: PetscCall(VecNormBegin(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1380: PetscCall(VecNormBegin(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1381: PetscCall(VecNormEnd(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1382: PetscCall(VecNormEnd(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1383: PetscCall(VecNormEnd(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1384: }
1385: }
1386: PetscFunctionReturn(PETSC_SUCCESS);
1387: }
1389: /*@
1390: SNESLineSearchSetComputeNorms - Turns on or off the computation of final norms in the line search.
1392: Input Parameters:
1393: + linesearch - linesearch context
1394: - flg - indicates whether or not to compute norms
1396: Options Database Key:
1397: . -snes_linesearch_norms <true> - Turns on/off computation of the norms for basic (none) linesearch
1399: Level: intermediate
1401: Note:
1402: This is most relevant to the `SNESLINESEARCHBASIC` (or equivalently `SNESLINESEARCHNONE`) line search type since most line searches have a stopping criteria involving the norm.
1404: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetNorms()`, `SNESLineSearchComputeNorms()`, `SNESLINESEARCHBASIC`
1405: @*/
1406: PetscErrorCode SNESLineSearchSetComputeNorms(SNESLineSearch linesearch, PetscBool flg)
1407: {
1408: PetscFunctionBegin;
1409: linesearch->norms = flg;
1410: PetscFunctionReturn(PETSC_SUCCESS);
1411: }
1413: /*@
1414: SNESLineSearchGetVecs - Gets the vectors from the `SNESLineSearch` context
1416: Not Collective on but the vectors are parallel
1418: Input Parameter:
1419: . linesearch - linesearch context
1421: Output Parameters:
1422: + X - Solution vector
1423: . F - Function vector
1424: . Y - Search direction vector
1425: . W - Solution work vector
1426: - G - Function work vector
1428: Level: advanced
1430: Notes:
1431: At the beginning of a line search application, `X` should contain a
1432: solution and the vector `F` the function computed at `X`. At the end of the
1433: line search application, `X` should contain the new solution, and `F` the
1434: function evaluated at the new solution.
1436: These vectors are owned by the `SNESLineSearch` and should not be destroyed by the caller
1438: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1439: @*/
1440: PetscErrorCode SNESLineSearchGetVecs(SNESLineSearch linesearch, Vec *X, Vec *F, Vec *Y, Vec *W, Vec *G)
1441: {
1442: PetscFunctionBegin;
1444: if (X) {
1446: *X = linesearch->vec_sol;
1447: }
1448: if (F) {
1450: *F = linesearch->vec_func;
1451: }
1452: if (Y) {
1454: *Y = linesearch->vec_update;
1455: }
1456: if (W) {
1458: *W = linesearch->vec_sol_new;
1459: }
1460: if (G) {
1462: *G = linesearch->vec_func_new;
1463: }
1464: PetscFunctionReturn(PETSC_SUCCESS);
1465: }
1467: /*@
1468: SNESLineSearchSetVecs - Sets the vectors on the `SNESLineSearch` context
1470: Logically Collective
1472: Input Parameters:
1473: + linesearch - linesearch context
1474: . X - Solution vector
1475: . F - Function vector
1476: . Y - Search direction vector
1477: . W - Solution work vector
1478: - G - Function work vector
1480: Level: advanced
1482: .seealso: `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
1483: @*/
1484: PetscErrorCode SNESLineSearchSetVecs(SNESLineSearch linesearch, Vec X, Vec F, Vec Y, Vec W, Vec G)
1485: {
1486: PetscFunctionBegin;
1488: if (X) {
1490: linesearch->vec_sol = X;
1491: }
1492: if (F) {
1494: linesearch->vec_func = F;
1495: }
1496: if (Y) {
1498: linesearch->vec_update = Y;
1499: }
1500: if (W) {
1502: linesearch->vec_sol_new = W;
1503: }
1504: if (G) {
1506: linesearch->vec_func_new = G;
1507: }
1508: PetscFunctionReturn(PETSC_SUCCESS);
1509: }
1511: /*@C
1512: SNESLineSearchAppendOptionsPrefix - Appends to the prefix used for searching for all
1513: `SNESLineSearch` options in the database.
1515: Logically Collective
1517: Input Parameters:
1518: + linesearch - the `SNESLineSearch` context
1519: - prefix - the prefix to prepend to all option names
1521: Level: advanced
1523: Note:
1524: A hyphen (-) must NOT be given at the beginning of the prefix name.
1525: The first character of all runtime options is AUTOMATICALLY the hyphen.
1527: .seealso: `SNESLineSearch()`, `SNESLineSearchSetFromOptions()`, `SNESGetOptionsPrefix()`
1528: @*/
1529: PetscErrorCode SNESLineSearchAppendOptionsPrefix(SNESLineSearch linesearch, const char prefix[])
1530: {
1531: PetscFunctionBegin;
1533: PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)linesearch, prefix));
1534: PetscFunctionReturn(PETSC_SUCCESS);
1535: }
1537: /*@C
1538: SNESLineSearchGetOptionsPrefix - Gets the prefix used for searching for all
1539: SNESLineSearch options in the database.
1541: Not Collective
1543: Input Parameter:
1544: . linesearch - the `SNESLineSearch` context
1546: Output Parameter:
1547: . prefix - pointer to the prefix string used
1549: Level: advanced
1551: Fortran Note:
1552: The user should pass in a string 'prefix' of
1553: sufficient length to hold the prefix.
1555: .seealso: `SNESLineSearch`, `SNESAppendOptionsPrefix()`
1556: @*/
1557: PetscErrorCode SNESLineSearchGetOptionsPrefix(SNESLineSearch linesearch, const char *prefix[])
1558: {
1559: PetscFunctionBegin;
1561: PetscCall(PetscObjectGetOptionsPrefix((PetscObject)linesearch, prefix));
1562: PetscFunctionReturn(PETSC_SUCCESS);
1563: }
1565: /*@C
1566: SNESLineSearchSetWorkVecs - Sets work vectors for the line search.
1568: Input Parameters:
1569: + linesearch - the `SNESLineSearch` context
1570: - nwork - the number of work vectors
1572: Level: developer
1574: .seealso: `SNESLineSearch`, `SNESSetWorkVecs()`
1575: @*/
1576: PetscErrorCode SNESLineSearchSetWorkVecs(SNESLineSearch linesearch, PetscInt nwork)
1577: {
1578: PetscFunctionBegin;
1579: PetscCheck(linesearch->vec_sol, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "Cannot get linesearch work-vectors without setting a solution vec!");
1580: PetscCall(VecDuplicateVecs(linesearch->vec_sol, nwork, &linesearch->work));
1581: PetscFunctionReturn(PETSC_SUCCESS);
1582: }
1584: /*@
1585: SNESLineSearchGetReason - Gets the success/failure status of the last line search application
1587: Input Parameter:
1588: . linesearch - linesearch context
1590: Output Parameter:
1591: . result - The success or failure status
1593: Level: developer
1595: Note:
1596: This is typically called after `SNESLineSearchApply()` in order to determine if the line-search failed
1597: (and set the SNES convergence accordingly).
1599: .seealso: `SNESLineSearch`, `SNESLineSearchSetReason()`, `SNESLineSearchReason`
1600: @*/
1601: PetscErrorCode SNESLineSearchGetReason(SNESLineSearch linesearch, SNESLineSearchReason *result)
1602: {
1603: PetscFunctionBegin;
1606: *result = linesearch->result;
1607: PetscFunctionReturn(PETSC_SUCCESS);
1608: }
1610: /*@
1611: SNESLineSearchSetReason - Sets the success/failure status of the last line search application
1613: Input Parameters:
1614: + linesearch - linesearch context
1615: - result - The success or failure status
1617: Level: developer
1619: Note:
1620: This is typically called in a `SNESLineSearchApply()` or a `SNESLINESEARCHSHELL` implementation to set
1621: the success or failure of the line search method.
1623: .seealso: `SNESLineSearch`, `SNESLineSearchReason`, `SNESLineSearchGetSResult()`
1624: @*/
1625: PetscErrorCode SNESLineSearchSetReason(SNESLineSearch linesearch, SNESLineSearchReason result)
1626: {
1627: PetscFunctionBegin;
1629: linesearch->result = result;
1630: PetscFunctionReturn(PETSC_SUCCESS);
1631: }
1633: /*@C
1634: SNESLineSearchSetVIFunctions - Sets VI-specific functions for line search computation.
1636: Logically Collective
1638: Input Parameters:
1639: + snes - nonlinear context obtained from `SNESCreate()`
1640: . projectfunc - function for projecting the function to the bounds
1641: - normfunc - function for computing the norm of an active set
1643: Calling sequence of `projectfunc`:
1644: .vb
1645: PetscErrorCode projectfunc(SNES snes, Vec X)
1646: .ve
1647: + snes - nonlinear context
1648: - X - current solution, store the projected solution here
1650: Calling sequence of `normfunc`:
1651: .vb
1652: PetscErrorCode normfunc(SNES snes, Vec X, Vec F, PetscScalar *fnorm)
1653: .ve
1654: + snes - nonlinear context
1655: . X - current solution
1656: . F - current residual
1657: - fnorm - VI-specific norm of the function
1659: Level: advanced
1661: Note:
1662: The VI solvers require projection of the solution to the feasible set. `projectfunc` should implement this.
1664: The VI solvers require special evaluation of the function norm such that the norm is only calculated
1665: on the inactive set. This should be implemented by `normfunc`.
1667: .seealso: `SNESLineSearch`, `SNESLineSearchGetVIFunctions()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`
1668: @*/
1669: PetscErrorCode SNESLineSearchSetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFunc projectfunc, SNESLineSearchVINormFunc normfunc)
1670: {
1671: PetscFunctionBegin;
1673: if (projectfunc) linesearch->ops->viproject = projectfunc;
1674: if (normfunc) linesearch->ops->vinorm = normfunc;
1675: PetscFunctionReturn(PETSC_SUCCESS);
1676: }
1678: /*@C
1679: SNESLineSearchGetVIFunctions - Sets VI-specific functions for line search computation.
1681: Not Collective
1683: Input Parameter:
1684: . linesearch - the line search context, obtain with `SNESGetLineSearch()`
1686: Output Parameters:
1687: + projectfunc - function for projecting the function to the bounds
1688: - normfunc - function for computing the norm of an active set
1690: Level: advanced
1692: .seealso: `SNESLineSearch`, `SNESLineSearchSetVIFunctions()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`
1693: @*/
1694: PetscErrorCode SNESLineSearchGetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFunc *projectfunc, SNESLineSearchVINormFunc *normfunc)
1695: {
1696: PetscFunctionBegin;
1697: if (projectfunc) *projectfunc = linesearch->ops->viproject;
1698: if (normfunc) *normfunc = linesearch->ops->vinorm;
1699: PetscFunctionReturn(PETSC_SUCCESS);
1700: }
1702: /*@C
1703: SNESLineSearchRegister - register a line search method
1705: Level: advanced
1707: .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchSetType()`
1708: @*/
1709: PetscErrorCode SNESLineSearchRegister(const char sname[], PetscErrorCode (*function)(SNESLineSearch))
1710: {
1711: PetscFunctionBegin;
1712: PetscCall(SNESInitializePackage());
1713: PetscCall(PetscFunctionListAdd(&SNESLineSearchList, sname, function));
1714: PetscFunctionReturn(PETSC_SUCCESS);
1715: }