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