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 (or gradient)
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: SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling
43: VecView() for the UPDATE to the solution 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 (or gradient)
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 SNESVecViewUpdateMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
60: {
61: int ierr;
62: Vec x;
63: PetscViewer viewer = (PetscViewer) dummy;
66: SNESGetSolutionUpdate(snes,&x);
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: SNESDefaultMonitor - Monitoring progress of the SNES solvers (default).
80: Collective on SNES
82: Input Parameters:
83: + snes - the SNES context
84: . its - iteration number
85: . fgnorm - 2-norm of residual (or gradient)
86: - dummy - unused context
88: Notes:
89: For SNES_NONLINEAR_EQUATIONS methods the routine prints the
90: residual norm at each iteration.
92: For SNES_UNCONSTRAINED_MINIMIZATION methods the routine prints the
93: function value and gradient norm at each iteration.
95: Level: intermediate
97: .keywords: SNES, nonlinear, default, monitor, norm
99: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
100: @*/
101: int SNESDefaultMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
102: {
103: int ierr;
104: PetscViewer viewer = (PetscViewer) dummy;
107: if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
109: if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
110: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
111: } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
112: PetscViewerASCIIPrintf(viewer,"%3d SNES Function value %14.12e, Gradient norm %14.12e n",its,snes->fc,fgnorm);
113: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown method class");
114: return(0);
115: }
117: /*@C
118: SNESRatioMonitor - Monitoring progress of the SNES solvers, prints ratio
119: of residual norm at each iteration to previous
121: Collective on SNES
123: Input Parameters:
124: + snes - the SNES context
125: . its - iteration number
126: . fgnorm - 2-norm of residual (or gradient)
127: - dummy - unused context
129: Level: intermediate
131: .keywords: SNES, nonlinear, monitor, norm
133: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
134: @*/
135: int SNESRatioMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
136: {
137: int ierr,len;
138: PetscReal *history;
139: PetscViewer viewer;
142: viewer = PETSC_VIEWER_STDOUT_(snes->comm);
144: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
145: if (its == 0 || !history || its > len) {
146: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
147: } else {
148: PetscReal ratio = fgnorm/history[its-1];
149: PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e %g n",its,fgnorm,ratio);
150: }
151: return(0);
152: }
154: /*
155: If the we set the history monitor space then we must destroy it
156: */
157: int SNESRatioMonitorDestroy(void *history)
158: {
159: int ierr;
162: PetscFree(history);
163: return(0);
164: }
166: /*@C
167: SNESSetRatioMonitor - Sets SNES to use a monitor that prints the
168: ratio of the function norm at each iteration
170: Collective on SNES
172: Input Parameters:
173: . snes - the SNES context
175: Level: intermediate
177: .keywords: SNES, nonlinear, monitor, norm
179: .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
180: @*/
181: int SNESSetRatioMonitor(SNES snes)
182: {
183: int ierr;
184: PetscReal *history;
188: SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
189: if (!history) {
190: PetscMalloc(100*sizeof(double),&history);
191: SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);
192: SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);
193: } else {
194: SNESSetMonitor(snes,SNESRatioMonitor,0,0);
195: }
196: return(0);
197: }
199: /* ---------------------------------------------------------------- */
200: /*
201: Default (short) SNES Monitor, same as SNESDefaultMonitor() except
202: it prints fewer digits of the residual as the residual gets smaller.
203: This is because the later digits are meaningless and are often
204: different on different machines; by using this routine different
205: machines will usually generate the same output.
206: */
207: int SNESDefaultSMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
208: {
212: if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
213: if (fgnorm > 1.e-9) {
214: PetscPrintf(snes->comm,"%3d SNES Function norm %g n",its,fgnorm);
215: } else if (fgnorm > 1.e-11){
216: PetscPrintf(snes->comm,"%3d SNES Function norm %5.3e n",its,fgnorm);
217: } else {
218: PetscPrintf(snes->comm,"%3d SNES Function norm < 1.e-11n",its);
219: }
220: } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
221: if (fgnorm > 1.e-9) {
222: PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm %g n",its,snes->fc,fgnorm);
223: } else if (fgnorm > 1.e-11) {
224: PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm %5.3e n",its,snes->fc,fgnorm);
225: } else {
226: PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm < 1.e-11n",its,snes->fc);
227: }
228: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown method class");
229: return(0);
230: }
231: /* ---------------------------------------------------------------- */
232: /*@C
233: SNESConverged_EQ_LS - Monitors the convergence of the solvers for
234: systems of nonlinear equations (default).
236: Collective on SNES
238: Input Parameters:
239: + snes - the SNES context
240: . xnorm - 2-norm of current iterate
241: . pnorm - 2-norm of current step
242: . fnorm - 2-norm of function
243: - dummy - unused context
245: Output Parameter:
246: . reason - one of
247: $ SNES_CONVERGED_FNORM_ABS - (fnorm < atol),
248: $ SNES_CONVERGED_PNORM_RELATIVE - (pnorm < xtol*xnorm),
249: $ SNES_CONVERGED_FNORM_RELATIVE - (fnorm < rtol*fnorm0),
250: $ SNES_DIVERGED_FUNCTION_COUNT - (nfct > maxf),
251: $ SNES_DIVERGED_FNORM_NAN - (fnorm == NaN),
252: $ SNES_CONVERGED_ITERATING - (otherwise),
254: where
255: + maxf - maximum number of function evaluations,
256: set with SNESSetTolerances()
257: . nfct - number of function evaluations,
258: . atol - absolute function norm tolerance,
259: set with SNESSetTolerances()
260: - rtol - relative function norm tolerance, set with SNESSetTolerances()
262: Level: intermediate
264: .keywords: SNES, nonlinear, default, converged, convergence
266: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
267: @*/
268: int SNESConverged_EQ_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
269: {
271: if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
272: SETERRQ(PETSC_ERR_ARG_WRONG,"For SNES_NONLINEAR_EQUATIONS only");
273: }
275: if (fnorm != fnorm) {
276: PetscLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaNn");
277: *reason = SNES_DIVERGED_FNORM_NAN;
278: } else if (fnorm <= snes->ttol) {
279: PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)n",fnorm,snes->ttol);
280: *reason = SNES_CONVERGED_FNORM_RELATIVE;
281: } else if (fnorm < snes->atol) {
282: PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %gn",fnorm,snes->atol);
283: *reason = SNES_CONVERGED_FNORM_ABS;
284: } else if (pnorm < snes->xtol*(xnorm)) {
285: PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %gn",pnorm,snes->xtol,xnorm);
286: *reason = SNES_CONVERGED_PNORM_RELATIVE;
287: } else if (snes->nfuncs > snes->max_funcs) {
288: PetscLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %dn",snes->nfuncs,snes->max_funcs);
289: *reason = SNES_DIVERGED_FUNCTION_COUNT ;
290: } else {
291: *reason = SNES_CONVERGED_ITERATING;
292: }
293: return(0);
294: }
295: /* ------------------------------------------------------------ */
296: /*@
297: SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
298: for the linear solvers within an inexact Newton method.
300: Collective on SNES
302: Input Parameter:
303: . snes - SNES context
305: Notes:
306: Currently, the default is to use a constant relative tolerance for
307: the inner linear solvers. Alternatively, one can use the
308: Eisenstat-Walker method, where the relative convergence tolerance
309: is reset at each Newton iteration according progress of the nonlinear
310: solver.
312: Level: advanced
314: Reference:
315: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
316: inexact Newton method", SISC 17 (1), pp.16-32, 1996.
318: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
319: @*/
320: int SNES_KSP_SetConvergenceTestEW(SNES snes)
321: {
323: snes->ksp_ewconv = PETSC_TRUE;
324: return(0);
325: }
327: /*@
328: SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
329: convergence criteria for the linear solvers within an inexact
330: Newton method.
332: Collective on SNES
333:
334: Input Parameters:
335: + snes - SNES context
336: . version - version 1 or 2 (default is 2)
337: . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
338: . rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
339: . alpha - power for version 2 rtol computation (1 < alpha <= 2)
340: . alpha2 - power for safeguard
341: . gamma2 - multiplicative factor for version 2 rtol computation
342: (0 <= gamma2 <= 1)
343: - threshold - threshold for imposing safeguard (0 < threshold < 1)
345: Note:
346: Use PETSC_DEFAULT to retain the default for any of the parameters.
348: Level: advanced
350: Reference:
351: S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
352: inexact Newton method", Utah State University Math. Stat. Dept. Res.
353: Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
355: .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
357: .seealso: SNES_KSP_SetConvergenceTestEW()
358: @*/
359: int SNES_KSP_SetParametersEW(SNES snes,int version,PetscReal rtol_0,
360: PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
361: PetscReal alpha2,PetscReal threshold)
362: {
363: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
366: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
367: if (version != PETSC_DEFAULT) kctx->version = version;
368: if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0;
369: if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max;
370: if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2;
371: if (alpha != PETSC_DEFAULT) kctx->alpha = alpha;
372: if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2;
373: if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
374: if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
375: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
376: }
377: if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
378: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0n",kctx->rtol_max);
379: }
380: if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
381: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0n",kctx->threshold);
382: }
383: if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
384: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0n",kctx->gamma);
385: }
386: if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
387: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0n",kctx->alpha);
388: }
389: if (kctx->version != 1 && kctx->version !=2) {
390: SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %d",kctx->version);
391: }
392: return(0);
393: }
395: int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
396: {
397: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
398: PetscReal rtol = 0.0,stol;
399: int ierr;
402: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
403: if (!snes->iter) { /* first time in, so use the original user rtol */
404: rtol = kctx->rtol_0;
405: } else {
406: if (kctx->version == 1) {
407: rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
408: if (rtol < 0.0) rtol = -rtol;
409: stol = pow(kctx->rtol_last,kctx->alpha2);
410: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
411: } else if (kctx->version == 2) {
412: rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
413: stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
414: if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
415: } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %d",kctx->version);
416: }
417: rtol = PetscMin(rtol,kctx->rtol_max);
418: kctx->rtol_last = rtol;
419: PetscLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %gn",snes->iter,kctx->version,rtol);
420: KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
421: kctx->norm_last = snes->norm;
422: return(0);
423: }
425: int SNES_KSP_EW_Converged_Private(KSP ksp,int n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
426: {
427: SNES snes = (SNES)ctx;
428: SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
429: int ierr;
432: if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
433: if (n == 0) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
434: KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
435: kctx->lresid_last = rnorm;
436: if (*reason) {
437: PetscLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%gn",n,rnorm);
438: }
439: return(0);
440: }