xref: /petsc/src/snes/interface/snesut.c (revision 3f1db9ec2fd39765c6c3a00831044586630c4cca)
1 #ifdef PETSC_RCS_HEADER
2 static char vcid[] = "$Id: snesut.c,v 1.40 1998/12/03 04:05:20 bsmith Exp bsmith $";
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 - Monitoring progress of the SNES solvers, by calling
11        VecView() on the solution 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    Notes:
22 
23 .keywords: SNES, nonlinear, default, monitor, norm
24 
25 .seealso: SNESSetMonitor(), SNESDefaultMonitor()
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_DRAWX_(comm);
39   }
40   ierr = VecView(x,viewer);CHKERRQ(ierr);
41 
42   PetscFunctionReturn(0);
43 }
44 
45 #undef __FUNC__
46 #define __FUNC__ "SNESDefaultMonitor"
47 /*@C
48    SNESDefaultMonitor - Monitoring progress of the SNES solvers (default).
49 
50    Collective on SNES
51 
52    Input Parameters:
53 +  snes - the SNES context
54 .  its - iteration number
55 .  fgnorm - 2-norm of residual (or gradient)
56 -  dummy - unused context
57 
58    Notes:
59    For SNES_NONLINEAR_EQUATIONS methods the routine prints the
60    residual norm at each iteration.
61 
62    For SNES_UNCONSTRAINED_MINIMIZATION methods the routine prints the
63    function value and gradient norm at each iteration.
64 
65 .keywords: SNES, nonlinear, default, monitor, norm
66 
67 .seealso: SNESSetMonitor()
68 @*/
69 int SNESDefaultMonitor(SNES snes,int its,double fgnorm,void *dummy)
70 {
71   PetscFunctionBegin;
72   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
73     PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);
74   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
75     PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);
76   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
77   PetscFunctionReturn(0);
78 }
79 
80 /* ---------------------------------------------------------------- */
81 #undef __FUNC__
82 #define __FUNC__ "SNESDefaultSMonitor"
83 /*
84      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
85   it prints fewer digits of the residual as the residual gets smaller.
86   This is because the later digits are meaningless and are often
87   different on different machines; by using this routine different
88   machines will usually generate the same output.
89 */
90 int SNESDefaultSMonitor(SNES snes,int its, double fgnorm,void *dummy)
91 {
92   PetscFunctionBegin;
93   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
94     if (fgnorm > 1.e-9) {
95       PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);
96     } else if (fgnorm > 1.e-11){
97       PetscPrintf(snes->comm, "iter = %d, SNES Function norm %5.3e \n",its,fgnorm);
98     } else {
99       PetscPrintf(snes->comm, "iter = %d, SNES Function norm < 1.e-11\n",its);
100     }
101   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
102     if (fgnorm > 1.e-9) {
103       PetscPrintf(snes->comm,
104        "iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);
105     } else if (fgnorm > 1.e-11) {
106       PetscPrintf(snes->comm,
107         "iter = %d, SNES Function value %g, Gradient norm %5.3e \n",its,snes->fc,fgnorm);
108     } else {
109       PetscPrintf(snes->comm,
110         "iter = %d, SNES Function value %g, Gradient norm < 1.e-11\n",its,snes->fc);
111     }
112   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
113   PetscFunctionReturn(0);
114 }
115 /* ---------------------------------------------------------------- */
116 #undef __FUNC__
117 #define __FUNC__ "SNESConverged_EQ_LS"
118 /*@C
119    SNESConverged_EQ_LS - Monitors the convergence of the solvers for
120    systems of nonlinear equations (default).
121 
122    Collective on SNES
123 
124    Input Parameters:
125 +  snes - the SNES context
126 .  xnorm - 2-norm of current iterate
127 .  pnorm - 2-norm of current step
128 .  fnorm - 2-norm of function
129 -  dummy - unused context
130 
131    Returns:
132 +  2  - if  ( fnorm < atol ),
133 .  3  - if  ( pnorm < xtol*xnorm ),
134 .  4  - if  ( fnorm < rtol*fnorm0 ),
135 . -2  - if  ( nfct > maxf ),
136 -  0  - otherwise,
137 
138    where
139 +    maxf - maximum number of function evaluations,
140             set with SNESSetTolerances()
141 .    nfct - number of function evaluations,
142 .    atol - absolute function norm tolerance,
143             set with SNESSetTolerances()
144 -    rtol - relative function norm tolerance, set with SNESSetTolerances()
145 
146 .keywords: SNES, nonlinear, default, converged, convergence
147 
148 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
149 @*/
150 int SNESConverged_EQ_LS(SNES snes,double xnorm,double pnorm,double fnorm,void *dummy)
151 {
152   PetscFunctionBegin;
153   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
154      SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only");
155   }
156   /* Note:  Reserve return code 1, -1 for compatibility with SNESConverged_EQ_TR */
157   if (fnorm != fnorm) {
158     PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n");
159     PetscFunctionReturn(-3);
160   }
161   if (fnorm <= snes->ttol) {
162     PLogInfo(snes,
163     "SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol);
164     PetscFunctionReturn(4);
165   }
166 
167   if (fnorm < snes->atol) {
168     PLogInfo(snes,
169       "SNESConverged_EQ_LS: Converged due to function norm %g < %g\n",fnorm,snes->atol);
170     PetscFunctionReturn(2);
171   }
172   if (pnorm < snes->xtol*(xnorm)) {
173     PLogInfo(snes,
174       "SNESConverged_EQ_LS: Converged due to small update length: %g < %g * %g\n",
175        pnorm,snes->xtol,xnorm);
176     PetscFunctionReturn(3);
177   }
178   if (snes->nfuncs > snes->max_funcs) {
179     PLogInfo(snes,"SNESConverged_EQ_LS: Exceeded maximum number of function evaluations: %d > %d\n",
180       snes->nfuncs, snes->max_funcs );
181     PetscFunctionReturn(-2);
182   }
183   PetscFunctionReturn(0);
184 }
185 /* ------------------------------------------------------------ */
186 #undef __FUNC__
187 #define __FUNC__ "SNES_KSP_SetConvergenceTestEW"
188 /*@
189    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
190    for the linear solvers within an inexact Newton method.
191 
192    Collective on SNES
193 
194    Input Parameter:
195 .  snes - SNES context
196 
197    Notes:
198    Currently, the default is to use a constant relative tolerance for
199    the inner linear solvers.  Alternatively, one can use the
200    Eisenstat-Walker method, where the relative convergence tolerance
201    is reset at each Newton iteration according progress of the nonlinear
202    solver.
203 
204    Reference:
205    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
206    inexact Newton method", SISC 17 (1), pp.16-32, 1996.
207 
208 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
209 @*/
210 int SNES_KSP_SetConvergenceTestEW(SNES snes)
211 {
212   PetscFunctionBegin;
213   snes->ksp_ewconv = 1;
214   PetscFunctionReturn(0);
215 }
216 
217 #undef __FUNC__
218 #define __FUNC__ "SNES_KSP_SetParametersEW"
219 /*@
220    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
221    convergence criteria for the linear solvers within an inexact
222    Newton method.
223 
224    Collective on SNES
225 
226    Input Parameters:
227 +    snes - SNES context
228 .    version - version 1 or 2 (default is 2)
229 .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
230 .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
231 .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
232 .    alpha2 - power for safeguard
233 .    gamma2 - multiplicative factor for version 2 rtol computation
234               (0 <= gamma2 <= 1)
235 -    threshold - threshold for imposing safeguard (0 < threshold < 1)
236 
237    Note:
238    Use PETSC_DEFAULT to retain the default for any of the parameters.
239 
240    Reference:
241    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
242    inexact Newton method", Utah State University Math. Stat. Dept. Res.
243    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
244 
245 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
246 
247 .seealso: SNES_KSP_SetConvergenceTestEW()
248 @*/
249 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0,
250                              double rtol_max,double gamma2,double alpha,
251                              double alpha2,double threshold)
252 {
253   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
254 
255   PetscFunctionBegin;
256   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing");
257   if (version != PETSC_DEFAULT)   kctx->version = version;
258   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0 = rtol_0;
259   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max = rtol_max;
260   if (gamma2 != PETSC_DEFAULT)    kctx->gamma = gamma2;
261   if (alpha != PETSC_DEFAULT)     kctx->alpha = alpha;
262   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2 = alpha2;
263   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
264   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
265     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0\n");
266   }
267   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
268     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n");
269   }
270   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
271     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n");
272   }
273   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
274     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n");
275   }
276   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
277     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n");
278   }
279   if (kctx->version != 1 && kctx->version !=2) {
280     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported");
281   }
282   PetscFunctionReturn(0);
283 }
284 
285 #undef __FUNC__
286 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private"
287 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
288 {
289   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
290   double              rtol = 0.0, stol;
291   int                 ierr;
292 
293   PetscFunctionBegin;
294   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists");
295   if (snes->iter == 1) {
296     rtol = kctx->rtol_0;
297   } else {
298     if (kctx->version == 1) {
299       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
300       if (rtol < 0.0) rtol = -rtol;
301       stol = pow(kctx->rtol_last,kctx->alpha2);
302       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
303     } else if (kctx->version == 2) {
304       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
305       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
306       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
307     } else SETERRQ( PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported");
308   }
309   rtol = PetscMin(rtol,kctx->rtol_max);
310   kctx->rtol_last = rtol;
311   PLogInfo(snes,"SNESConverged_EQ_LS: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",
312            snes->iter,kctx->version,rtol);
313   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT); CHKERRQ(ierr);
314   kctx->norm_last = snes->norm;
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNC__
319 #define __FUNC__ "SNES_KSP_EW_Converged_Private"
320 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx)
321 {
322   SNES                snes = (SNES)ctx;
323   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
324   int                 convinfo;
325 
326   PetscFunctionBegin;
327   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set");
328   if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);
329   convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx);
330   kctx->lresid_last = rnorm;
331   if (convinfo) {
332     PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm);
333   }
334   PetscFunctionReturn(convinfo);
335 }
336 
337 
338