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