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