Actual source code: snesut.c
1: #define PETSCSNES_DLL
3: #include src/snes/snesimpl.h
7: /*@C
8: SNESVecViewMonitor - Monitors progress of the SNES solvers by calling
9: VecView() for the approximate solution at each iteration.
11: Collective on SNES
13: Input Parameters:
14: + snes - the SNES context
15: . its - iteration number
16: . fgnorm - 2-norm of residual
17: - dummy - either a viewer or PETSC_NULL
19: Level: intermediate
21: .keywords: SNES, nonlinear, vector, monitor, view
23: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
24: @*/
25: PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
26: {
28: Vec x;
29: PetscViewer viewer = (PetscViewer) dummy;
32: SNESGetSolution(snes,&x);
33: if (!viewer) {
34: MPI_Comm comm;
35: PetscObjectGetComm((PetscObject)snes,&comm);
36: viewer = PETSC_VIEWER_DRAW_(comm);
37: }
38: VecView(x,viewer);
40: return(0);
41: }
45: /*@C
46: SNESVecViewResidualMonitor - Monitors progress of the SNES solvers by calling
47: VecView() for the residual at each iteration.
49: Collective on SNES
51: Input Parameters:
52: + snes - the SNES context
53: . its - iteration number
54: . fgnorm - 2-norm of residual
55: - dummy - either a viewer or PETSC_NULL
57: Level: intermediate
59: .keywords: SNES, nonlinear, vector, monitor, view
61: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
62: @*/
63: PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewResidualMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
64: {
66: Vec x;
67: PetscViewer viewer = (PetscViewer) dummy;
70: SNESGetFunction(snes,&x,0,0);
71: if (!viewer) {
72: MPI_Comm comm;
73: PetscObjectGetComm((PetscObject)snes,&comm);
74: viewer = PETSC_VIEWER_DRAW_(comm);
75: }
76: VecView(x,viewer);
78: return(0);
79: }
83: /*@C
84: SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling
85: VecView() for the UPDATE to the solution at each iteration.
87: Collective on SNES
89: Input Parameters:
90: + snes - the SNES context
91: . its - iteration number
92: . fgnorm - 2-norm of residual
93: - dummy - either a viewer or PETSC_NULL
95: Level: intermediate
97: .keywords: SNES, nonlinear, vector, monitor, view
99: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
100: @*/
101: PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewUpdateMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
102: {
104: Vec x;
105: PetscViewer viewer = (PetscViewer) dummy;
108: SNESGetSolutionUpdate(snes,&x);
109: if (!viewer) {
110: MPI_Comm comm;
111: PetscObjectGetComm((PetscObject)snes,&comm);
112: viewer = PETSC_VIEWER_DRAW_(comm);
113: }
114: VecView(x,viewer);
116: return(0);
117: }
121: /*@C
122: SNESDefaultMonitor - Monitors progress of the SNES solvers (default).
124: Collective on SNES
126: Input Parameters:
127: + snes - the SNES context
128: . its - iteration number
129: . fgnorm - 2-norm of residual
130: - dummy - unused context
132: Notes:
133: This routine prints the residual norm at each iteration.
135: Level: intermediate
137: .keywords: SNES, nonlinear, default, monitor, norm
139: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
140: @*/
141: PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
142: {
144: PetscViewer viewer = (PetscViewer) dummy;
147: if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
148: PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);
149: return(0);
150: }
154: /*@C
155: SNESRatioMonitor - Monitors progress of the SNES solvers by printing the ratio
156: of residual norm at each iteration to the previous.
158: Collective on SNES
160: Input Parameters:
161: + snes - the SNES context
162: . its - iteration number
163: . fgnorm - 2-norm of residual (or gradient)
164: - dummy - unused context
166: Level: intermediate
168: .keywords: SNES, nonlinear, monitor, norm
170: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
171: @*/
172: PetscErrorCode PETSCSNES_DLLEXPORT SNESRatioMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
173: {
175: PetscInt len;
176: PetscReal *history;
177: PetscViewer viewer;
180: viewer = PETSC_VIEWER_STDOUT_(snes->comm);
182: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
183: if (!its || !history || its > len) {
184: PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);
185: } else {
186: PetscReal ratio = fgnorm/history[its-1];
187: PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e %g \n",its,fgnorm,ratio);
188: }
189: return(0);
190: }
192: /*
193: If the we set the history monitor space then we must destroy it
194: */
197: PetscErrorCode SNESRatioMonitorDestroy(void *history)
198: {
202: PetscFree(history);
203: return(0);
204: }
208: /*@C
209: SNESSetRatioMonitor - Sets SNES to use a monitor that prints the
210: ratio of the function norm at each iteration.
212: Collective on SNES
214: Input Parameters:
215: . snes - the SNES context
217: Level: intermediate
219: .keywords: SNES, nonlinear, monitor, norm
221: .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
222: @*/
223: PetscErrorCode PETSCSNES_DLLEXPORT SNESSetRatioMonitor(SNES snes)
224: {
226: PetscReal *history;
230: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
231: if (!history) {
232: PetscMalloc(100*sizeof(double),&history);
233: SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);
234: SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);
235: } else {
236: SNESSetMonitor(snes,SNESRatioMonitor,0,0);
237: }
238: return(0);
239: }
241: /* ---------------------------------------------------------------- */
244: /*
245: Default (short) SNES Monitor, same as SNESDefaultMonitor() except
246: it prints fewer digits of the residual as the residual gets smaller.
247: This is because the later digits are meaningless and are often
248: different on different machines; by using this routine different
249: machines will usually generate the same output.
250: */
251: PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultSMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
252: {
256: if (fgnorm > 1.e-9) {
257: PetscPrintf(snes->comm,"%3D SNES Function norm %g \n",its,fgnorm);
258: } else if (fgnorm > 1.e-11){
259: PetscPrintf(snes->comm,"%3D SNES Function norm %5.3e \n",its,fgnorm);
260: } else {
261: PetscPrintf(snes->comm,"%3D SNES Function norm < 1.e-11\n",its);
262: }
263: return(0);
264: }
265: /* ---------------------------------------------------------------- */
268: /*@C
269: SNESConverged_LS - Monitors the convergence of the solvers for
270: systems of nonlinear equations (default).
272: Collective on SNES
274: Input Parameters:
275: + snes - the SNES context
276: . xnorm - 2-norm of current iterate
277: . pnorm - 2-norm of current step
278: . fnorm - 2-norm of function
279: - dummy - unused context
281: Output Parameter:
282: . reason - one of
283: $ SNES_CONVERGED_FNORM_ABS - (fnorm < abstol),
284: $ SNES_CONVERGED_PNORM_RELATIVE - (pnorm < xtol*xnorm),
285: $ SNES_CONVERGED_FNORM_RELATIVE - (fnorm < rtol*fnorm0),
286: $ SNES_DIVERGED_FUNCTION_COUNT - (nfct > maxf),
287: $ SNES_DIVERGED_FNORM_NAN - (fnorm == NaN),
288: $ SNES_CONVERGED_ITERATING - (otherwise),
290: where
291: + maxf - maximum number of function evaluations,
292: set with SNESSetTolerances()
293: . nfct - number of function evaluations,
294: . abstol - absolute function norm tolerance,
295: set with SNESSetTolerances()
296: - rtol - relative function norm tolerance, set with SNESSetTolerances()
298: Level: intermediate
300: .keywords: SNES, nonlinear, default, converged, convergence
302: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
303: @*/
304: PetscErrorCode PETSCSNES_DLLEXPORT SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
305: {
309: if (fnorm != fnorm) {
310: PetscLogInfo((snes,"SNESConverged_LS:Failed to converged, function norm is NaN\n"));
311: *reason = SNES_DIVERGED_FNORM_NAN;
312: } else if (fnorm <= snes->ttol) {
313: PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol));
314: *reason = SNES_CONVERGED_FNORM_RELATIVE;
315: } else if (fnorm < snes->abstol) {
316: PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g\n",fnorm,snes->abstol));
317: *reason = SNES_CONVERGED_FNORM_ABS;
318: } else if (pnorm < snes->xtol*xnorm) {
319: PetscLogInfo((snes,"SNESConverged_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm));
320: *reason = SNES_CONVERGED_PNORM_RELATIVE;
321: } else if (snes->nfuncs >= snes->max_funcs) {
322: PetscLogInfo((snes,"SNESConverged_LS:Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs));
323: *reason = SNES_DIVERGED_FUNCTION_COUNT ;
324: } else {
325: *reason = SNES_CONVERGED_ITERATING;
326: }
327: return(0);
328: }
329: /* ------------------------------------------------------------ */
332: /*@
333: SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
334: for the linear solvers within an inexact Newton method.
336: Collective on SNES
338: Input Parameter:
339: . snes - SNES context
341: Notes:
342: Currently, the default is to use a constant relative tolerance for
343: the inner linear solvers. Alternatively, one can use the
344: Eisenstat-Walker method, where the relative convergence tolerance
345: is reset at each Newton iteration according progress of the nonlinear
346: solver.
348: Level: advanced
350: Reference:
351: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
352: inexact Newton method", SISC 17 (1), pp.16-32, 1996.
354: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
355: @*/
356: PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetConvergenceTestEW(SNES snes)
357: {
359: snes->ksp_ewconv = PETSC_TRUE;
360: return(0);
361: }
365: /*@
366: SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
367: convergence criteria for the linear solvers within an inexact
368: Newton method.
370: Collective on SNES
371:
372: Input Parameters:
373: + snes - SNES context
374: . version - version 1 or 2 (default is 2)
375: . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
376: . rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
377: . alpha - power for version 2 rtol computation (1 < alpha <= 2)
378: . alpha2 - power for safeguard
379: . gamma2 - multiplicative factor for version 2 rtol computation
380: (0 <= gamma2 <= 1)
381: - threshold - threshold for imposing safeguard (0 < threshold < 1)
383: Note:
384: Use PETSC_DEFAULT to retain the default for any of the parameters.
386: Level: advanced
388: Reference:
389: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
390: inexact Newton method", Utah State University Math. Stat. Dept. Res.
391: Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
393: .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
395: .seealso: SNES_KSP_SetConvergenceTestEW()
396: @*/
397: PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetParametersEW(SNES snes,PetscInt version,PetscReal rtol_0,PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
398: PetscReal alpha2,PetscReal threshold)
399: {
400: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
403: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
404: if (version != PETSC_DEFAULT) kctx->version = version;
405: if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0;
406: if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max;
407: if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2;
408: if (alpha != PETSC_DEFAULT) kctx->alpha = alpha;
409: if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2;
410: if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
411: if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
412: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
413: }
414: if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
415: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0\n",kctx->rtol_max);
416: }
417: if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
418: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0\n",kctx->threshold);
419: }
420: if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
421: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0\n",kctx->gamma);
422: }
423: if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
424: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0\n",kctx->alpha);
425: }
426: if (kctx->version != 1 && kctx->version !=2) {
427: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %D",kctx->version);
428: }
429: return(0);
430: }
434: PetscErrorCode SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
435: {
436: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
437: PetscReal rtol = 0.0,stol;
438: PetscErrorCode ierr;
441: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
442: if (!snes->iter) { /* first time in, so use the original user rtol */
443: rtol = kctx->rtol_0;
444: } else {
445: if (kctx->version == 1) {
446: rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
447: if (rtol < 0.0) rtol = -rtol;
448: stol = pow(kctx->rtol_last,kctx->alpha2);
449: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
450: } else if (kctx->version == 2) {
451: rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
452: stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
453: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
454: } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %D",kctx->version);
455: }
456: rtol = PetscMin(rtol,kctx->rtol_max);
457: kctx->rtol_last = rtol;
458: PetscLogInfo((snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %D, Eisenstat-Walker (version %D) KSP rtol = %g\n",snes->iter,kctx->version,rtol));
459: KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
460: kctx->norm_last = snes->norm;
461: return(0);
462: }
466: PetscErrorCode SNES_KSP_EW_Converged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
467: {
468: SNES snes = (SNES)ctx;
469: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
470: PetscErrorCode ierr;
473: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
474: if (!n) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
475: KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
476: kctx->lresid_last = rnorm;
477: if (*reason) {
478: PetscLogInfo((snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%D, rnorm=%g\n",n,rnorm));
479: }
480: return(0);
481: }