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