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: /*@C
6: SNESVecViewMonitor - Monitors progress of the SNES solvers by calling
7: VecView() for the approximate solution at each iteration.
9: Collective on SNES
11: Input Parameters:
12: + snes - the SNES context
13: . its - iteration number
14: . fgnorm - 2-norm of residual
15: - dummy - either a viewer or PETSC_NULL
17: Level: intermediate
19: .keywords: SNES, nonlinear, vector, monitor, view
21: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
22: @*/
23: int SNESVecViewMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
24: {
25: int ierr;
26: Vec x;
27: PetscViewer viewer = (PetscViewer) dummy;
30: SNESGetSolution(snes,&x);
31: if (!viewer) {
32: MPI_Comm comm;
33: ierr = PetscObjectGetComm((PetscObject)snes,&comm);
34: viewer = PETSC_VIEWER_DRAW_(comm);
35: }
36: VecView(x,viewer);
38: return(0);
39: }
41: /*@C
42: SNESVecViewResidualMonitor - Monitors progress of the SNES solvers by calling
43: VecView() for the residual at each iteration.
45: Collective on SNES
47: Input Parameters:
48: + snes - the SNES context
49: . its - iteration number
50: . fgnorm - 2-norm of residual
51: - dummy - either a viewer or PETSC_NULL
53: Level: intermediate
55: .keywords: SNES, nonlinear, vector, monitor, view
57: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
58: @*/
59: int SNESVecViewResidualMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
60: {
61: int ierr;
62: Vec x;
63: PetscViewer viewer = (PetscViewer) dummy;
66: SNESGetFunction(snes,&x,0,0);
67: if (!viewer) {
68: MPI_Comm comm;
69: ierr = PetscObjectGetComm((PetscObject)snes,&comm);
70: viewer = PETSC_VIEWER_DRAW_(comm);
71: }
72: VecView(x,viewer);
74: return(0);
75: }
77: /*@C
78: SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling
79: VecView() for the UPDATE to the solution at each iteration.
81: Collective on SNES
83: Input Parameters:
84: + snes - the SNES context
85: . its - iteration number
86: . fgnorm - 2-norm of residual
87: - dummy - either a viewer or PETSC_NULL
89: Level: intermediate
91: .keywords: SNES, nonlinear, vector, monitor, view
93: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
94: @*/
95: int SNESVecViewUpdateMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
96: {
97: int ierr;
98: Vec x;
99: PetscViewer viewer = (PetscViewer) dummy;
102: SNESGetSolutionUpdate(snes,&x);
103: if (!viewer) {
104: MPI_Comm comm;
105: ierr = PetscObjectGetComm((PetscObject)snes,&comm);
106: viewer = PETSC_VIEWER_DRAW_(comm);
107: }
108: VecView(x,viewer);
110: return(0);
111: }
113: /*@C
114: SNESDefaultMonitor - Monitors progress of the SNES solvers (default).
116: Collective on SNES
118: Input Parameters:
119: + snes - the SNES context
120: . its - iteration number
121: . fgnorm - 2-norm of residual
122: - dummy - unused context
124: Notes:
125: This routine prints the residual norm at each iteration.
127: Level: intermediate
129: .keywords: SNES, nonlinear, default, monitor, norm
131: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
132: @*/
133: int SNESDefaultMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
134: {
135: int ierr;
136: PetscViewer viewer = (PetscViewer) dummy;
139: if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
140: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
141: return(0);
142: }
144: /*@C
145: SNESRatioMonitor - Monitors progress of the SNES solvers by printing the ratio
146: of residual norm at each iteration to the previous.
148: Collective on SNES
150: Input Parameters:
151: + snes - the SNES context
152: . its - iteration number
153: . fgnorm - 2-norm of residual (or gradient)
154: - dummy - unused context
156: Level: intermediate
158: .keywords: SNES, nonlinear, monitor, norm
160: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
161: @*/
162: int SNESRatioMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
163: {
164: int ierr,len;
165: PetscReal *history;
166: PetscViewer viewer;
169: viewer = PETSC_VIEWER_STDOUT_(snes->comm);
171: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
172: if (its == 0 || !history || its > len) {
173: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
174: } else {
175: PetscReal ratio = fgnorm/history[its-1];
176: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e %g n",its,fgnorm,ratio);
177: }
178: return(0);
179: }
181: /*
182: If the we set the history monitor space then we must destroy it
183: */
184: int SNESRatioMonitorDestroy(void *history)
185: {
186: int ierr;
189: PetscFree(history);
190: return(0);
191: }
193: /*@C
194: SNESSetRatioMonitor - Sets SNES to use a monitor that prints the
195: ratio of the function norm at each iteration.
197: Collective on SNES
199: Input Parameters:
200: . snes - the SNES context
202: Level: intermediate
204: .keywords: SNES, nonlinear, monitor, norm
206: .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
207: @*/
208: int SNESSetRatioMonitor(SNES snes)
209: {
210: int ierr;
211: PetscReal *history;
215: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
216: if (!history) {
217: PetscMalloc(100*sizeof(double),&history);
218: SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);
219: SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);
220: } else {
221: SNESSetMonitor(snes,SNESRatioMonitor,0,0);
222: }
223: return(0);
224: }
226: /* ---------------------------------------------------------------- */
227: /*
228: Default (short) SNES Monitor, same as SNESDefaultMonitor() except
229: it prints fewer digits of the residual as the residual gets smaller.
230: This is because the later digits are meaningless and are often
231: different on different machines; by using this routine different
232: machines will usually generate the same output.
233: */
234: int SNESDefaultSMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
235: {
239: if (fgnorm > 1.e-9) {
240: PetscPrintf(snes->comm,"%3d SNES Function norm %g n",its,fgnorm);
241: } else if (fgnorm > 1.e-11){
242: PetscPrintf(snes->comm,"%3d SNES Function norm %5.3e n",its,fgnorm);
243: } else {
244: PetscPrintf(snes->comm,"%3d SNES Function norm < 1.e-11n",its);
245: }
246: return(0);
247: }
248: /* ---------------------------------------------------------------- */
249: /*@C
250: SNESConverged_LS - Monitors the convergence of the solvers for
251: systems of nonlinear equations (default).
253: Collective on SNES
255: Input Parameters:
256: + snes - the SNES context
257: . xnorm - 2-norm of current iterate
258: . pnorm - 2-norm of current step
259: . fnorm - 2-norm of function
260: - dummy - unused context
262: Output Parameter:
263: . reason - one of
264: $ SNES_CONVERGED_FNORM_ABS - (fnorm < atol),
265: $ SNES_CONVERGED_PNORM_RELATIVE - (pnorm < xtol*xnorm),
266: $ SNES_CONVERGED_FNORM_RELATIVE - (fnorm < rtol*fnorm0),
267: $ SNES_DIVERGED_FUNCTION_COUNT - (nfct > maxf),
268: $ SNES_DIVERGED_FNORM_NAN - (fnorm == NaN),
269: $ SNES_CONVERGED_ITERATING - (otherwise),
271: where
272: + maxf - maximum number of function evaluations,
273: set with SNESSetTolerances()
274: . nfct - number of function evaluations,
275: . atol - absolute function norm tolerance,
276: set with SNESSetTolerances()
277: - rtol - relative function norm tolerance, set with SNESSetTolerances()
279: Level: intermediate
281: .keywords: SNES, nonlinear, default, converged, convergence
283: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
284: @*/
285: int SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
286: {
288: if (fnorm != fnorm) {
289: PetscLogInfo(snes,"SNESConverged_LS:Failed to converged, function norm is NaNn");
290: *reason = SNES_DIVERGED_FNORM_NAN;
291: } else if (fnorm <= snes->ttol) {
292: PetscLogInfo(snes,"SNESConverged_LS:Converged due to function norm %g < %g (relative tolerance)n",fnorm,snes->ttol);
293: *reason = SNES_CONVERGED_FNORM_RELATIVE;
294: } else if (fnorm < snes->atol) {
295: PetscLogInfo(snes,"SNESConverged_LS:Converged due to function norm %g < %gn",fnorm,snes->atol);
296: *reason = SNES_CONVERGED_FNORM_ABS;
297: } else if (pnorm < snes->xtol*xnorm) {
298: PetscLogInfo(snes,"SNESConverged_LS:Converged due to small update length: %g < %g * %gn",pnorm,snes->xtol,xnorm);
299: *reason = SNES_CONVERGED_PNORM_RELATIVE;
300: } else if (snes->nfuncs > snes->max_funcs) {
301: PetscLogInfo(snes,"SNESConverged_LS:Exceeded maximum number of function evaluations: %d > %dn",snes->nfuncs,snes->max_funcs);
302: *reason = SNES_DIVERGED_FUNCTION_COUNT ;
303: } else {
304: *reason = SNES_CONVERGED_ITERATING;
305: }
306: return(0);
307: }
308: /* ------------------------------------------------------------ */
309: /*@
310: SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
311: for the linear solvers within an inexact Newton method.
313: Collective on SNES
315: Input Parameter:
316: . snes - SNES context
318: Notes:
319: Currently, the default is to use a constant relative tolerance for
320: the inner linear solvers. Alternatively, one can use the
321: Eisenstat-Walker method, where the relative convergence tolerance
322: is reset at each Newton iteration according progress of the nonlinear
323: solver.
325: Level: advanced
327: Reference:
328: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
329: inexact Newton method", SISC 17 (1), pp.16-32, 1996.
331: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
332: @*/
333: int SNES_KSP_SetConvergenceTestEW(SNES snes)
334: {
336: snes->ksp_ewconv = PETSC_TRUE;
337: return(0);
338: }
340: /*@
341: SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
342: convergence criteria for the linear solvers within an inexact
343: Newton method.
345: Collective on SNES
346:
347: Input Parameters:
348: + snes - SNES context
349: . version - version 1 or 2 (default is 2)
350: . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
351: . rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
352: . alpha - power for version 2 rtol computation (1 < alpha <= 2)
353: . alpha2 - power for safeguard
354: . gamma2 - multiplicative factor for version 2 rtol computation
355: (0 <= gamma2 <= 1)
356: - threshold - threshold for imposing safeguard (0 < threshold < 1)
358: Note:
359: Use PETSC_DEFAULT to retain the default for any of the parameters.
361: Level: advanced
363: Reference:
364: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
365: inexact Newton method", Utah State University Math. Stat. Dept. Res.
366: Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
368: .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
370: .seealso: SNES_KSP_SetConvergenceTestEW()
371: @*/
372: int SNES_KSP_SetParametersEW(SNES snes,int version,PetscReal rtol_0,
373: PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
374: PetscReal alpha2,PetscReal threshold)
375: {
376: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
379: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
380: if (version != PETSC_DEFAULT) kctx->version = version;
381: if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0;
382: if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max;
383: if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2;
384: if (alpha != PETSC_DEFAULT) kctx->alpha = alpha;
385: if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2;
386: if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
387: if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
388: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
389: }
390: if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
391: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0n",kctx->rtol_max);
392: }
393: if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
394: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0n",kctx->threshold);
395: }
396: if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
397: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0n",kctx->gamma);
398: }
399: if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
400: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0n",kctx->alpha);
401: }
402: if (kctx->version != 1 && kctx->version !=2) {
403: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %d",kctx->version);
404: }
405: return(0);
406: }
408: int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
409: {
410: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
411: PetscReal rtol = 0.0,stol;
412: int ierr;
415: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
416: if (!snes->iter) { /* first time in, so use the original user rtol */
417: rtol = kctx->rtol_0;
418: } else {
419: if (kctx->version == 1) {
420: rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
421: if (rtol < 0.0) rtol = -rtol;
422: stol = pow(kctx->rtol_last,kctx->alpha2);
423: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
424: } else if (kctx->version == 2) {
425: rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
426: stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
427: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
428: } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %d",kctx->version);
429: }
430: rtol = PetscMin(rtol,kctx->rtol_max);
431: kctx->rtol_last = rtol;
432: PetscLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %gn",snes->iter,kctx->version,rtol);
433: KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
434: kctx->norm_last = snes->norm;
435: return(0);
436: }
438: int SNES_KSP_EW_Converged_Private(KSP ksp,int n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
439: {
440: SNES snes = (SNES)ctx;
441: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
442: int ierr;
445: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
446: if (n == 0) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
447: KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
448: kctx->lresid_last = rnorm;
449: if (*reason) {
450: PetscLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%gn",n,rnorm);
451: }
452: return(0);
453: }