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 Notes:
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;
170: PetscAssertPointer(outlinesearch, 2);
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: @*/
224: PetscErrorCode SNESLineSearchSetUp(SNESLineSearch linesearch)
225: {
226: PetscFunctionBegin;
227: if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC));
228: if (!linesearch->setupcalled) {
229: if (!linesearch->vec_sol_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_sol_new));
230: if (!linesearch->vec_func_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_func_new));
231: if (linesearch->ops->setup) PetscUseTypeMethod(linesearch, setup);
232: if (!linesearch->ops->snesfunc) PetscCall(SNESLineSearchSetFunction(linesearch, SNESComputeFunction));
233: linesearch->lambda = linesearch->damping;
234: linesearch->setupcalled = PETSC_TRUE;
235: }
236: PetscFunctionReturn(PETSC_SUCCESS);
237: }
239: /*@
240: SNESLineSearchReset - Undoes the `SNESLineSearchSetUp()` and deletes any `Vec`s or `Mat`s allocated by the line search.
242: Collective
244: Input Parameter:
245: . linesearch - The `SNESLineSearch` instance.
247: Level: developer
249: Note:
250: Usually only called by `SNESReset()`
252: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetUp()`
253: @*/
254: PetscErrorCode SNESLineSearchReset(SNESLineSearch linesearch)
255: {
256: PetscFunctionBegin;
257: if (linesearch->ops->reset) PetscUseTypeMethod(linesearch, reset);
259: PetscCall(VecDestroy(&linesearch->vec_sol_new));
260: PetscCall(VecDestroy(&linesearch->vec_func_new));
262: PetscCall(VecDestroyVecs(linesearch->nwork, &linesearch->work));
264: linesearch->nwork = 0;
265: linesearch->setupcalled = PETSC_FALSE;
266: PetscFunctionReturn(PETSC_SUCCESS);
267: }
269: /*@C
270: SNESLineSearchSetFunction - Sets the function evaluation used by the `SNES` line search
271: `
273: Input Parameters:
274: + linesearch - the `SNESLineSearch` context
275: - func - function evaluation routine, this is usually the function provided with `SNESSetFunction()`
277: Level: developer
279: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESSetFunction()`
280: @*/
281: PetscErrorCode SNESLineSearchSetFunction(SNESLineSearch linesearch, PetscErrorCode (*func)(SNES, Vec, Vec))
282: {
283: PetscFunctionBegin;
285: linesearch->ops->snesfunc = func;
286: PetscFunctionReturn(PETSC_SUCCESS);
287: }
289: /*@C
290: SNESLineSearchSetPreCheck - Sets a user function that is called after the initial search direction has been computed but
291: before the line search routine has been applied. Allows the user to adjust the result of (usually a linear solve) that
292: determined the search direction.
294: Logically Collective
296: Input Parameters:
297: + linesearch - the `SNESLineSearch` context
298: . func - [optional] function evaluation routine, for the calling sequence see `SNESLineSearchPreCheck()`
299: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
301: Level: intermediate
303: Note:
304: Use `SNESLineSearchSetPostCheck()` to change the step after the line search.
305: search is complete.
307: Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.
309: .seealso: `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
310: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()`
312: @*/
313: PetscErrorCode SNESLineSearchSetPreCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch, Vec, Vec, PetscBool *, void *), void *ctx)
314: {
315: PetscFunctionBegin;
317: if (func) linesearch->ops->precheck = func;
318: if (ctx) linesearch->precheckctx = ctx;
319: PetscFunctionReturn(PETSC_SUCCESS);
320: }
322: /*@C
323: SNESLineSearchGetPreCheck - Gets the pre-check function for the line search routine.
325: Input Parameter:
326: . linesearch - the `SNESLineSearch` context
328: Output Parameters:
329: + func - [optional] function evaluation routine, for calling sequence see `SNESLineSearchPreCheck`
330: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
332: Level: intermediate
334: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
335: @*/
336: PetscErrorCode SNESLineSearchGetPreCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, PetscBool *, void *), void **ctx)
337: {
338: PetscFunctionBegin;
340: if (func) *func = linesearch->ops->precheck;
341: if (ctx) *ctx = linesearch->precheckctx;
342: PetscFunctionReturn(PETSC_SUCCESS);
343: }
345: /*@C
346: SNESLineSearchSetPostCheck - Sets a user function that is called after the line search has been applied to determine the step
347: direction and length. Allows the user a chance to change or override the decision of the line search routine
349: Logically Collective
351: Input Parameters:
352: + linesearch - the `SNESLineSearch` context
353: . func - [optional] function evaluation routine, for the calling sequence see `SNESLineSearchPostCheck`
354: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
356: Level: intermediate
358: Notes:
359: Use `SNESLineSearchSetPreCheck()` to change the step before the line search.
360: search is complete.
362: Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.
364: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchGetPostCheck()`,
365: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()`
366: @*/
367: PetscErrorCode SNESLineSearchSetPostCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void *ctx)
368: {
369: PetscFunctionBegin;
371: if (func) linesearch->ops->postcheck = func;
372: if (ctx) linesearch->postcheckctx = ctx;
373: PetscFunctionReturn(PETSC_SUCCESS);
374: }
376: /*@C
377: SNESLineSearchGetPostCheck - Gets the post-check function for the line search routine.
379: Input Parameter:
380: . linesearch - the `SNESLineSearch` context
382: Output Parameters:
383: + func - [optional] function evaluation routine, see for the calling sequence `SNESLineSearchPostCheck`
384: - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
386: Level: intermediate
388: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`
389: @*/
390: PetscErrorCode SNESLineSearchGetPostCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void **ctx)
391: {
392: PetscFunctionBegin;
394: if (func) *func = linesearch->ops->postcheck;
395: if (ctx) *ctx = linesearch->postcheckctx;
396: PetscFunctionReturn(PETSC_SUCCESS);
397: }
399: /*@
400: SNESLineSearchPreCheck - Prepares the line search for being applied.
402: Logically Collective
404: Input Parameters:
405: + linesearch - The linesearch instance.
406: . X - The current solution
407: - Y - The step direction
409: Output Parameter:
410: . changed - Indicator that the precheck routine has changed anything
412: Level: advanced
414: Note:
415: This calls any function provided with `SNESLineSearchSetPreCheck()`
417: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`,
418: `SNESLineSearchGetPostCheck()`
419: @*/
420: PetscErrorCode SNESLineSearchPreCheck(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed)
421: {
422: PetscFunctionBegin;
423: *changed = PETSC_FALSE;
424: if (linesearch->ops->precheck) {
425: PetscUseTypeMethod(linesearch, precheck, X, Y, changed, linesearch->precheckctx);
427: }
428: PetscFunctionReturn(PETSC_SUCCESS);
429: }
431: /*@
432: SNESLineSearchPostCheck - Hook to modify step direction or updated solution after a successful linesearch
434: Logically Collective
436: Input Parameters:
437: + linesearch - The linesearch context
438: . X - The last solution
439: . Y - The step direction
440: - W - The updated solution, W = X + lambda*Y for some lambda
442: Output Parameters:
443: + changed_Y - Indicator if the direction Y has been changed.
444: - changed_W - Indicator if the new candidate solution W has been changed.
446: Level: developer
448: Note:
449: This calls any function provided with `SNESLineSearchSetPreCheck()`
451: .seealso: `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPrecheck()`, `SNESLineSearchGetPrecheck()`
452: @*/
453: PetscErrorCode SNESLineSearchPostCheck(SNESLineSearch linesearch, Vec X, Vec Y, Vec W, PetscBool *changed_Y, PetscBool *changed_W)
454: {
455: PetscFunctionBegin;
456: *changed_Y = PETSC_FALSE;
457: *changed_W = PETSC_FALSE;
458: if (linesearch->ops->postcheck) {
459: PetscUseTypeMethod(linesearch, postcheck, X, Y, W, changed_Y, changed_W, linesearch->postcheckctx);
462: }
463: PetscFunctionReturn(PETSC_SUCCESS);
464: }
466: /*@C
467: SNESLineSearchPreCheckPicard - Implements a correction that is sometimes useful to improve the convergence rate of Picard iteration
469: Logically Collective
471: Input Parameters:
472: + linesearch - linesearch context
473: . X - base state for this step
474: - ctx - context for this function
476: Input/Output Parameter:
477: . Y - correction, possibly modified
479: Output Parameter:
480: . changed - flag indicating that Y was modified
482: Options Database Key:
483: + -snes_linesearch_precheck_picard - activate this routine
484: - -snes_linesearch_precheck_picard_angle - angle
486: Level: advanced
488: Notes:
489: This function should be passed to `SNESLineSearchSetPreCheck()`
491: The justification for this method involves the linear convergence of a Picard iteration
492: so the Picard linearization should be provided in place of the "Jacobian". This correction
493: is generally not useful when using a Newton linearization.
495: References:
496: . - * - Hindmarsh and Payne (1996) Time step limits for stable solutions of the ice sheet equation, Annals of Glaciology.
498: .seealso: `SNESLineSearch`, `SNESSetPicard()`, `SNESGetLineSearch()`, `SNESLineSearchSetPreCheck()`
499: @*/
500: PetscErrorCode SNESLineSearchPreCheckPicard(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed, void *ctx)
501: {
502: PetscReal angle = *(PetscReal *)linesearch->precheckctx;
503: Vec Ylast;
504: PetscScalar dot;
505: PetscInt iter;
506: PetscReal ynorm, ylastnorm, theta, angle_radians;
507: SNES snes;
509: PetscFunctionBegin;
510: PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
511: PetscCall(PetscObjectQuery((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject *)&Ylast));
512: if (!Ylast) {
513: PetscCall(VecDuplicate(Y, &Ylast));
514: PetscCall(PetscObjectCompose((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject)Ylast));
515: PetscCall(PetscObjectDereference((PetscObject)Ylast));
516: }
517: PetscCall(SNESGetIterationNumber(snes, &iter));
518: if (iter < 2) {
519: PetscCall(VecCopy(Y, Ylast));
520: *changed = PETSC_FALSE;
521: PetscFunctionReturn(PETSC_SUCCESS);
522: }
524: PetscCall(VecDot(Y, Ylast, &dot));
525: PetscCall(VecNorm(Y, NORM_2, &ynorm));
526: PetscCall(VecNorm(Ylast, NORM_2, &ylastnorm));
527: /* Compute the angle between the vectors Y and Ylast, clip to keep inside the domain of acos() */
528: theta = PetscAcosReal((PetscReal)PetscClipInterval(PetscAbsScalar(dot) / (ynorm * ylastnorm), -1.0, 1.0));
529: angle_radians = angle * PETSC_PI / 180.;
530: if (PetscAbsReal(theta) < angle_radians || PetscAbsReal(theta - PETSC_PI) < angle_radians) {
531: /* Modify the step Y */
532: PetscReal alpha, ydiffnorm;
533: PetscCall(VecAXPY(Ylast, -1.0, Y));
534: PetscCall(VecNorm(Ylast, NORM_2, &ydiffnorm));
535: alpha = (ydiffnorm > .001 * ylastnorm) ? ylastnorm / ydiffnorm : 1000.0;
536: PetscCall(VecCopy(Y, Ylast));
537: PetscCall(VecScale(Y, alpha));
538: 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));
539: *changed = PETSC_TRUE;
540: } else {
541: PetscCall(PetscInfo(snes, "Angle %14.12e degrees exceeds threshold %14.12e, no correction applied\n", (double)(theta * 180. / PETSC_PI), (double)angle));
542: PetscCall(VecCopy(Y, Ylast));
543: *changed = PETSC_FALSE;
544: }
545: PetscFunctionReturn(PETSC_SUCCESS);
546: }
548: /*@
549: SNESLineSearchApply - Computes the line-search update.
551: Collective
553: Input Parameters:
554: + linesearch - The linesearch context
555: - Y - The search direction
557: Input/Output Parameters:
558: + X - The current solution, on output the new solution
559: . F - The current function, on output the new function
560: - fnorm - The current norm, on output the new function norm
562: Options Database Keys:
563: + -snes_linesearch_type - basic (or equivalently none), bt, l2, cp, nleqerr, shell
564: . -snes_linesearch_monitor [:filename] - Print progress of line searches
565: . -snes_linesearch_damping - The linesearch damping parameter, default is 1.0 (no damping)
566: . -snes_linesearch_norms - Turn on/off the linesearch norms computation (SNESLineSearchSetComputeNorms())
567: . -snes_linesearch_keeplambda - Keep the previous search length as the initial guess
568: - -snes_linesearch_max_it - The number of iterations for iterative line searches
570: Level: intermediate
572: Notes:
573: This is typically called from within a `SNESSolve()` implementation in order to
574: help with convergence of the nonlinear method. Various `SNES` types use line searches
575: in different ways, but the overarching theme is that a line search is used to determine
576: an optimal damping parameter of a step at each iteration of the method. Each
577: application of the line search may invoke `SNESComputeFunction()` several times, and
578: therefore may be fairly expensive.
580: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchPreCheck()`, `SNESLineSearchPostCheck()`, `SNESSolve()`, `SNESComputeFunction()`, `SNESLineSearchSetComputeNorms()`,
581: `SNESLineSearchType`, `SNESLineSearchSetType()`
582: @*/
583: PetscErrorCode SNESLineSearchApply(SNESLineSearch linesearch, Vec X, Vec F, PetscReal *fnorm, Vec Y)
584: {
585: PetscFunctionBegin;
591: linesearch->result = SNES_LINESEARCH_SUCCEEDED;
593: linesearch->vec_sol = X;
594: linesearch->vec_update = Y;
595: linesearch->vec_func = F;
597: PetscCall(SNESLineSearchSetUp(linesearch));
599: if (!linesearch->keeplambda) linesearch->lambda = linesearch->damping; /* set the initial guess to lambda */
601: if (fnorm) linesearch->fnorm = *fnorm;
602: else PetscCall(VecNorm(F, NORM_2, &linesearch->fnorm));
604: PetscCall(PetscLogEventBegin(SNESLINESEARCH_Apply, linesearch, X, F, Y));
606: PetscUseTypeMethod(linesearch, apply);
608: PetscCall(PetscLogEventEnd(SNESLINESEARCH_Apply, linesearch, X, F, Y));
610: if (fnorm) *fnorm = linesearch->fnorm;
611: PetscFunctionReturn(PETSC_SUCCESS);
612: }
614: /*@
615: SNESLineSearchDestroy - Destroys the line search instance.
617: Collective
619: Input Parameter:
620: . linesearch - The linesearch context
622: Level: developer
624: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchReset()`, `SNESDestroy()`
625: @*/
626: PetscErrorCode SNESLineSearchDestroy(SNESLineSearch *linesearch)
627: {
628: PetscFunctionBegin;
629: if (!*linesearch) PetscFunctionReturn(PETSC_SUCCESS);
631: if (--((PetscObject)(*linesearch))->refct > 0) {
632: *linesearch = NULL;
633: PetscFunctionReturn(PETSC_SUCCESS);
634: }
635: PetscCall(PetscObjectSAWsViewOff((PetscObject)*linesearch));
636: PetscCall(SNESLineSearchReset(*linesearch));
637: PetscTryTypeMethod(*linesearch, destroy);
638: PetscCall(PetscViewerDestroy(&(*linesearch)->monitor));
639: PetscCall(SNESLineSearchMonitorCancel((*linesearch)));
640: PetscCall(PetscHeaderDestroy(linesearch));
641: PetscFunctionReturn(PETSC_SUCCESS);
642: }
644: /*@
645: SNESLineSearchSetDefaultMonitor - Turns on/off printing useful information and debugging output about the line search.
647: Logically Collective
649: Input Parameters:
650: + linesearch - the linesearch object
651: - viewer - an `PETSCVIEWERASCII` `PetscViewer` or `NULL` to turn off monitor
653: Options Database Key:
654: . -snes_linesearch_monitor [:filename] - enables the monitor
656: Level: intermediate
658: Developer Notes:
659: This monitor is implemented differently than the other line search monitors that are set with
660: `SNESLineSearchMonitorSet()` since it is called in many locations of the line search routines to display aspects of the
661: line search that are not visible to the other monitors.
663: .seealso: `SNESLineSearch`, `PETSCVIEWERASCII`, `SNESGetLineSearch()`, `SNESLineSearchGetDefaultMonitor()`, `PetscViewer`, `SNESLineSearchSetMonitor()`,
664: `SNESLineSearchMonitorSetFromOptions()`
665: @*/
666: PetscErrorCode SNESLineSearchSetDefaultMonitor(SNESLineSearch linesearch, PetscViewer viewer)
667: {
668: PetscFunctionBegin;
669: if (viewer) PetscCall(PetscObjectReference((PetscObject)viewer));
670: PetscCall(PetscViewerDestroy(&linesearch->monitor));
671: linesearch->monitor = viewer;
672: PetscFunctionReturn(PETSC_SUCCESS);
673: }
675: /*@
676: SNESLineSearchGetDefaultMonitor - Gets the `PetscViewer` instance for the line search monitor.
678: Logically Collective
680: Input Parameter:
681: . linesearch - linesearch context
683: Output Parameter:
684: . monitor - monitor context
686: Level: intermediate
688: .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetDefaultMonitor()`, `PetscViewer`
689: @*/
690: PetscErrorCode SNESLineSearchGetDefaultMonitor(SNESLineSearch linesearch, PetscViewer *monitor)
691: {
692: PetscFunctionBegin;
694: *monitor = linesearch->monitor;
695: PetscFunctionReturn(PETSC_SUCCESS);
696: }
698: /*@C
699: SNESLineSearchMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
701: Collective
703: Input Parameters:
704: + ls - `SNESLineSearch` object you wish to monitor
705: . name - the monitor type one is seeking
706: . help - message indicating what monitoring is done
707: . manual - manual page for the monitor
708: . monitor - the monitor function
709: - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `SNESLineSearch` or `PetscViewer`
711: Level: developer
713: .seealso: `SNESLineSearch`, `SNESLineSearchSetMonitor()`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
714: `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
715: `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
716: `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
717: `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
718: `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
719: `PetscOptionsFList()`, `PetscOptionsEList()`
720: @*/
721: PetscErrorCode SNESLineSearchMonitorSetFromOptions(SNESLineSearch ls, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(SNESLineSearch, PetscViewerAndFormat *), PetscErrorCode (*monitorsetup)(SNESLineSearch, PetscViewerAndFormat *))
722: {
723: PetscViewer viewer;
724: PetscViewerFormat format;
725: PetscBool flg;
727: PetscFunctionBegin;
728: PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)ls), ((PetscObject)ls)->options, ((PetscObject)ls)->prefix, name, &viewer, &format, &flg));
729: if (flg) {
730: PetscViewerAndFormat *vf;
731: PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
732: PetscCall(PetscObjectDereference((PetscObject)viewer));
733: if (monitorsetup) PetscCall((*monitorsetup)(ls, vf));
734: PetscCall(SNESLineSearchMonitorSet(ls, (PetscErrorCode(*)(SNESLineSearch, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
735: }
736: PetscFunctionReturn(PETSC_SUCCESS);
737: }
739: /*@
740: SNESLineSearchSetFromOptions - Sets options for the line search
742: Logically Collective
744: Input Parameter:
745: . linesearch - linesearch context
747: Options Database Keys:
748: + -snes_linesearch_type <type> - basic (or equivalently none), bt, l2, cp, nleqerr, shell
749: . -snes_linesearch_order <order> - 1, 2, 3. Most types only support certain orders (bt supports 2 or 3)
750: . -snes_linesearch_norms - Turn on/off the linesearch norms for the basic linesearch typem (`SNESLineSearchSetComputeNorms()`)
751: . -snes_linesearch_minlambda - The minimum step length
752: . -snes_linesearch_maxstep - The maximum step size
753: . -snes_linesearch_rtol - Relative tolerance for iterative line searches
754: . -snes_linesearch_atol - Absolute tolerance for iterative line searches
755: . -snes_linesearch_ltol - Change in lambda tolerance for iterative line searches
756: . -snes_linesearch_max_it - The number of iterations for iterative line searches
757: . -snes_linesearch_monitor [:filename] - Print progress of line searches
758: . -snes_linesearch_monitor_solution_update [viewer:filename:format] - view each update tried by line search routine
759: . -snes_linesearch_damping - The linesearch damping parameter
760: . -snes_linesearch_keeplambda - Keep the previous search length as the initial guess.
761: . -snes_linesearch_precheck_picard - Use precheck that speeds up convergence of picard method
762: - -snes_linesearch_precheck_picard_angle - Angle used in Picard precheck method
764: Level: intermediate
766: .seealso: `SNESLineSearch`, `SNESLineSearchCreate()`, `SNESLineSearchSetOrder()`, `SNESLineSearchSetType()`, `SNESLineSearchSetTolerances()`, `SNESLineSearchSetDamping()`, `SNESLineSearchPreCheckPicard()`,
767: `SNESLineSearchType`, `SNESLineSearchSetComputeNorms()`
768: @*/
769: PetscErrorCode SNESLineSearchSetFromOptions(SNESLineSearch linesearch)
770: {
771: const char *deft = SNESLINESEARCHBASIC;
772: char type[256];
773: PetscBool flg, set;
774: PetscViewer viewer;
776: PetscFunctionBegin;
777: PetscCall(SNESLineSearchRegisterAll());
779: PetscObjectOptionsBegin((PetscObject)linesearch);
780: if (((PetscObject)linesearch)->type_name) deft = ((PetscObject)linesearch)->type_name;
781: PetscCall(PetscOptionsFList("-snes_linesearch_type", "Linesearch type", "SNESLineSearchSetType", SNESLineSearchList, deft, type, 256, &flg));
782: if (flg) {
783: PetscCall(SNESLineSearchSetType(linesearch, type));
784: } else if (!((PetscObject)linesearch)->type_name) {
785: PetscCall(SNESLineSearchSetType(linesearch, deft));
786: }
788: PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)linesearch), ((PetscObject)linesearch)->options, ((PetscObject)linesearch)->prefix, "-snes_linesearch_monitor", &viewer, NULL, &set));
789: if (set) {
790: PetscCall(SNESLineSearchSetDefaultMonitor(linesearch, viewer));
791: PetscCall(PetscViewerDestroy(&viewer));
792: }
793: PetscCall(SNESLineSearchMonitorSetFromOptions(linesearch, "-snes_linesearch_monitor_solution_update", "View correction at each iteration", "SNESLineSearchMonitorSolutionUpdate", SNESLineSearchMonitorSolutionUpdate, NULL));
795: /* tolerances */
796: PetscCall(PetscOptionsReal("-snes_linesearch_minlambda", "Minimum step length", "SNESLineSearchSetTolerances", linesearch->steptol, &linesearch->steptol, NULL));
797: PetscCall(PetscOptionsReal("-snes_linesearch_maxstep", "Maximum step size", "SNESLineSearchSetTolerances", linesearch->maxstep, &linesearch->maxstep, NULL));
798: PetscCall(PetscOptionsReal("-snes_linesearch_rtol", "Relative tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->rtol, &linesearch->rtol, NULL));
799: PetscCall(PetscOptionsReal("-snes_linesearch_atol", "Absolute tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->atol, &linesearch->atol, NULL));
800: PetscCall(PetscOptionsReal("-snes_linesearch_ltol", "Change in lambda tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->ltol, &linesearch->ltol, NULL));
801: PetscCall(PetscOptionsInt("-snes_linesearch_max_it", "Maximum iterations for iterative line searches", "SNESLineSearchSetTolerances", linesearch->max_its, &linesearch->max_its, NULL));
803: /* damping parameters */
804: PetscCall(PetscOptionsReal("-snes_linesearch_damping", "Line search damping and initial step guess", "SNESLineSearchSetDamping", linesearch->damping, &linesearch->damping, NULL));
806: PetscCall(PetscOptionsBool("-snes_linesearch_keeplambda", "Use previous lambda as damping", "SNESLineSearchSetKeepLambda", linesearch->keeplambda, &linesearch->keeplambda, NULL));
808: /* precheck */
809: PetscCall(PetscOptionsBool("-snes_linesearch_precheck_picard", "Use a correction that sometimes improves convergence of Picard iteration", "SNESLineSearchPreCheckPicard", flg, &flg, &set));
810: if (set) {
811: if (flg) {
812: linesearch->precheck_picard_angle = 10.; /* correction only active if angle is less than 10 degrees */
814: 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));
815: PetscCall(SNESLineSearchSetPreCheck(linesearch, SNESLineSearchPreCheckPicard, &linesearch->precheck_picard_angle));
816: } else {
817: PetscCall(SNESLineSearchSetPreCheck(linesearch, NULL, NULL));
818: }
819: }
820: PetscCall(PetscOptionsInt("-snes_linesearch_order", "Order of approximation used in the line search", "SNESLineSearchSetOrder", linesearch->order, &linesearch->order, NULL));
821: PetscCall(PetscOptionsBool("-snes_linesearch_norms", "Compute final norms in line search", "SNESLineSearchSetComputeNorms", linesearch->norms, &linesearch->norms, NULL));
823: PetscTryTypeMethod(linesearch, setfromoptions, PetscOptionsObject);
825: PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)linesearch, PetscOptionsObject));
826: PetscOptionsEnd();
827: PetscFunctionReturn(PETSC_SUCCESS);
828: }
830: /*@
831: SNESLineSearchView - Prints useful information about the line search
833: Logically Collective
835: Input Parameters:
836: + linesearch - linesearch context
837: - viewer - the viewer to display the line search information
839: Level: intermediate
841: .seealso: `SNESLineSearch`, `PetscViewer`, `SNESLineSearchCreate()`
842: @*/
843: PetscErrorCode SNESLineSearchView(SNESLineSearch linesearch, PetscViewer viewer)
844: {
845: PetscBool iascii;
847: PetscFunctionBegin;
849: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)linesearch), &viewer));
851: PetscCheckSameComm(linesearch, 1, viewer, 2);
853: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
854: if (iascii) {
855: PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)linesearch, viewer));
856: PetscCall(PetscViewerASCIIPushTab(viewer));
857: PetscTryTypeMethod(linesearch, view, viewer);
858: PetscCall(PetscViewerASCIIPopTab(viewer));
859: PetscCall(PetscViewerASCIIPrintf(viewer, " maxstep=%e, minlambda=%e\n", (double)linesearch->maxstep, (double)linesearch->steptol));
860: PetscCall(PetscViewerASCIIPrintf(viewer, " tolerances: relative=%e, absolute=%e, lambda=%e\n", (double)linesearch->rtol, (double)linesearch->atol, (double)linesearch->ltol));
861: PetscCall(PetscViewerASCIIPrintf(viewer, " maximum iterations=%" PetscInt_FMT "\n", linesearch->max_its));
862: if (linesearch->ops->precheck) {
863: if (linesearch->ops->precheck == SNESLineSearchPreCheckPicard) {
864: PetscCall(PetscViewerASCIIPrintf(viewer, " using precheck step to speed up Picard convergence\n"));
865: } else {
866: PetscCall(PetscViewerASCIIPrintf(viewer, " using user-defined precheck step\n"));
867: }
868: }
869: if (linesearch->ops->postcheck) PetscCall(PetscViewerASCIIPrintf(viewer, " using user-defined postcheck step\n"));
870: }
871: PetscFunctionReturn(PETSC_SUCCESS);
872: }
874: /*@C
875: SNESLineSearchGetType - Gets the linesearch type
877: Logically Collective
879: Input Parameter:
880: . linesearch - linesearch context
882: Output Parameter:
883: . type - The type of line search, or `NULL` if not set
885: Level: intermediate
887: .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchSetType()`
888: @*/
889: PetscErrorCode SNESLineSearchGetType(SNESLineSearch linesearch, SNESLineSearchType *type)
890: {
891: PetscFunctionBegin;
893: PetscAssertPointer(type, 2);
894: *type = ((PetscObject)linesearch)->type_name;
895: PetscFunctionReturn(PETSC_SUCCESS);
896: }
898: /*@C
899: SNESLineSearchSetType - Sets the linesearch type
901: Logically Collective
903: Input Parameters:
904: + linesearch - linesearch context
905: - type - The type of line search to be used, see `SNESLineSearchType`
907: Options Database Key:
908: . -snes_linesearch_type <type> - basic (or equivalently none), bt, l2, cp, nleqerr, shell
910: Level: intermediate
912: .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchGetType()`
913: @*/
914: PetscErrorCode SNESLineSearchSetType(SNESLineSearch linesearch, SNESLineSearchType type)
915: {
916: PetscBool match;
917: PetscErrorCode (*r)(SNESLineSearch);
919: PetscFunctionBegin;
921: PetscAssertPointer(type, 2);
923: PetscCall(PetscObjectTypeCompare((PetscObject)linesearch, type, &match));
924: if (match) PetscFunctionReturn(PETSC_SUCCESS);
926: PetscCall(PetscFunctionListFind(SNESLineSearchList, type, &r));
927: PetscCheck(r, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Line Search type %s", type);
928: /* Destroy the previous private linesearch context */
929: if (linesearch->ops->destroy) {
930: PetscCall((*(linesearch)->ops->destroy)(linesearch));
931: linesearch->ops->destroy = NULL;
932: }
933: /* Reinitialize function pointers in SNESLineSearchOps structure */
934: linesearch->ops->apply = NULL;
935: linesearch->ops->view = NULL;
936: linesearch->ops->setfromoptions = NULL;
937: linesearch->ops->destroy = NULL;
939: PetscCall(PetscObjectChangeTypeName((PetscObject)linesearch, type));
940: PetscCall((*r)(linesearch));
941: PetscFunctionReturn(PETSC_SUCCESS);
942: }
944: /*@
945: SNESLineSearchSetSNES - Sets the `SNES` for the linesearch for function evaluation.
947: Input Parameters:
948: + linesearch - linesearch context
949: - snes - The snes instance
951: Level: developer
953: Note:
954: This happens automatically when the line search is obtained/created with
955: `SNESGetLineSearch()`. This routine is therefore mainly called within `SNES`
956: implementations.
958: .seealso: `SNESLineSearch`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`, `SNES`
959: @*/
960: PetscErrorCode SNESLineSearchSetSNES(SNESLineSearch linesearch, SNES snes)
961: {
962: PetscFunctionBegin;
965: linesearch->snes = snes;
966: PetscFunctionReturn(PETSC_SUCCESS);
967: }
969: /*@
970: SNESLineSearchGetSNES - Gets the `SNES` instance associated with the line search.
972: Not Collective
974: Input Parameter:
975: . linesearch - linesearch context
977: Output Parameter:
978: . snes - The `SNES` instance
980: Level: developer
982: .seealso: `SNESLineSearch`, `SNESType`, `SNESLineSearchSetVecs()`, `SNES`
983: @*/
984: PetscErrorCode SNESLineSearchGetSNES(SNESLineSearch linesearch, SNES *snes)
985: {
986: PetscFunctionBegin;
988: PetscAssertPointer(snes, 2);
989: *snes = linesearch->snes;
990: PetscFunctionReturn(PETSC_SUCCESS);
991: }
993: /*@
994: SNESLineSearchGetLambda - Gets the last linesearch steplength discovered.
996: Not Collective
998: Input Parameter:
999: . linesearch - linesearch context
1001: Output Parameter:
1002: . lambda - The last steplength computed during `SNESLineSearchApply()`
1004: Level: advanced
1006: Note:
1007: This is useful in methods where the solver is ill-scaled and
1008: requires some adaptive notion of the difference in scale between the
1009: solution and the function. For instance, `SNESQN` may be scaled by the
1010: line search lambda using the argument -snes_qn_scaling ls.
1012: .seealso: `SNESLineSearch`, `SNESLineSearchSetLambda()`, `SNESLineSearchGetDamping()`, `SNESLineSearchApply()`
1013: @*/
1014: PetscErrorCode SNESLineSearchGetLambda(SNESLineSearch linesearch, PetscReal *lambda)
1015: {
1016: PetscFunctionBegin;
1018: PetscAssertPointer(lambda, 2);
1019: *lambda = linesearch->lambda;
1020: PetscFunctionReturn(PETSC_SUCCESS);
1021: }
1023: /*@
1024: SNESLineSearchSetLambda - Sets the linesearch steplength
1026: Input Parameters:
1027: + linesearch - linesearch context
1028: - lambda - The last steplength.
1030: Level: advanced
1032: Note:
1033: This routine is typically used within implementations of `SNESLineSearchApply()`
1034: to set the final steplength. This routine (and `SNESLineSearchGetLambda()`) were
1035: added in order to facilitate Quasi-Newton methods that use the previous steplength
1036: as an inner scaling parameter.
1038: .seealso: `SNESLineSearch`, `SNESLineSearchGetLambda()`
1039: @*/
1040: PetscErrorCode SNESLineSearchSetLambda(SNESLineSearch linesearch, PetscReal lambda)
1041: {
1042: PetscFunctionBegin;
1044: linesearch->lambda = lambda;
1045: PetscFunctionReturn(PETSC_SUCCESS);
1046: }
1048: /*@
1049: SNESLineSearchGetTolerances - Gets the tolerances for the linesearch.
1051: Not Collective
1053: Input Parameter:
1054: . linesearch - linesearch context
1056: Output Parameters:
1057: + steptol - The minimum steplength
1058: . maxstep - The maximum steplength
1059: . rtol - The relative tolerance for iterative line searches
1060: . atol - The absolute tolerance for iterative line searches
1061: . ltol - The change in lambda tolerance for iterative line searches
1062: - max_its - The maximum number of iterations of the line search
1064: Level: intermediate
1066: Note:
1067: Different line searches may implement these parameters slightly differently as
1068: the type requires.
1070: .seealso: `SNESLineSearch`, `SNESLineSearchSetTolerances()`
1071: @*/
1072: PetscErrorCode SNESLineSearchGetTolerances(SNESLineSearch linesearch, PetscReal *steptol, PetscReal *maxstep, PetscReal *rtol, PetscReal *atol, PetscReal *ltol, PetscInt *max_its)
1073: {
1074: PetscFunctionBegin;
1076: if (steptol) {
1077: PetscAssertPointer(steptol, 2);
1078: *steptol = linesearch->steptol;
1079: }
1080: if (maxstep) {
1081: PetscAssertPointer(maxstep, 3);
1082: *maxstep = linesearch->maxstep;
1083: }
1084: if (rtol) {
1085: PetscAssertPointer(rtol, 4);
1086: *rtol = linesearch->rtol;
1087: }
1088: if (atol) {
1089: PetscAssertPointer(atol, 5);
1090: *atol = linesearch->atol;
1091: }
1092: if (ltol) {
1093: PetscAssertPointer(ltol, 6);
1094: *ltol = linesearch->ltol;
1095: }
1096: if (max_its) {
1097: PetscAssertPointer(max_its, 7);
1098: *max_its = linesearch->max_its;
1099: }
1100: PetscFunctionReturn(PETSC_SUCCESS);
1101: }
1103: /*@
1104: SNESLineSearchSetTolerances - Sets the tolerances for the linesearch.
1106: Collective
1108: Input Parameters:
1109: + linesearch - linesearch context
1110: . steptol - The minimum steplength
1111: . maxstep - The maximum steplength
1112: . rtol - The relative tolerance for iterative line searches
1113: . atol - The absolute tolerance for iterative line searches
1114: . ltol - The change in lambda tolerance for iterative line searches
1115: - max_its - The maximum number of iterations of the line search
1117: Level: intermediate
1119: Note:
1120: The user may choose to not set any of the tolerances using `PETSC_DEFAULT` in
1121: place of an argument.
1123: .seealso: `SNESLineSearch`, `SNESLineSearchGetTolerances()`
1124: @*/
1125: PetscErrorCode SNESLineSearchSetTolerances(SNESLineSearch linesearch, PetscReal steptol, PetscReal maxstep, PetscReal rtol, PetscReal atol, PetscReal ltol, PetscInt max_its)
1126: {
1127: PetscFunctionBegin;
1136: if (steptol != (PetscReal)PETSC_DEFAULT) {
1137: PetscCheck(steptol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Minimum step length %14.12e must be non-negative", (double)steptol);
1138: linesearch->steptol = steptol;
1139: }
1141: if (maxstep != (PetscReal)PETSC_DEFAULT) {
1142: PetscCheck(maxstep >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum step length %14.12e must be non-negative", (double)maxstep);
1143: linesearch->maxstep = maxstep;
1144: }
1146: if (rtol != (PetscReal)PETSC_DEFAULT) {
1147: 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);
1148: linesearch->rtol = rtol;
1149: }
1151: if (atol != (PetscReal)PETSC_DEFAULT) {
1152: PetscCheck(atol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %14.12e must be non-negative", (double)atol);
1153: linesearch->atol = atol;
1154: }
1156: if (ltol != (PetscReal)PETSC_DEFAULT) {
1157: PetscCheck(ltol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Lambda tolerance %14.12e must be non-negative", (double)ltol);
1158: linesearch->ltol = ltol;
1159: }
1161: if (max_its != PETSC_DEFAULT) {
1162: PetscCheck(max_its >= 0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations %" PetscInt_FMT " must be non-negative", max_its);
1163: linesearch->max_its = max_its;
1164: }
1165: PetscFunctionReturn(PETSC_SUCCESS);
1166: }
1168: /*@
1169: SNESLineSearchGetDamping - Gets the line search damping parameter.
1171: Input Parameter:
1172: . linesearch - linesearch context
1174: Output Parameter:
1175: . damping - The damping parameter
1177: Level: advanced
1179: .seealso: `SNESLineSearchGetStepTolerance()`, `SNESQN`
1180: @*/
1181: PetscErrorCode SNESLineSearchGetDamping(SNESLineSearch linesearch, PetscReal *damping)
1182: {
1183: PetscFunctionBegin;
1185: PetscAssertPointer(damping, 2);
1186: *damping = linesearch->damping;
1187: PetscFunctionReturn(PETSC_SUCCESS);
1188: }
1190: /*@
1191: SNESLineSearchSetDamping - Sets the line search damping parameter.
1193: Input Parameters:
1194: + linesearch - linesearch context
1195: - damping - The damping parameter
1197: Options Database Key:
1198: . -snes_linesearch_damping <damping> - the damping value
1200: Level: intermediate
1202: Note:
1203: The `SNESLINESEARCHNONE` line search merely takes the update step scaled by the damping parameter.
1204: The use of the damping parameter in the l2 and cp line searches is much more subtle;
1205: it is used as a starting point in calculating the secant step. However, the eventual
1206: step may be of greater length than the damping parameter. In the bt line search it is
1207: used as the maximum possible step length, as the bt line search only backtracks.
1209: .seealso: `SNESLineSearch`, `SNESLineSearchGetDamping()`
1210: @*/
1211: PetscErrorCode SNESLineSearchSetDamping(SNESLineSearch linesearch, PetscReal damping)
1212: {
1213: PetscFunctionBegin;
1215: linesearch->damping = damping;
1216: PetscFunctionReturn(PETSC_SUCCESS);
1217: }
1219: /*@
1220: SNESLineSearchGetOrder - Gets the line search approximation order.
1222: Input Parameter:
1223: . linesearch - linesearch context
1225: Output Parameter:
1226: . order - The order
1228: Level: intermediate
1230: .seealso: `SNESLineSearch`, `SNESLineSearchSetOrder()`
1231: @*/
1232: PetscErrorCode SNESLineSearchGetOrder(SNESLineSearch linesearch, PetscInt *order)
1233: {
1234: PetscFunctionBegin;
1236: PetscAssertPointer(order, 2);
1237: *order = linesearch->order;
1238: PetscFunctionReturn(PETSC_SUCCESS);
1239: }
1241: /*@
1242: SNESLineSearchSetOrder - Sets the maximum order of the polynomial fit used in the line search
1244: Input Parameters:
1245: + linesearch - linesearch context
1246: - order - The order
1248: Level: intermediate
1250: Values for `order`\:
1251: + 1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
1252: . 2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
1253: - 3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order
1255: Note:
1256: These orders are supported by `SNESLINESEARCHBT` and `SNESLINESEARCHCP`
1258: .seealso: `SNESLineSearch`, `SNESLineSearchGetOrder()`, `SNESLineSearchSetDamping()`
1259: @*/
1260: PetscErrorCode SNESLineSearchSetOrder(SNESLineSearch linesearch, PetscInt order)
1261: {
1262: PetscFunctionBegin;
1264: linesearch->order = order;
1265: PetscFunctionReturn(PETSC_SUCCESS);
1266: }
1268: /*@
1269: SNESLineSearchGetNorms - Gets the norms for for X, Y, and F.
1271: Not Collective
1273: Input Parameter:
1274: . linesearch - linesearch context
1276: Output Parameters:
1277: + xnorm - The norm of the current solution
1278: . fnorm - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution.
1279: - ynorm - The norm of the current update
1281: Level: developer
1283: Note:
1284: Some values may not be up to date at particular points in the code.
1286: This, in combination with `SNESLineSearchSetNorms()`, allow the line search and the `SNESSolve_XXX()` to share
1287: computed values.
1289: .seealso: `SNESLineSearch`, `SNESLineSearchSetNorms()` `SNESLineSearchGetVecs()`
1290: @*/
1291: PetscErrorCode SNESLineSearchGetNorms(SNESLineSearch linesearch, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm)
1292: {
1293: PetscFunctionBegin;
1295: if (xnorm) *xnorm = linesearch->xnorm;
1296: if (fnorm) *fnorm = linesearch->fnorm;
1297: if (ynorm) *ynorm = linesearch->ynorm;
1298: PetscFunctionReturn(PETSC_SUCCESS);
1299: }
1301: /*@
1302: SNESLineSearchSetNorms - Gets the computed norms for for X, Y, and F.
1304: Collective
1306: Input Parameters:
1307: + linesearch - linesearch context
1308: . xnorm - The norm of the current solution
1309: . fnorm - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution
1310: - ynorm - The norm of the current update
1312: Level: developer
1314: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1315: @*/
1316: PetscErrorCode SNESLineSearchSetNorms(SNESLineSearch linesearch, PetscReal xnorm, PetscReal fnorm, PetscReal ynorm)
1317: {
1318: PetscFunctionBegin;
1320: linesearch->xnorm = xnorm;
1321: linesearch->fnorm = fnorm;
1322: linesearch->ynorm = ynorm;
1323: PetscFunctionReturn(PETSC_SUCCESS);
1324: }
1326: /*@
1327: SNESLineSearchComputeNorms - Computes the norms of X, F, and Y.
1329: Input Parameter:
1330: . linesearch - linesearch context
1332: Options Database Key:
1333: . -snes_linesearch_norms - turn norm computation on or off
1335: Level: intermediate
1337: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms`, `SNESLineSearchSetNorms()`, `SNESLineSearchSetComputeNorms()`
1338: @*/
1339: PetscErrorCode SNESLineSearchComputeNorms(SNESLineSearch linesearch)
1340: {
1341: SNES snes;
1343: PetscFunctionBegin;
1344: if (linesearch->norms) {
1345: if (linesearch->ops->vinorm) {
1346: PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
1347: PetscCall(VecNorm(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1348: PetscCall(VecNorm(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1349: PetscCall((*linesearch->ops->vinorm)(snes, linesearch->vec_func, linesearch->vec_sol, &linesearch->fnorm));
1350: } else {
1351: PetscCall(VecNormBegin(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1352: PetscCall(VecNormBegin(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1353: PetscCall(VecNormBegin(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1354: PetscCall(VecNormEnd(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1355: PetscCall(VecNormEnd(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1356: PetscCall(VecNormEnd(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1357: }
1358: }
1359: PetscFunctionReturn(PETSC_SUCCESS);
1360: }
1362: /*@
1363: SNESLineSearchSetComputeNorms - Turns on or off the computation of final norms in the line search.
1365: Input Parameters:
1366: + linesearch - linesearch context
1367: - flg - indicates whether or not to compute norms
1369: Options Database Key:
1370: . -snes_linesearch_norms <true> - Turns on/off computation of the norms for basic (none) linesearch
1372: Level: intermediate
1374: Note:
1375: This is most relevant to the `SNESLINESEARCHBASIC` (or equivalently `SNESLINESEARCHNONE`) line search type since most line searches have a stopping criteria involving the norm.
1377: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetNorms()`, `SNESLineSearchComputeNorms()`, `SNESLINESEARCHBASIC`
1378: @*/
1379: PetscErrorCode SNESLineSearchSetComputeNorms(SNESLineSearch linesearch, PetscBool flg)
1380: {
1381: PetscFunctionBegin;
1382: linesearch->norms = flg;
1383: PetscFunctionReturn(PETSC_SUCCESS);
1384: }
1386: /*@
1387: SNESLineSearchGetVecs - Gets the vectors from the `SNESLineSearch` context
1389: Not Collective but the vectors are parallel
1391: Input Parameter:
1392: . linesearch - linesearch context
1394: Output Parameters:
1395: + X - Solution vector
1396: . F - Function vector
1397: . Y - Search direction vector
1398: . W - Solution work vector
1399: - G - Function work vector
1401: Level: advanced
1403: Notes:
1404: At the beginning of a line search application, `X` should contain a
1405: solution and the vector `F` the function computed at `X`. At the end of the
1406: line search application, `X` should contain the new solution, and `F` the
1407: function evaluated at the new solution.
1409: These vectors are owned by the `SNESLineSearch` and should not be destroyed by the caller
1411: .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1412: @*/
1413: PetscErrorCode SNESLineSearchGetVecs(SNESLineSearch linesearch, Vec *X, Vec *F, Vec *Y, Vec *W, Vec *G)
1414: {
1415: PetscFunctionBegin;
1417: if (X) {
1418: PetscAssertPointer(X, 2);
1419: *X = linesearch->vec_sol;
1420: }
1421: if (F) {
1422: PetscAssertPointer(F, 3);
1423: *F = linesearch->vec_func;
1424: }
1425: if (Y) {
1426: PetscAssertPointer(Y, 4);
1427: *Y = linesearch->vec_update;
1428: }
1429: if (W) {
1430: PetscAssertPointer(W, 5);
1431: *W = linesearch->vec_sol_new;
1432: }
1433: if (G) {
1434: PetscAssertPointer(G, 6);
1435: *G = linesearch->vec_func_new;
1436: }
1437: PetscFunctionReturn(PETSC_SUCCESS);
1438: }
1440: /*@
1441: SNESLineSearchSetVecs - Sets the vectors on the `SNESLineSearch` context
1443: Logically Collective
1445: Input Parameters:
1446: + linesearch - linesearch context
1447: . X - Solution vector
1448: . F - Function vector
1449: . Y - Search direction vector
1450: . W - Solution work vector
1451: - G - Function work vector
1453: Level: advanced
1455: .seealso: `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
1456: @*/
1457: PetscErrorCode SNESLineSearchSetVecs(SNESLineSearch linesearch, Vec X, Vec F, Vec Y, Vec W, Vec G)
1458: {
1459: PetscFunctionBegin;
1461: if (X) {
1463: linesearch->vec_sol = X;
1464: }
1465: if (F) {
1467: linesearch->vec_func = F;
1468: }
1469: if (Y) {
1471: linesearch->vec_update = Y;
1472: }
1473: if (W) {
1475: linesearch->vec_sol_new = W;
1476: }
1477: if (G) {
1479: linesearch->vec_func_new = G;
1480: }
1481: PetscFunctionReturn(PETSC_SUCCESS);
1482: }
1484: /*@C
1485: SNESLineSearchAppendOptionsPrefix - Appends to the prefix used for searching for all
1486: `SNESLineSearch` options in the database.
1488: Logically Collective
1490: Input Parameters:
1491: + linesearch - the `SNESLineSearch` context
1492: - prefix - the prefix to prepend to all option names
1494: Level: advanced
1496: Note:
1497: A hyphen (-) must NOT be given at the beginning of the prefix name.
1498: The first character of all runtime options is AUTOMATICALLY the hyphen.
1500: .seealso: `SNESLineSearch()`, `SNESLineSearchSetFromOptions()`, `SNESGetOptionsPrefix()`
1501: @*/
1502: PetscErrorCode SNESLineSearchAppendOptionsPrefix(SNESLineSearch linesearch, const char prefix[])
1503: {
1504: PetscFunctionBegin;
1506: PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)linesearch, prefix));
1507: PetscFunctionReturn(PETSC_SUCCESS);
1508: }
1510: /*@C
1511: SNESLineSearchGetOptionsPrefix - Gets the prefix used for searching for all
1512: SNESLineSearch options in the database.
1514: Not Collective
1516: Input Parameter:
1517: . linesearch - the `SNESLineSearch` context
1519: Output Parameter:
1520: . prefix - pointer to the prefix string used
1522: Level: advanced
1524: Fortran Notes:
1525: The user should pass in a string 'prefix' of
1526: sufficient length to hold the prefix.
1528: .seealso: `SNESLineSearch`, `SNESAppendOptionsPrefix()`
1529: @*/
1530: PetscErrorCode SNESLineSearchGetOptionsPrefix(SNESLineSearch linesearch, const char *prefix[])
1531: {
1532: PetscFunctionBegin;
1534: PetscCall(PetscObjectGetOptionsPrefix((PetscObject)linesearch, prefix));
1535: PetscFunctionReturn(PETSC_SUCCESS);
1536: }
1538: /*@C
1539: SNESLineSearchSetWorkVecs - Sets work vectors for the line search.
1541: Input Parameters:
1542: + linesearch - the `SNESLineSearch` context
1543: - nwork - the number of work vectors
1545: Level: developer
1547: .seealso: `SNESLineSearch`, `SNESSetWorkVecs()`
1548: @*/
1549: PetscErrorCode SNESLineSearchSetWorkVecs(SNESLineSearch linesearch, PetscInt nwork)
1550: {
1551: PetscFunctionBegin;
1552: PetscCheck(linesearch->vec_sol, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "Cannot get linesearch work-vectors without setting a solution vec!");
1553: PetscCall(VecDuplicateVecs(linesearch->vec_sol, nwork, &linesearch->work));
1554: PetscFunctionReturn(PETSC_SUCCESS);
1555: }
1557: /*@
1558: SNESLineSearchGetReason - Gets the success/failure status of the last line search application
1560: Input Parameter:
1561: . linesearch - linesearch context
1563: Output Parameter:
1564: . result - The success or failure status
1566: Level: developer
1568: Note:
1569: This is typically called after `SNESLineSearchApply()` in order to determine if the line-search failed
1570: (and set the SNES convergence accordingly).
1572: .seealso: `SNESLineSearch`, `SNESLineSearchSetReason()`, `SNESLineSearchReason`
1573: @*/
1574: PetscErrorCode SNESLineSearchGetReason(SNESLineSearch linesearch, SNESLineSearchReason *result)
1575: {
1576: PetscFunctionBegin;
1578: PetscAssertPointer(result, 2);
1579: *result = linesearch->result;
1580: PetscFunctionReturn(PETSC_SUCCESS);
1581: }
1583: /*@
1584: SNESLineSearchSetReason - Sets the success/failure status of the last line search application
1586: Input Parameters:
1587: + linesearch - linesearch context
1588: - result - The success or failure status
1590: Level: developer
1592: Note:
1593: This is typically called in a `SNESLineSearchApply()` or a `SNESLINESEARCHSHELL` implementation to set
1594: the success or failure of the line search method.
1596: .seealso: `SNESLineSearch`, `SNESLineSearchReason`, `SNESLineSearchGetSResult()`
1597: @*/
1598: PetscErrorCode SNESLineSearchSetReason(SNESLineSearch linesearch, SNESLineSearchReason result)
1599: {
1600: PetscFunctionBegin;
1602: linesearch->result = result;
1603: PetscFunctionReturn(PETSC_SUCCESS);
1604: }
1606: // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation
1607: /*@C
1608: SNESLineSearchSetVIFunctions - Sets VI-specific functions for line search computation.
1610: Logically Collective
1612: Input Parameters:
1613: + linesearch - the linesearch object
1614: . projectfunc - function for projecting the function to the bounds
1615: - normfunc - function for computing the norm of an active set
1617: Calling sequence of `projectfunc`:
1618: $ PetscErrorCode projectfunc(SNES snes, Vec X)
1619: + snes - nonlinear context
1620: - X - current solution, store the projected solution here
1622: Calling sequence of `normfunc`:
1623: $ PetscErrorCode normfunc(SNES snes, Vec X, Vec F, PetscScalar *fnorm)
1624: + snes - nonlinear context
1625: . X - current solution
1626: . F - current residual
1627: - fnorm - the computed norm
1629: Level: advanced
1631: Notes:
1632: The VI solvers require projection of the solution to the feasible set. `projectfunc` should implement this.
1634: The VI solvers require special evaluation of the function norm such that the norm is only calculated
1635: on the inactive set. This should be implemented by `normfunc`.
1637: .seealso: `SNESLineSearch`, `SNESLineSearchGetVIFunctions()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`
1638: @*/
1639: PetscErrorCode SNESLineSearchSetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFunc projectfunc, SNESLineSearchVINormFunc normfunc)
1640: {
1641: PetscFunctionBegin;
1643: if (projectfunc) linesearch->ops->viproject = projectfunc;
1644: if (normfunc) linesearch->ops->vinorm = normfunc;
1645: PetscFunctionReturn(PETSC_SUCCESS);
1646: }
1648: /*@C
1649: SNESLineSearchGetVIFunctions - Sets VI-specific functions for line search computation.
1651: Not Collective
1653: Input Parameter:
1654: . linesearch - the line search context, obtain with `SNESGetLineSearch()`
1656: Output Parameters:
1657: + projectfunc - function for projecting the function to the bounds
1658: - normfunc - function for computing the norm of an active set
1660: Level: advanced
1662: .seealso: `SNESLineSearch`, `SNESLineSearchSetVIFunctions()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`
1663: @*/
1664: PetscErrorCode SNESLineSearchGetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFunc *projectfunc, SNESLineSearchVINormFunc *normfunc)
1665: {
1666: PetscFunctionBegin;
1667: if (projectfunc) *projectfunc = linesearch->ops->viproject;
1668: if (normfunc) *normfunc = linesearch->ops->vinorm;
1669: PetscFunctionReturn(PETSC_SUCCESS);
1670: }
1672: /*@C
1673: SNESLineSearchRegister - register a line search type
1675: Input Parameters:
1676: + sname - name of the line search
1677: - function - the creation function for that type
1679: Calling sequence of `function`:
1680: . ls - the linesearch context
1682: Level: advanced
1684: .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchSetType()`
1685: @*/
1686: PetscErrorCode SNESLineSearchRegister(const char sname[], PetscErrorCode (*function)(SNESLineSearch ls))
1687: {
1688: PetscFunctionBegin;
1689: PetscCall(SNESInitializePackage());
1690: PetscCall(PetscFunctionListAdd(&SNESLineSearchList, sname, function));
1691: PetscFunctionReturn(PETSC_SUCCESS);
1692: }