Actual source code: snesut.c
1: /*$Id: snesut.c,v 1.66 2001/08/06 21:17:07 bsmith Exp $*/
3: #include src/snes/snesimpl.h
5: #undef __FUNCT__
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: int SNESVecViewMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
26: {
27: int ierr;
28: Vec x;
29: PetscViewer viewer = (PetscViewer) dummy;
32: SNESGetSolution(snes,&x);
33: if (!viewer) {
34: MPI_Comm comm;
35: ierr = PetscObjectGetComm((PetscObject)snes,&comm);
36: viewer = PETSC_VIEWER_DRAW_(comm);
37: }
38: VecView(x,viewer);
40: return(0);
41: }
43: #undef __FUNCT__
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: int SNESVecViewResidualMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
64: {
65: int ierr;
66: Vec x;
67: PetscViewer viewer = (PetscViewer) dummy;
70: SNESGetFunction(snes,&x,0,0);
71: if (!viewer) {
72: MPI_Comm comm;
73: ierr = PetscObjectGetComm((PetscObject)snes,&comm);
74: viewer = PETSC_VIEWER_DRAW_(comm);
75: }
76: VecView(x,viewer);
78: return(0);
79: }
81: #undef __FUNCT__
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: int SNESVecViewUpdateMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
102: {
103: int ierr;
104: Vec x;
105: PetscViewer viewer = (PetscViewer) dummy;
108: SNESGetSolutionUpdate(snes,&x);
109: if (!viewer) {
110: MPI_Comm comm;
111: ierr = PetscObjectGetComm((PetscObject)snes,&comm);
112: viewer = PETSC_VIEWER_DRAW_(comm);
113: }
114: VecView(x,viewer);
116: return(0);
117: }
119: #undef __FUNCT__
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: int SNESDefaultMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
142: {
143: int ierr;
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: }
152: #undef __FUNCT__
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: int SNESRatioMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
173: {
174: int ierr,len;
175: PetscReal *history;
176: PetscViewer viewer;
179: viewer = PETSC_VIEWER_STDOUT_(snes->comm);
181: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
182: if (its == 0 || !history || its > len) {
183: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
184: } else {
185: PetscReal ratio = fgnorm/history[its-1];
186: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e %g n",its,fgnorm,ratio);
187: }
188: return(0);
189: }
191: /*
192: If the we set the history monitor space then we must destroy it
193: */
194: #undef __FUNCT__
196: int SNESRatioMonitorDestroy(void *history)
197: {
198: int ierr;
201: PetscFree(history);
202: return(0);
203: }
205: #undef __FUNCT__
207: /*@C
208: SNESSetRatioMonitor - Sets SNES to use a monitor that prints the
209: ratio of the function norm at each iteration.
211: Collective on SNES
213: Input Parameters:
214: . snes - the SNES context
216: Level: intermediate
218: .keywords: SNES, nonlinear, monitor, norm
220: .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
221: @*/
222: int SNESSetRatioMonitor(SNES snes)
223: {
224: int ierr;
225: PetscReal *history;
229: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
230: if (!history) {
231: PetscMalloc(100*sizeof(double),&history);
232: SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);
233: SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);
234: } else {
235: SNESSetMonitor(snes,SNESRatioMonitor,0,0);
236: }
237: return(0);
238: }
240: /* ---------------------------------------------------------------- */
241: #undef __FUNCT__
243: /*
244: Default (short) SNES Monitor, same as SNESDefaultMonitor() except
245: it prints fewer digits of the residual as the residual gets smaller.
246: This is because the later digits are meaningless and are often
247: different on different machines; by using this routine different
248: machines will usually generate the same output.
249: */
250: int SNESDefaultSMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
251: {
255: if (fgnorm > 1.e-9) {
256: PetscPrintf(snes->comm,"%3d SNES Function norm %g n",its,fgnorm);
257: } else if (fgnorm > 1.e-11){
258: PetscPrintf(snes->comm,"%3d SNES Function norm %5.3e n",its,fgnorm);
259: } else {
260: PetscPrintf(snes->comm,"%3d SNES Function norm < 1.e-11n",its);
261: }
262: return(0);
263: }
264: /* ---------------------------------------------------------------- */
265: #undef __FUNCT__
267: /*@C
268: SNESConverged_LS - Monitors the convergence of the solvers for
269: systems of nonlinear equations (default).
271: Collective on SNES
273: Input Parameters:
274: + snes - the SNES context
275: . xnorm - 2-norm of current iterate
276: . pnorm - 2-norm of current step
277: . fnorm - 2-norm of function
278: - dummy - unused context
280: Output Parameter:
281: . reason - one of
282: $ SNES_CONVERGED_FNORM_ABS - (fnorm < atol),
283: $ SNES_CONVERGED_PNORM_RELATIVE - (pnorm < xtol*xnorm),
284: $ SNES_CONVERGED_FNORM_RELATIVE - (fnorm < rtol*fnorm0),
285: $ SNES_DIVERGED_FUNCTION_COUNT - (nfct > maxf),
286: $ SNES_DIVERGED_FNORM_NAN - (fnorm == NaN),
287: $ SNES_CONVERGED_ITERATING - (otherwise),
289: where
290: + maxf - maximum number of function evaluations,
291: set with SNESSetTolerances()
292: . nfct - number of function evaluations,
293: . atol - absolute function norm tolerance,
294: set with SNESSetTolerances()
295: - rtol - relative function norm tolerance, set with SNESSetTolerances()
297: Level: intermediate
299: .keywords: SNES, nonlinear, default, converged, convergence
301: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
302: @*/
303: int SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
304: {
306: if (fnorm != fnorm) {
307: PetscLogInfo(snes,"SNESConverged_LS:Failed to converged, function norm is NaNn");
308: *reason = SNES_DIVERGED_FNORM_NAN;
309: } else if (fnorm <= snes->ttol) {
310: PetscLogInfo(snes,"SNESConverged_LS:Converged due to function norm %g < %g (relative tolerance)n",fnorm,snes->ttol);
311: *reason = SNES_CONVERGED_FNORM_RELATIVE;
312: } else if (fnorm < snes->atol) {
313: PetscLogInfo(snes,"SNESConverged_LS:Converged due to function norm %g < %gn",fnorm,snes->atol);
314: *reason = SNES_CONVERGED_FNORM_ABS;
315: } else if (pnorm < snes->xtol*xnorm) {
316: PetscLogInfo(snes,"SNESConverged_LS:Converged due to small update length: %g < %g * %gn",pnorm,snes->xtol,xnorm);
317: *reason = SNES_CONVERGED_PNORM_RELATIVE;
318: } else if (snes->nfuncs > snes->max_funcs) {
319: PetscLogInfo(snes,"SNESConverged_LS:Exceeded maximum number of function evaluations: %d > %dn",snes->nfuncs,snes->max_funcs);
320: *reason = SNES_DIVERGED_FUNCTION_COUNT ;
321: } else {
322: *reason = SNES_CONVERGED_ITERATING;
323: }
324: return(0);
325: }
326: /* ------------------------------------------------------------ */
327: #undef __FUNCT__
329: /*@
330: SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
331: for the linear solvers within an inexact Newton method.
333: Collective on SNES
335: Input Parameter:
336: . snes - SNES context
338: Notes:
339: Currently, the default is to use a constant relative tolerance for
340: the inner linear solvers. Alternatively, one can use the
341: Eisenstat-Walker method, where the relative convergence tolerance
342: is reset at each Newton iteration according progress of the nonlinear
343: solver.
345: Level: advanced
347: Reference:
348: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
349: inexact Newton method", SISC 17 (1), pp.16-32, 1996.
351: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
352: @*/
353: int SNES_KSP_SetConvergenceTestEW(SNES snes)
354: {
356: snes->ksp_ewconv = PETSC_TRUE;
357: return(0);
358: }
360: #undef __FUNCT__
362: /*@
363: SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
364: convergence criteria for the linear solvers within an inexact
365: Newton method.
367: Collective on SNES
368:
369: Input Parameters:
370: + snes - SNES context
371: . version - version 1 or 2 (default is 2)
372: . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
373: . rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
374: . alpha - power for version 2 rtol computation (1 < alpha <= 2)
375: . alpha2 - power for safeguard
376: . gamma2 - multiplicative factor for version 2 rtol computation
377: (0 <= gamma2 <= 1)
378: - threshold - threshold for imposing safeguard (0 < threshold < 1)
380: Note:
381: Use PETSC_DEFAULT to retain the default for any of the parameters.
383: Level: advanced
385: Reference:
386: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
387: inexact Newton method", Utah State University Math. Stat. Dept. Res.
388: Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
390: .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
392: .seealso: SNES_KSP_SetConvergenceTestEW()
393: @*/
394: int SNES_KSP_SetParametersEW(SNES snes,int version,PetscReal rtol_0,
395: PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
396: PetscReal alpha2,PetscReal threshold)
397: {
398: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
401: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
402: if (version != PETSC_DEFAULT) kctx->version = version;
403: if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0;
404: if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max;
405: if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2;
406: if (alpha != PETSC_DEFAULT) kctx->alpha = alpha;
407: if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2;
408: if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
409: if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
410: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
411: }
412: if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
413: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0n",kctx->rtol_max);
414: }
415: if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
416: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0n",kctx->threshold);
417: }
418: if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
419: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0n",kctx->gamma);
420: }
421: if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
422: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0n",kctx->alpha);
423: }
424: if (kctx->version != 1 && kctx->version !=2) {
425: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %d",kctx->version);
426: }
427: return(0);
428: }
430: #undef __FUNCT__
432: int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
433: {
434: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
435: PetscReal rtol = 0.0,stol;
436: int ierr;
439: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
440: if (!snes->iter) { /* first time in, so use the original user rtol */
441: rtol = kctx->rtol_0;
442: } else {
443: if (kctx->version == 1) {
444: rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
445: if (rtol < 0.0) rtol = -rtol;
446: stol = pow(kctx->rtol_last,kctx->alpha2);
447: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
448: } else if (kctx->version == 2) {
449: rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
450: stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
451: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
452: } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %d",kctx->version);
453: }
454: rtol = PetscMin(rtol,kctx->rtol_max);
455: kctx->rtol_last = rtol;
456: PetscLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %gn",snes->iter,kctx->version,rtol);
457: KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
458: kctx->norm_last = snes->norm;
459: return(0);
460: }
462: #undef __FUNCT__
464: int SNES_KSP_EW_Converged_Private(KSP ksp,int n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
465: {
466: SNES snes = (SNES)ctx;
467: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
468: int ierr;
471: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
472: if (n == 0) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
473: KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
474: kctx->lresid_last = rnorm;
475: if (*reason) {
476: PetscLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%gn",n,rnorm);
477: }
478: return(0);
479: }