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