xref: /petsc/src/snes/interface/snesut.c (revision c8a8475e04bcaa43590892a5c3e60c6f87bc31f7)
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
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__ "SNESVecViewResidualMonitor"
45 /*@C
46    SNESVecViewResidualMonitor - Monitors progress of the SNES solvers by calling
47    VecView() for the residual 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
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 SNESVecViewResidualMonitor(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 = SNESGetFunction(snes,&x,0,0);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__ "SNESVecViewUpdateMonitor"
83 /*@C
84    SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling
85    VecView() for the UPDATE to the solution at each iteration.
86 
87    Collective on SNES
88 
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
94 
95    Level: intermediate
96 
97 .keywords: SNES, nonlinear, vector, monitor, view
98 
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;
106 
107   PetscFunctionBegin;
108   ierr = SNESGetSolutionUpdate(snes,&x);CHKERRQ(ierr);
109   if (!viewer) {
110     MPI_Comm comm;
111     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
112     viewer = PETSC_VIEWER_DRAW_(comm);
113   }
114   ierr = VecView(x,viewer);CHKERRQ(ierr);
115 
116   PetscFunctionReturn(0);
117 }
118 
119 #undef __FUNCT__
120 #define __FUNCT__ "SNESDefaultMonitor"
121 /*@C
122    SNESDefaultMonitor - Monitors progress of the SNES solvers (default).
123 
124    Collective on SNES
125 
126    Input Parameters:
127 +  snes - the SNES context
128 .  its - iteration number
129 .  fgnorm - 2-norm of residual
130 -  dummy - unused context
131 
132    Notes:
133    This routine prints the residual norm at each iteration.
134 
135    Level: intermediate
136 
137 .keywords: SNES, nonlinear, default, monitor, norm
138 
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;
145 
146   PetscFunctionBegin;
147   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
148   ierr = PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr);
149   PetscFunctionReturn(0);
150 }
151 
152 #undef __FUNCT__
153 #define __FUNCT__ "SNESRatioMonitor"
154 /*@C
155    SNESRatioMonitor - Monitors progress of the SNES solvers by printing the ratio
156    of residual norm at each iteration to the previous.
157 
158    Collective on SNES
159 
160    Input Parameters:
161 +  snes - the SNES context
162 .  its - iteration number
163 .  fgnorm - 2-norm of residual (or gradient)
164 -  dummy - unused context
165 
166    Level: intermediate
167 
168 .keywords: SNES, nonlinear, monitor, norm
169 
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;
177 
178   PetscFunctionBegin;
179   viewer = PETSC_VIEWER_STDOUT_(snes->comm);
180 
181   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);CHKERRQ(ierr);
182   if (its == 0 || !history || its > len) {
183     ierr = PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr);
184   } else {
185     PetscReal ratio = fgnorm/history[its-1];
186     ierr = PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e %g \n",its,fgnorm,ratio);CHKERRQ(ierr);
187   }
188   PetscFunctionReturn(0);
189 }
190 
191 /*
192    If the we set the history monitor space then we must destroy it
193 */
194 #undef __FUNCT__
195 #define __FUNCT__ "SNESRatioMonitorDestroy"
196 int SNESRatioMonitorDestroy(void *history)
197 {
198   int         ierr;
199 
200   PetscFunctionBegin;
201   ierr = PetscFree(history);CHKERRQ(ierr);
202   PetscFunctionReturn(0);
203 }
204 
205 #undef __FUNCT__
206 #define __FUNCT__ "SNESSetRatioMonitor"
207 /*@C
208    SNESSetRatioMonitor - Sets SNES to use a monitor that prints the
209    ratio of the function norm at each iteration.
210 
211    Collective on SNES
212 
213    Input Parameters:
214 .   snes - the SNES context
215 
216    Level: intermediate
217 
218 .keywords: SNES, nonlinear, monitor, norm
219 
220 .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
221 @*/
222 int SNESSetRatioMonitor(SNES snes)
223 {
224   int       ierr;
225   PetscReal *history;
226 
227   PetscFunctionBegin;
228 
229   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
230   if (!history) {
231     ierr = PetscMalloc(100*sizeof(double),&history);CHKERRQ(ierr);
232     ierr = SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);CHKERRQ(ierr);
233     ierr = SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);CHKERRQ(ierr);
234   } else {
235     ierr = SNESSetMonitor(snes,SNESRatioMonitor,0,0);CHKERRQ(ierr);
236   }
237   PetscFunctionReturn(0);
238 }
239 
240 /* ---------------------------------------------------------------- */
241 #undef __FUNCT__
242 #define __FUNCT__ "SNESDefaultSMonitor"
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 {
252   int ierr;
253 
254   PetscFunctionBegin;
255   if (fgnorm > 1.e-9) {
256     ierr = PetscPrintf(snes->comm,"%3d SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr);
257   } else if (fgnorm > 1.e-11){
258     ierr = PetscPrintf(snes->comm,"%3d SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr);
259   } else {
260     ierr = PetscPrintf(snes->comm,"%3d SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr);
261   }
262   PetscFunctionReturn(0);
263 }
264 /* ---------------------------------------------------------------- */
265 #undef __FUNCT__
266 #define __FUNCT__ "SNESConverged_LS"
267 /*@C
268    SNESConverged_LS - Monitors the convergence of the solvers for
269    systems of nonlinear equations (default).
270 
271    Collective on SNES
272 
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
279 
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),
288 
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()
296 
297    Level: intermediate
298 
299 .keywords: SNES, nonlinear, default, converged, convergence
300 
301 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
302 @*/
303 int SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
304 {
305   PetscFunctionBegin;
306   if (fnorm != fnorm) {
307     PetscLogInfo(snes,"SNESConverged_LS:Failed to converged, function norm is NaN\n");
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 < %g\n",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 * %g\n",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 > %d\n",snes->nfuncs,snes->max_funcs);
320     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
321   } else {
322     *reason = SNES_CONVERGED_ITERATING;
323   }
324   PetscFunctionReturn(0);
325 }
326 /* ------------------------------------------------------------ */
327 #undef __FUNCT__
328 #define __FUNCT__ "SNES_KSP_SetConvergenceTestEW"
329 /*@
330    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
331    for the linear solvers within an inexact Newton method.
332 
333    Collective on SNES
334 
335    Input Parameter:
336 .  snes - SNES context
337 
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.
344 
345    Level: advanced
346 
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.
350 
351 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
352 @*/
353 int SNES_KSP_SetConvergenceTestEW(SNES snes)
354 {
355   PetscFunctionBegin;
356   snes->ksp_ewconv = PETSC_TRUE;
357   PetscFunctionReturn(0);
358 }
359 
360 #undef __FUNCT__
361 #define __FUNCT__ "SNES_KSP_SetParametersEW"
362 /*@
363    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
364    convergence criteria for the linear solvers within an inexact
365    Newton method.
366 
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)
379 
380    Note:
381    Use PETSC_DEFAULT to retain the default for any of the parameters.
382 
383    Level: advanced
384 
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.
389 
390 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
391 
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;
399 
400   PetscFunctionBegin;
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.0\n",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.0\n",kctx->threshold);
417   }
418   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
419     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0\n",kctx->gamma);
420   }
421   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
422     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0\n",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   PetscFunctionReturn(0);
428 }
429 
430 #undef __FUNCT__
431 #define __FUNCT__ "SNES_KSP_EW_ComputeRelativeTolerance_Private"
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;
437 
438   PetscFunctionBegin;
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 = %g\n",snes->iter,kctx->version,rtol);
457   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
458   kctx->norm_last = snes->norm;
459   PetscFunctionReturn(0);
460 }
461 
462 #undef __FUNCT__
463 #define __FUNCT__ "SNES_KSP_EW_Converged_Private"
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;
469 
470   PetscFunctionBegin;
471   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
472   if (n == 0) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);}
473   ierr = KSPDefaultConverged(ksp,n,rnorm,reason,ctx);CHKERRQ(ierr);
474   kctx->lresid_last = rnorm;
475   if (*reason) {
476     PetscLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm);
477   }
478   PetscFunctionReturn(0);
479 }
480 
481 
482