xref: /petsc/src/snes/interface/snesut.c (revision f68b968ce39302dfa79eb1a6cfa1998ce074e829)
1 #define PETSCSNES_DLL
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 PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
26 {
27   PetscErrorCode 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 PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewResidualMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
64 {
65   PetscErrorCode 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 PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewUpdateMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
102 {
103   PetscErrorCode 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 PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
142 {
143   PetscErrorCode 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 typedef struct {
153   PetscViewer viewer;
154   PetscReal   *history;
155 } SNESRatioMonitorContext;
156 
157 #undef __FUNCT__
158 #define __FUNCT__ "SNESRatioMonitor"
159 /*@C
160    SNESRatioMonitor - Monitors progress of the SNES solvers by printing the ratio
161    of residual norm at each iteration to the previous.
162 
163    Collective on SNES
164 
165    Input Parameters:
166 +  snes - the SNES context
167 .  its - iteration number
168 .  fgnorm - 2-norm of residual (or gradient)
169 -  dummy -  context of monitor
170 
171    Level: intermediate
172 
173 .keywords: SNES, nonlinear, monitor, norm
174 
175 .seealso: SNESSetMonitor(), SNESVecViewMonitor()
176 @*/
177 PetscErrorCode PETSCSNES_DLLEXPORT SNESRatioMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
178 {
179   PetscErrorCode          ierr;
180   PetscInt                len;
181   PetscReal               *history;
182   SNESRatioMonitorContext *ctx = (SNESRatioMonitorContext*)dummy;
183 
184   PetscFunctionBegin;
185   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);CHKERRQ(ierr);
186   if (!its || !history || its > len) {
187     ierr = PetscViewerASCIIPrintf(ctx->viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr);
188   } else {
189     PetscReal ratio = fgnorm/history[its-1];
190     ierr = PetscViewerASCIIPrintf(ctx->viewer,"%3D SNES Function norm %14.12e %g \n",its,fgnorm,ratio);CHKERRQ(ierr);
191   }
192   PetscFunctionReturn(0);
193 }
194 
195 /*
196    If the we set the history monitor space then we must destroy it
197 */
198 #undef __FUNCT__
199 #define __FUNCT__ "SNESRatioMonitorDestroy"
200 PetscErrorCode SNESRatioMonitorDestroy(void *ct)
201 {
202   PetscErrorCode          ierr;
203   SNESRatioMonitorContext *ctx = (SNESRatioMonitorContext*)ct;
204 
205   PetscFunctionBegin;
206   if (ctx->history) {ierr = PetscFree(ctx->history);CHKERRQ(ierr);}
207   ierr = PetscViewerDestroy(ctx->viewer);CHKERRQ(ierr);
208   ierr = PetscFree(ctx);CHKERRQ(ierr);
209   PetscFunctionReturn(0);
210 }
211 
212 #undef __FUNCT__
213 #define __FUNCT__ "SNESSetRatioMonitor"
214 /*@C
215    SNESSetRatioMonitor - Sets SNES to use a monitor that prints the
216    ratio of the function norm at each iteration.
217 
218    Collective on SNES
219 
220    Input Parameters:
221 +   snes - the SNES context
222 -   viewer - ASCII viewer to print output
223 
224    Level: intermediate
225 
226 .keywords: SNES, nonlinear, monitor, norm
227 
228 .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
229 @*/
230 PetscErrorCode PETSCSNES_DLLEXPORT SNESSetRatioMonitor(SNES snes,PetscViewer viewer)
231 {
232   PetscErrorCode          ierr;
233   SNESRatioMonitorContext *ctx;
234   PetscReal               *history;
235 
236   PetscFunctionBegin;
237   if (!viewer) {
238     viewer = PETSC_VIEWER_STDOUT_(snes->comm);
239     ierr   = PetscObjectReference((PetscObject)viewer);CHKERRQ(ierr);
240   }
241   ierr = PetscNew(SNESRatioMonitorContext,&ctx);
242   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
243   if (!history) {
244     ierr = PetscMalloc(100*sizeof(PetscReal),&ctx->history);CHKERRQ(ierr);
245     ierr = SNESSetConvergenceHistory(snes,ctx->history,0,100,PETSC_TRUE);CHKERRQ(ierr);
246   }
247   ctx->viewer = viewer;
248   ierr = SNESSetMonitor(snes,SNESRatioMonitor,ctx,SNESRatioMonitorDestroy);CHKERRQ(ierr);
249   PetscFunctionReturn(0);
250 }
251 
252 /* ---------------------------------------------------------------- */
253 #undef __FUNCT__
254 #define __FUNCT__ "SNESDefaultSMonitor"
255 /*
256      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
257   it prints fewer digits of the residual as the residual gets smaller.
258   This is because the later digits are meaningless and are often
259   different on different machines; by using this routine different
260   machines will usually generate the same output.
261 */
262 PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultSMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
263 {
264   PetscErrorCode ierr;
265   PetscViewer    viewer = (PetscViewer) dummy;
266 
267   PetscFunctionBegin;
268   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
269   if (fgnorm > 1.e-9) {
270     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr);
271   } else if (fgnorm > 1.e-11){
272     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr);
273   } else {
274     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr);
275   }
276   PetscFunctionReturn(0);
277 }
278 /* ---------------------------------------------------------------- */
279 #undef __FUNCT__
280 #define __FUNCT__ "SNESConverged_LS"
281 /*@C
282    SNESConverged_LS - Monitors the convergence of the solvers for
283    systems of nonlinear equations (default).
284 
285    Collective on SNES
286 
287    Input Parameters:
288 +  snes - the SNES context
289 .  xnorm - 2-norm of current iterate
290 .  pnorm - 2-norm of current step
291 .  fnorm - 2-norm of function
292 -  dummy - unused context
293 
294    Output Parameter:
295 .   reason  - one of
296 $  SNES_CONVERGED_FNORM_ABS       - (fnorm < abstol),
297 $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
298 $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
299 $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
300 $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
301 $  SNES_CONVERGED_ITERATING       - (otherwise),
302 
303    where
304 +    maxf - maximum number of function evaluations,
305             set with SNESSetTolerances()
306 .    nfct - number of function evaluations,
307 .    abstol - absolute function norm tolerance,
308             set with SNESSetTolerances()
309 -    rtol - relative function norm tolerance, set with SNESSetTolerances()
310 
311    Level: intermediate
312 
313 .keywords: SNES, nonlinear, default, converged, convergence
314 
315 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
316 @*/
317 PetscErrorCode PETSCSNES_DLLEXPORT SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
318 {
319   PetscErrorCode ierr;
320 
321   PetscFunctionBegin;
322   if (fnorm != fnorm) {
323     ierr = PetscLogInfo((snes,"SNESConverged_LS:Failed to converged, function norm is NaN\n"));CHKERRQ(ierr);
324     *reason = SNES_DIVERGED_FNORM_NAN;
325   } else if (fnorm <= snes->ttol) {
326     ierr = PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol));CHKERRQ(ierr);
327     *reason = SNES_CONVERGED_FNORM_RELATIVE;
328   } else if (fnorm < snes->abstol) {
329     ierr = PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g\n",fnorm,snes->abstol));CHKERRQ(ierr);
330     *reason = SNES_CONVERGED_FNORM_ABS;
331   } else if (pnorm < snes->xtol*xnorm) {
332     ierr = PetscLogInfo((snes,"SNESConverged_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm));CHKERRQ(ierr);
333     *reason = SNES_CONVERGED_PNORM_RELATIVE;
334   } else if (snes->nfuncs >= snes->max_funcs) {
335     ierr = PetscLogInfo((snes,"SNESConverged_LS:Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs));CHKERRQ(ierr);
336     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
337   } else {
338     *reason = SNES_CONVERGED_ITERATING;
339   }
340   PetscFunctionReturn(0);
341 }
342 /* ------------------------------------------------------------ */
343 #undef __FUNCT__
344 #define __FUNCT__ "SNES_KSP_SetConvergenceTestEW"
345 /*@
346    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
347    for the linear solvers within an inexact Newton method.
348 
349    Collective on SNES
350 
351    Input Parameter:
352 .  snes - SNES context
353 
354    Notes:
355    Currently, the default is to use a constant relative tolerance for
356    the inner linear solvers.  Alternatively, one can use the
357    Eisenstat-Walker method, where the relative convergence tolerance
358    is reset at each Newton iteration according progress of the nonlinear
359    solver.
360 
361    Level: advanced
362 
363    Reference:
364    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
365    inexact Newton method", SISC 17 (1), pp.16-32, 1996.
366 
367 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
368 @*/
369 PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetConvergenceTestEW(SNES snes)
370 {
371   PetscFunctionBegin;
372   snes->ksp_ewconv = PETSC_TRUE;
373   PetscFunctionReturn(0);
374 }
375 
376 #undef __FUNCT__
377 #define __FUNCT__ "SNES_KSP_SetParametersEW"
378 /*@
379    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
380    convergence criteria for the linear solvers within an inexact
381    Newton method.
382 
383    Collective on SNES
384 
385    Input Parameters:
386 +    snes - SNES context
387 .    version - version 1 or 2 (default is 2)
388 .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
389 .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
390 .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
391 .    alpha2 - power for safeguard
392 .    gamma2 - multiplicative factor for version 2 rtol computation
393               (0 <= gamma2 <= 1)
394 -    threshold - threshold for imposing safeguard (0 < threshold < 1)
395 
396    Note:
397    Use PETSC_DEFAULT to retain the default for any of the parameters.
398 
399    Level: advanced
400 
401    Reference:
402    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
403    inexact Newton method", Utah State University Math. Stat. Dept. Res.
404    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
405 
406 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
407 
408 .seealso: SNES_KSP_SetConvergenceTestEW()
409 @*/
410 PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetParametersEW(SNES snes,PetscInt version,PetscReal rtol_0,PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
411                                         PetscReal alpha2,PetscReal threshold)
412 {
413   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
414 
415   PetscFunctionBegin;
416   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
417   if (version != PETSC_DEFAULT)   kctx->version   = version;
418   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
419   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
420   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
421   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
422   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
423   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
424   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
425     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
426   }
427   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
428     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0\n",kctx->rtol_max);
429   }
430   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
431     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0\n",kctx->threshold);
432   }
433   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
434     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0\n",kctx->gamma);
435   }
436   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
437     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0\n",kctx->alpha);
438   }
439   if (kctx->version != 1 && kctx->version !=2) {
440     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %D",kctx->version);
441   }
442   PetscFunctionReturn(0);
443 }
444 
445 #undef __FUNCT__
446 #define __FUNCT__ "SNES_KSP_EW_ComputeRelativeTolerance_Private"
447 PetscErrorCode SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
448 {
449   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
450   PetscReal           rtol = 0.0,stol;
451   PetscErrorCode      ierr;
452 
453   PetscFunctionBegin;
454   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
455   if (!snes->iter) { /* first time in, so use the original user rtol */
456     rtol = kctx->rtol_0;
457   } else {
458     if (kctx->version == 1) {
459       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
460       if (rtol < 0.0) rtol = -rtol;
461       stol = pow(kctx->rtol_last,kctx->alpha2);
462       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
463     } else if (kctx->version == 2) {
464       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
465       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
466       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
467     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %D",kctx->version);
468   }
469   rtol = PetscMin(rtol,kctx->rtol_max);
470   kctx->rtol_last = rtol;
471   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);
472   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
473   kctx->norm_last = snes->norm;
474   PetscFunctionReturn(0);
475 }
476 
477 #undef __FUNCT__
478 #define __FUNCT__ "SNES_KSP_EW_Converged_Private"
479 PetscErrorCode SNES_KSP_EW_Converged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
480 {
481   SNES                snes = (SNES)ctx;
482   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
483   PetscErrorCode      ierr;
484 
485   PetscFunctionBegin;
486   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
487   if (!n) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);}
488   ierr = KSPDefaultConverged(ksp,n,rnorm,reason,ctx);CHKERRQ(ierr);
489   kctx->lresid_last = rnorm;
490   if (*reason) {
491     ierr = PetscLogInfo((snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%D, rnorm=%g\n",n,rnorm));CHKERRQ(ierr);
492   }
493   PetscFunctionReturn(0);
494 }
495 
496 
497