xref: /petsc/src/snes/interface/snesut.c (revision 549d3d68a6ae470532d58d544870024f02ff2d7c)
1 #ifdef PETSC_RCS_HEADER
2 static char vcid[] = "$Id: snesut.c,v 1.46 1999/04/19 22:15:28 bsmith Exp balay $";
3 #endif
4 
5 #include "src/snes/snesimpl.h"       /*I   "snes.h"   I*/
6 
7 #undef __FUNC__
8 #define __FUNC__ "SNESVecViewMonitor"
9 /*@C
10    SNESVecViewMonitor - Monitors progress of the SNES solvers by calling
11    VecView() for the approximate solution at each iteration.
12 
13    Collective on SNES
14 
15    Input Parameters:
16 +  snes - the SNES context
17 .  its - iteration number
18 .  fgnorm - 2-norm of residual (or gradient)
19 -  dummy - either a viewer or PETSC_NULL
20 
21    Level: intermediate
22 
23 .keywords: SNES, nonlinear, vector, monitor, view
24 
25 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
26 @*/
27 int SNESVecViewMonitor(SNES snes,int its,double fgnorm,void *dummy)
28 {
29   int    ierr;
30   Vec    x;
31   Viewer viewer = (Viewer) dummy;
32 
33   PetscFunctionBegin;
34   ierr = SNESGetSolution(snes,&x);CHKERRQ(ierr);
35   if (!viewer) {
36     MPI_Comm comm;
37     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
38     viewer = VIEWER_DRAW_(comm);
39   }
40   ierr = VecView(x,viewer);CHKERRQ(ierr);
41 
42   PetscFunctionReturn(0);
43 }
44 
45 #undef __FUNC__
46 #define __FUNC__ "SNESVecViewMonitorUpdate"
47 /*@C
48    SNESVecViewMonitorUpdate - Monitors progress of the SNES solvers by calling
49    VecView() for the UPDATE to the solution at each iteration.
50 
51    Collective on SNES
52 
53    Input Parameters:
54 +  snes - the SNES context
55 .  its - iteration number
56 .  fgnorm - 2-norm of residual (or gradient)
57 -  dummy - either a viewer or PETSC_NULL
58 
59    Level: intermediate
60 
61 .keywords: SNES, nonlinear, vector, monitor, view
62 
63 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
64 @*/
65 int SNESVecViewMonitorUpdate(SNES snes,int its,double fgnorm,void *dummy)
66 {
67   int    ierr;
68   Vec    x;
69   Viewer viewer = (Viewer) dummy;
70 
71   PetscFunctionBegin;
72   ierr = SNESGetSolutionUpdate(snes,&x);CHKERRQ(ierr);
73   if (!viewer) {
74     MPI_Comm comm;
75     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
76     viewer = VIEWER_DRAW_(comm);
77   }
78   ierr = VecView(x,viewer);CHKERRQ(ierr);
79 
80   PetscFunctionReturn(0);
81 }
82 
83 #undef __FUNC__
84 #define __FUNC__ "SNESDefaultMonitor"
85 /*@C
86    SNESDefaultMonitor - Monitoring progress of the SNES solvers (default).
87 
88    Collective on SNES
89 
90    Input Parameters:
91 +  snes - the SNES context
92 .  its - iteration number
93 .  fgnorm - 2-norm of residual (or gradient)
94 -  dummy - unused context
95 
96    Notes:
97    For SNES_NONLINEAR_EQUATIONS methods the routine prints the
98    residual norm at each iteration.
99 
100    For SNES_UNCONSTRAINED_MINIMIZATION methods the routine prints the
101    function value and gradient norm at each iteration.
102 
103    Level: intermediate
104 
105 .keywords: SNES, nonlinear, default, monitor, norm
106 
107 .seealso: SNESSetMonitor(), SNESVecViewMonitor()
108 @*/
109 int SNESDefaultMonitor(SNES snes,int its,double fgnorm,void *dummy)
110 {
111   int ierr;
112 
113   PetscFunctionBegin;
114   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
115     ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr);
116   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
117     ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
118   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
119   PetscFunctionReturn(0);
120 }
121 
122 /* ---------------------------------------------------------------- */
123 #undef __FUNC__
124 #define __FUNC__ "SNESDefaultSMonitor"
125 /*
126      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
127   it prints fewer digits of the residual as the residual gets smaller.
128   This is because the later digits are meaningless and are often
129   different on different machines; by using this routine different
130   machines will usually generate the same output.
131 */
132 int SNESDefaultSMonitor(SNES snes,int its, double fgnorm,void *dummy)
133 {
134   int ierr;
135 
136   PetscFunctionBegin;
137   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
138     if (fgnorm > 1.e-9) {
139       ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr);
140     } else if (fgnorm > 1.e-11){
141       ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr);
142     } else {
143       ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr);
144     }
145   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
146     if (fgnorm > 1.e-9) {
147       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
148     } else if (fgnorm > 1.e-11) {
149       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %5.3e \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
150     } else {
151       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm < 1.e-11\n",its,snes->fc);CHKERRQ(ierr);
152     }
153   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
154   PetscFunctionReturn(0);
155 }
156 /* ---------------------------------------------------------------- */
157 #undef __FUNC__
158 #define __FUNC__ "SNESConverged_EQ_LS"
159 /*@C
160    SNESConverged_EQ_LS - Monitors the convergence of the solvers for
161    systems of nonlinear equations (default).
162 
163    Collective on SNES
164 
165    Input Parameters:
166 +  snes - the SNES context
167 .  xnorm - 2-norm of current iterate
168 .  pnorm - 2-norm of current step
169 .  fnorm - 2-norm of function
170 -  dummy - unused context
171 
172    Returns:
173 +  2  - if  ( fnorm < atol ),
174 .  3  - if  ( pnorm < xtol*xnorm ),
175 .  4  - if  ( fnorm < rtol*fnorm0 ),
176 . -2  - if  ( nfct > maxf ),
177 -  0  - 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,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   /* Note:  Reserve return code 1, -1 for compatibility with SNESConverged_EQ_TR */
200   if (fnorm != fnorm) {
201     PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n");
202     PetscFunctionReturn(-3);
203   }
204   if (fnorm <= snes->ttol) {
205     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol);
206     PetscFunctionReturn(4);
207   }
208 
209   if (fnorm < snes->atol) {
210     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g\n",fnorm,snes->atol);
211     PetscFunctionReturn(2);
212   }
213   if (pnorm < snes->xtol*(xnorm)) {
214     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm);
215     PetscFunctionReturn(3);
216   }
217   if (snes->nfuncs > snes->max_funcs) {
218     PLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %d\n",snes->nfuncs, snes->max_funcs);
219     PetscFunctionReturn(-2);
220   }
221   PetscFunctionReturn(0);
222 }
223 /* ------------------------------------------------------------ */
224 #undef __FUNC__
225 #define __FUNC__ "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 = 1;
254   PetscFunctionReturn(0);
255 }
256 
257 #undef __FUNC__
258 #define __FUNC__ "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,double rtol_0,
292                              double rtol_max,double gamma2,double alpha,
293                              double alpha2,double 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__ "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   double              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 == 1) {
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,"SNESConverged_EQ_LS: 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__ "SNES_KSP_EW_Converged_Private"
361 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx)
362 {
363   SNES                snes = (SNES)ctx;
364   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
365   int                 convinfo;
366 
367   PetscFunctionBegin;
368   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set");
369   if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);
370   convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx);
371   kctx->lresid_last = rnorm;
372   if (convinfo) {
373     PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm);
374   }
375   PetscFunctionReturn(convinfo);
376 }
377 
378 
379