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