xref: /petsc/src/snes/interface/snesut.c (revision be1d678a52e6eff2808b2fa31ae986cdbf03c9fe) !
1 
2 #include "src/snes/snesimpl.h"       /*I   "petscsnes.h"   I*/
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "SNESVecViewMonitor"
6 /*@C
7    SNESVecViewMonitor - Monitors progress of the SNES solvers by calling
8    VecView() for the approximate solution at each iteration.
9 
10    Collective on SNES
11 
12    Input Parameters:
13 +  snes - the SNES context
14 .  its - iteration number
15 .  fgnorm - 2-norm of residual
16 -  dummy - either a viewer or PETSC_NULL
17 
18    Level: intermediate
19 
20 .keywords: SNES, nonlinear, vector, monitor, view
21 
22 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
23 @*/
24 PetscErrorCode SNESVecViewMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
25 {
26   PetscErrorCode ierr;
27   Vec            x;
28   PetscViewer    viewer = (PetscViewer) dummy;
29 
30   PetscFunctionBegin;
31   ierr = SNESGetSolution(snes,&x);CHKERRQ(ierr);
32   if (!viewer) {
33     MPI_Comm comm;
34     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
35     viewer = PETSC_VIEWER_DRAW_(comm);
36   }
37   ierr = VecView(x,viewer);CHKERRQ(ierr);
38 
39   PetscFunctionReturn(0);
40 }
41 
42 #undef __FUNCT__
43 #define __FUNCT__ "SNESVecViewResidualMonitor"
44 /*@C
45    SNESVecViewResidualMonitor - Monitors progress of the SNES solvers by calling
46    VecView() for the residual at each iteration.
47 
48    Collective on SNES
49 
50    Input Parameters:
51 +  snes - the SNES context
52 .  its - iteration number
53 .  fgnorm - 2-norm of residual
54 -  dummy - either a viewer or PETSC_NULL
55 
56    Level: intermediate
57 
58 .keywords: SNES, nonlinear, vector, monitor, view
59 
60 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
61 @*/
62 PetscErrorCode SNESVecViewResidualMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
63 {
64   PetscErrorCode ierr;
65   Vec            x;
66   PetscViewer    viewer = (PetscViewer) dummy;
67 
68   PetscFunctionBegin;
69   ierr = SNESGetFunction(snes,&x,0,0);CHKERRQ(ierr);
70   if (!viewer) {
71     MPI_Comm comm;
72     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
73     viewer = PETSC_VIEWER_DRAW_(comm);
74   }
75   ierr = VecView(x,viewer);CHKERRQ(ierr);
76 
77   PetscFunctionReturn(0);
78 }
79 
80 #undef __FUNCT__
81 #define __FUNCT__ "SNESVecViewUpdateMonitor"
82 /*@C
83    SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling
84    VecView() for the UPDATE to the solution at each iteration.
85 
86    Collective on SNES
87 
88    Input Parameters:
89 +  snes - the SNES context
90 .  its - iteration number
91 .  fgnorm - 2-norm of residual
92 -  dummy - either a viewer or PETSC_NULL
93 
94    Level: intermediate
95 
96 .keywords: SNES, nonlinear, vector, monitor, view
97 
98 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
99 @*/
100 PetscErrorCode SNESVecViewUpdateMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
101 {
102   PetscErrorCode ierr;
103   Vec            x;
104   PetscViewer    viewer = (PetscViewer) dummy;
105 
106   PetscFunctionBegin;
107   ierr = SNESGetSolutionUpdate(snes,&x);CHKERRQ(ierr);
108   if (!viewer) {
109     MPI_Comm comm;
110     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
111     viewer = PETSC_VIEWER_DRAW_(comm);
112   }
113   ierr = VecView(x,viewer);CHKERRQ(ierr);
114 
115   PetscFunctionReturn(0);
116 }
117 
118 #undef __FUNCT__
119 #define __FUNCT__ "SNESDefaultMonitor"
120 /*@C
121    SNESDefaultMonitor - Monitors progress of the SNES solvers (default).
122 
123    Collective on SNES
124 
125    Input Parameters:
126 +  snes - the SNES context
127 .  its - iteration number
128 .  fgnorm - 2-norm of residual
129 -  dummy - unused context
130 
131    Notes:
132    This routine prints the residual norm at each iteration.
133 
134    Level: intermediate
135 
136 .keywords: SNES, nonlinear, default, monitor, norm
137 
138 .seealso: SNESSetMonitor(), SNESVecViewMonitor()
139 @*/
140 PetscErrorCode SNESDefaultMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
141 {
142   PetscErrorCode ierr;
143   PetscViewer    viewer = (PetscViewer) dummy;
144 
145   PetscFunctionBegin;
146   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
147   ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr);
148   PetscFunctionReturn(0);
149 }
150 
151 #undef __FUNCT__
152 #define __FUNCT__ "SNESRatioMonitor"
153 /*@C
154    SNESRatioMonitor - Monitors progress of the SNES solvers by printing the ratio
155    of residual norm at each iteration to the previous.
156 
157    Collective on SNES
158 
159    Input Parameters:
160 +  snes - the SNES context
161 .  its - iteration number
162 .  fgnorm - 2-norm of residual (or gradient)
163 -  dummy - unused context
164 
165    Level: intermediate
166 
167 .keywords: SNES, nonlinear, monitor, norm
168 
169 .seealso: SNESSetMonitor(), SNESVecViewMonitor()
170 @*/
171 PetscErrorCode SNESRatioMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
172 {
173   PetscErrorCode ierr;
174   PetscInt       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 || !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 PetscErrorCode SNESRatioMonitorDestroy(void *history)
197 {
198   PetscErrorCode 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 PetscErrorCode SNESSetRatioMonitor(SNES snes)
223 {
224   PetscErrorCode 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 PetscErrorCode SNESDefaultSMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
251 {
252   PetscErrorCode 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 < abstol),
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 .    abstol - 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 PetscErrorCode SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
304 {
305   PetscErrorCode ierr;
306 
307   PetscFunctionBegin;
308   if (fnorm != fnorm) {
309     ierr = PetscLogInfo((snes,"SNESConverged_LS:Failed to converged, function norm is NaN\n"));CHKERRQ(ierr);
310     *reason = SNES_DIVERGED_FNORM_NAN;
311   } else if (fnorm <= snes->ttol) {
312     ierr = PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol));CHKERRQ(ierr);
313     *reason = SNES_CONVERGED_FNORM_RELATIVE;
314   } else if (fnorm < snes->abstol) {
315     ierr = PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g\n",fnorm,snes->abstol));CHKERRQ(ierr);
316     *reason = SNES_CONVERGED_FNORM_ABS;
317   } else if (pnorm < snes->xtol*xnorm) {
318     ierr = PetscLogInfo((snes,"SNESConverged_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm));CHKERRQ(ierr);
319     *reason = SNES_CONVERGED_PNORM_RELATIVE;
320   } else if (snes->nfuncs >= snes->max_funcs) {
321     ierr = PetscLogInfo((snes,"SNESConverged_LS:Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs));CHKERRQ(ierr);
322     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
323   } else {
324     *reason = SNES_CONVERGED_ITERATING;
325   }
326   PetscFunctionReturn(0);
327 }
328 /* ------------------------------------------------------------ */
329 #undef __FUNCT__
330 #define __FUNCT__ "SNES_KSP_SetConvergenceTestEW"
331 /*@
332    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
333    for the linear solvers within an inexact Newton method.
334 
335    Collective on SNES
336 
337    Input Parameter:
338 .  snes - SNES context
339 
340    Notes:
341    Currently, the default is to use a constant relative tolerance for
342    the inner linear solvers.  Alternatively, one can use the
343    Eisenstat-Walker method, where the relative convergence tolerance
344    is reset at each Newton iteration according progress of the nonlinear
345    solver.
346 
347    Level: advanced
348 
349    Reference:
350    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
351    inexact Newton method", SISC 17 (1), pp.16-32, 1996.
352 
353 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
354 @*/
355 PetscErrorCode SNES_KSP_SetConvergenceTestEW(SNES snes)
356 {
357   PetscFunctionBegin;
358   snes->ksp_ewconv = PETSC_TRUE;
359   PetscFunctionReturn(0);
360 }
361 
362 #undef __FUNCT__
363 #define __FUNCT__ "SNES_KSP_SetParametersEW"
364 /*@
365    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
366    convergence criteria for the linear solvers within an inexact
367    Newton method.
368 
369    Collective on SNES
370 
371    Input Parameters:
372 +    snes - SNES context
373 .    version - version 1 or 2 (default is 2)
374 .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
375 .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
376 .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
377 .    alpha2 - power for safeguard
378 .    gamma2 - multiplicative factor for version 2 rtol computation
379               (0 <= gamma2 <= 1)
380 -    threshold - threshold for imposing safeguard (0 < threshold < 1)
381 
382    Note:
383    Use PETSC_DEFAULT to retain the default for any of the parameters.
384 
385    Level: advanced
386 
387    Reference:
388    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
389    inexact Newton method", Utah State University Math. Stat. Dept. Res.
390    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
391 
392 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
393 
394 .seealso: SNES_KSP_SetConvergenceTestEW()
395 @*/
396 PetscErrorCode SNES_KSP_SetParametersEW(SNES snes,PetscInt version,PetscReal rtol_0,PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
397                                         PetscReal alpha2,PetscReal threshold)
398 {
399   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
400 
401   PetscFunctionBegin;
402   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
403   if (version != PETSC_DEFAULT)   kctx->version   = version;
404   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
405   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
406   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
407   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
408   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
409   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
410   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
411     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
412   }
413   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
414     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0\n",kctx->rtol_max);
415   }
416   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
417     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0\n",kctx->threshold);
418   }
419   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
420     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0\n",kctx->gamma);
421   }
422   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
423     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0\n",kctx->alpha);
424   }
425   if (kctx->version != 1 && kctx->version !=2) {
426     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %D",kctx->version);
427   }
428   PetscFunctionReturn(0);
429 }
430 
431 #undef __FUNCT__
432 #define __FUNCT__ "SNES_KSP_EW_ComputeRelativeTolerance_Private"
433 PetscErrorCode SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
434 {
435   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
436   PetscReal           rtol = 0.0,stol;
437   PetscErrorCode      ierr;
438 
439   PetscFunctionBegin;
440   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
441   if (!snes->iter) { /* first time in, so use the original user rtol */
442     rtol = kctx->rtol_0;
443   } else {
444     if (kctx->version == 1) {
445       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
446       if (rtol < 0.0) rtol = -rtol;
447       stol = pow(kctx->rtol_last,kctx->alpha2);
448       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
449     } else if (kctx->version == 2) {
450       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
451       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
452       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
453     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %D",kctx->version);
454   }
455   rtol = PetscMin(rtol,kctx->rtol_max);
456   kctx->rtol_last = rtol;
457   ierr = PetscLogInfo((snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %D, Eisenstat-Walker (version %D) KSP rtol = %g\n",snes->iter,kctx->version,rtol));CHKERRQ(ierr);
458   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
459   kctx->norm_last = snes->norm;
460   PetscFunctionReturn(0);
461 }
462 
463 #undef __FUNCT__
464 #define __FUNCT__ "SNES_KSP_EW_Converged_Private"
465 PetscErrorCode SNES_KSP_EW_Converged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
466 {
467   SNES                snes = (SNES)ctx;
468   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
469   PetscErrorCode      ierr;
470 
471   PetscFunctionBegin;
472   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
473   if (!n) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);}
474   ierr = KSPDefaultConverged(ksp,n,rnorm,reason,ctx);CHKERRQ(ierr);
475   kctx->lresid_last = rnorm;
476   if (*reason) {
477     ierr = PetscLogInfo((snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%D, rnorm=%g\n",n,rnorm));CHKERRQ(ierr);
478   }
479   PetscFunctionReturn(0);
480 }
481 
482 
483