xref: /petsc/src/snes/interface/snesut.c (revision 4bbc92c1ffdc419abb1af95adee3d231624e4f0c)
1 /*$Id: snesut.c,v 1.58 2000/08/01 20:57:16 bsmith Exp bsmith $*/
2 
3 #include "src/snes/snesimpl.h"       /*I   "petscsnes.h"   I*/
4 
5 #undef __FUNC__
6 #define __FUNC__ /*<a name=""></a>*/"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   Viewer viewer = (Viewer) 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 = VIEWER_DRAW_(comm);
37   }
38   ierr = VecView(x,viewer);CHKERRQ(ierr);
39 
40   PetscFunctionReturn(0);
41 }
42 
43 #undef __FUNC__
44 #define __FUNC__ /*<a name=""></a>*/"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   Viewer viewer = (Viewer) 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 = VIEWER_DRAW_(comm);
75   }
76   ierr = VecView(x,viewer);CHKERRQ(ierr);
77 
78   PetscFunctionReturn(0);
79 }
80 
81 #undef __FUNC__
82 #define __FUNC__ /*<a name=""></a>*/"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   Viewer viewer = (Viewer) dummy;
111 
112   PetscFunctionBegin;
113   if (!viewer) viewer = VIEWER_STDOUT_(snes->comm);
114 
115   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
116     ierr = ViewerASCIIPrintf(viewer,"iter = %d, SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr);
117   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
118     ierr = ViewerASCIIPrintf(viewer,"iter = %d, SNES Function value %14.12e, Gradient norm %14.12e \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
119   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
120   PetscFunctionReturn(0);
121 }
122 
123 /* ---------------------------------------------------------------- */
124 #undef __FUNC__
125 #define __FUNC__ /*<a name=""></a>*/"SNESDefaultSMonitor"
126 /*
127      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
128   it prints fewer digits of the residual as the residual gets smaller.
129   This is because the later digits are meaningless and are often
130   different on different machines; by using this routine different
131   machines will usually generate the same output.
132 */
133 int SNESDefaultSMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
134 {
135   int ierr;
136 
137   PetscFunctionBegin;
138   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
139     if (fgnorm > 1.e-9) {
140       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr);
141     } else if (fgnorm > 1.e-11){
142       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr);
143     } else {
144       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr);
145     }
146   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
147     if (fgnorm > 1.e-9) {
148       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
149     } else if (fgnorm > 1.e-11) {
150       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %5.3e \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
151     } else {
152       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm < 1.e-11\n",its,snes->fc);CHKERRQ(ierr);
153     }
154   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
155   PetscFunctionReturn(0);
156 }
157 /* ---------------------------------------------------------------- */
158 #undef __FUNC__
159 #define __FUNC__ /*<a name=""></a>*/"SNESConverged_EQ_LS"
160 /*@C
161    SNESConverged_EQ_LS - Monitors the convergence of the solvers for
162    systems of nonlinear equations (default).
163 
164    Collective on SNES
165 
166    Input Parameters:
167 +  snes - the SNES context
168 .  xnorm - 2-norm of current iterate
169 .  pnorm - 2-norm of current step
170 .  fnorm - 2-norm of function
171 -  dummy - unused context
172 
173    Output Parameter:
174 .   reason  - one of
175 $  SNES_CONVERGED_FNORM_ABS       - (fnorm < atol),
176 $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
177 $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
178 $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
179 $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
180 $  SNES_CONVERGED_ITERATING       - (otherwise),
181 
182    where
183 +    maxf - maximum number of function evaluations,
184             set with SNESSetTolerances()
185 .    nfct - number of function evaluations,
186 .    atol - absolute function norm tolerance,
187             set with SNESSetTolerances()
188 -    rtol - relative function norm tolerance, set with SNESSetTolerances()
189 
190    Level: intermediate
191 
192 .keywords: SNES, nonlinear, default, converged, convergence
193 
194 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
195 @*/
196 int SNESConverged_EQ_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
197 {
198   PetscFunctionBegin;
199   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
200      SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only");
201   }
202 
203   if (fnorm != fnorm) {
204     PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n");
205     *reason = SNES_DIVERGED_FNORM_NAN;
206   } else if (fnorm <= snes->ttol) {
207     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol);
208     *reason = SNES_CONVERGED_FNORM_RELATIVE;
209   } else if (fnorm < snes->atol) {
210     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g\n",fnorm,snes->atol);
211     *reason = SNES_CONVERGED_FNORM_ABS;
212   } else if (pnorm < snes->xtol*(xnorm)) {
213     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm);
214     *reason = SNES_CONVERGED_PNORM_RELATIVE;
215   } else if (snes->nfuncs > snes->max_funcs) {
216     PLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %d\n",snes->nfuncs,snes->max_funcs);
217     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
218   } else {
219     *reason = SNES_CONVERGED_ITERATING;
220   }
221   PetscFunctionReturn(0);
222 }
223 /* ------------------------------------------------------------ */
224 #undef __FUNC__
225 #define __FUNC__ /*<a name=""></a>*/"SNES_KSP_SetConvergenceTestEW"
226 /*@
227    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
228    for the linear solvers within an inexact Newton method.
229 
230    Collective on SNES
231 
232    Input Parameter:
233 .  snes - SNES context
234 
235    Notes:
236    Currently, the default is to use a constant relative tolerance for
237    the inner linear solvers.  Alternatively, one can use the
238    Eisenstat-Walker method, where the relative convergence tolerance
239    is reset at each Newton iteration according progress of the nonlinear
240    solver.
241 
242    Level: advanced
243 
244    Reference:
245    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
246    inexact Newton method", SISC 17 (1), pp.16-32, 1996.
247 
248 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
249 @*/
250 int SNES_KSP_SetConvergenceTestEW(SNES snes)
251 {
252   PetscFunctionBegin;
253   snes->ksp_ewconv = PETSC_TRUE;
254   PetscFunctionReturn(0);
255 }
256 
257 #undef __FUNC__
258 #define __FUNC__ /*<a name=""></a>*/"SNES_KSP_SetParametersEW"
259 /*@
260    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
261    convergence criteria for the linear solvers within an inexact
262    Newton method.
263 
264    Collective on SNES
265 
266    Input Parameters:
267 +    snes - SNES context
268 .    version - version 1 or 2 (default is 2)
269 .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
270 .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
271 .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
272 .    alpha2 - power for safeguard
273 .    gamma2 - multiplicative factor for version 2 rtol computation
274               (0 <= gamma2 <= 1)
275 -    threshold - threshold for imposing safeguard (0 < threshold < 1)
276 
277    Note:
278    Use PETSC_DEFAULT to retain the default for any of the parameters.
279 
280    Level: advanced
281 
282    Reference:
283    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
284    inexact Newton method", Utah State University Math. Stat. Dept. Res.
285    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
286 
287 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
288 
289 .seealso: SNES_KSP_SetConvergenceTestEW()
290 @*/
291 int SNES_KSP_SetParametersEW(SNES snes,int version,PetscReal rtol_0,
292                              PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
293                              PetscReal alpha2,PetscReal threshold)
294 {
295   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
296 
297   PetscFunctionBegin;
298   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing");
299   if (version != PETSC_DEFAULT)   kctx->version   = version;
300   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
301   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
302   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
303   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
304   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
305   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
306   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
307     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
308   }
309   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
310     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n",kctx->rtol_max);
311   }
312   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
313     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n",kctx->threshold);
314   }
315   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
316     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n",kctx->gamma);
317   }
318   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
319     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n",kctx->alpha);
320   }
321   if (kctx->version != 1 && kctx->version !=2) {
322     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported: %d",kctx->version);
323   }
324   PetscFunctionReturn(0);
325 }
326 
327 #undef __FUNC__
328 #define __FUNC__ /*<a name=""></a>*/"SNES_KSP_EW_ComputeRelativeTolerance_Private"
329 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
330 {
331   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
332   PetscReal           rtol = 0.0,stol;
333   int                 ierr;
334 
335   PetscFunctionBegin;
336   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists");
337   if (!snes->iter) { /* first time in, so use the original user rtol */
338     rtol = kctx->rtol_0;
339   } else {
340     if (kctx->version == 1) {
341       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
342       if (rtol < 0.0) rtol = -rtol;
343       stol = pow(kctx->rtol_last,kctx->alpha2);
344       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
345     } else if (kctx->version == 2) {
346       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
347       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
348       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
349     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported: %d",kctx->version);
350   }
351   rtol = PetscMin(rtol,kctx->rtol_max);
352   kctx->rtol_last = rtol;
353   PLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",snes->iter,kctx->version,rtol);
354   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
355   kctx->norm_last = snes->norm;
356   PetscFunctionReturn(0);
357 }
358 
359 #undef __FUNC__
360 #define __FUNC__ /*<a name=""></a>*/"SNES_KSP_EW_Converged_Private"
361 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
362 {
363   SNES                snes = (SNES)ctx;
364   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
365   int                 ierr;
366 
367   PetscFunctionBegin;
368   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set");
369   if (n == 0) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);}
370   ierr = KSPDefaultConverged(ksp,n,rnorm,reason,ctx);CHKERRQ(ierr);
371   kctx->lresid_last = rnorm;
372   if (*reason) {
373     PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm);
374   }
375   PetscFunctionReturn(0);
376 }
377 
378 
379