xref: /petsc/src/snes/interface/snesut.c (revision 77c4ece699e97450631aa6fc5b0ef04ff52df029)
1 #ifndef lint
2 static char vcid[] = "$Id: snesut.c,v 1.11 1996/01/24 05:47:18 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     PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);
32   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION)
33     PetscPrintf(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       PetscPrintf(snes->comm, "iter = %d, Function norm %g \n",its,fgnorm);
44     }
45     else if (fgnorm > 1.e-11){
46       PetscPrintf(snes->comm, "iter = %d, Function norm %5.3e \n",its,fgnorm);
47     }
48     else {
49       PetscPrintf(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       PetscPrintf(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       PetscPrintf(snes->comm,
59         "iter = %d, Function value %g, Gradient norm %5.3e \n",
60         its,snes->fc,fgnorm);
61     }
62     else {
63       PetscPrintf(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 (fnorm <= snes->ttol) {
109     PLogInfo((PetscObject)snes,
110     "SNES:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol);
111     return 4;
112   }
113 
114   if (fnorm < snes->atol) {
115     PLogInfo((PetscObject)snes,
116       "SNES: Converged due to function norm %g < %g\n",fnorm,snes->atol);
117     return 2;
118   }
119   if (pnorm < snes->xtol*(xnorm)) {
120     PLogInfo((PetscObject)snes,
121       "SNES: Converged due to small update length: %g < %g * %g\n",
122        pnorm,snes->xtol,xnorm);
123     return 3;
124   }
125   if (snes->nfuncs > snes->max_funcs) {
126     PLogInfo((PetscObject)snes,
127       "SNES: Exceeded maximum number of function evaluations: %d > %d\n",
128       snes->nfuncs, snes->max_funcs );
129     return -2;
130   }
131   return 0;
132 }
133 /* ------------------------------------------------------------ */
134 /*@
135    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test for
136    for the linear solvers within an inexact Newton method.
137 
138    Input Parameter:
139 .  snes - SNES context
140 
141    Notes:
142    Currently, the default is to use a constant relative tolerance for
143    the inner linear solvers.  Alternatively, one can use the
144    Eisenstat-Walker method, where the relative convergence tolerance
145    is reset at each Newton iteration according progress of the nonlinear
146    solver.
147 
148    Reference:
149    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
150    inexact Newton method", Utah State University Math. Stat. Dept. Res.
151    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
152 
153 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
154 @*/
155 int SNES_KSP_SetConvergenceTestEW(SNES snes)
156 {
157   snes->ksp_ewconv = 1;
158   return 0;
159 }
160 
161 /*@
162    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
163    convergence criteria for the linear solvers within an inexact
164    Newton method.
165 
166    Input Parameters:
167 .  snes - SNES context
168 .  version - version 1 or 2 (default is 2)
169 .  rtol_0 - initial relative tolerance
170 $    (0 <= rtol_0 < 1)
171 .  rtol_max - maximum relative tolerance
172 $    (0 <= rtol_max < 1)
173 .  alpha - power for version 2 rtol computation
174 $    (1 < alpha <= 2)
175 .  alpha2 - power for safeguard
176 .  gamma2 - multiplicative factor for version 2 rtol computation
177 $    (0 <= gamma2 <= 1)
178 .  threshold - threshold for imposing safeguard
179 $    (0 < threshold < 1)
180 
181    Note:
182    Use PETSC_DEFAULT to retain the default for any of the parameters.
183 
184    Reference:
185    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
186    inexact Newton method", Utah State University Math. Stat. Dept. Res.
187    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
188 
189 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
190 
191 .seealso: SNES_KSP_SetConvergenceTestEW()
192 @*/
193 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0,
194                              double rtol_max,double gamma2,double alpha,
195                              double alpha2,double threshold)
196 {
197   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
198   if (!kctx) SETERRQ(1,"SNES_KSP_SetParametersEW:No context");
199   if (version != PETSC_DEFAULT)   kctx->version = version;
200   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0 = rtol_0;
201   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max = rtol_max;
202   if (gamma2 != PETSC_DEFAULT)    kctx->gamma = gamma2;
203   if (alpha != PETSC_DEFAULT)     kctx->alpha = alpha;
204   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2 = alpha2;
205   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
206   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) SETERRQ(1,
207     "SNES_KSP_SetParametersEW: 0.0 <= rtol_0 < 1.0\n");
208   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) SETERRQ(1,
209     "SNES_KSP_SetParametersEW: 0.0 <= rtol_max < 1.0\n");
210   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) SETERRQ(1,
211     "SNES_KSP_SetParametersEW: 0.0 < threshold < 1.0\n");
212   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) SETERRQ(1,
213     "SNES_KSP_SetParametersEW: 0.0 <= alpha <= 1.0\n");
214   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) SETERRQ(1,
215     "SNES_KSP_SetParametersEW: 1.0 < alpha <= 2.0\n");
216   if (kctx->version != 1 && kctx->version !=2) SETERRQ(1,
217      "SNES_KSP_SetParametersEW: Only versions 1 and 2 are supported");
218   return 0;
219 }
220 
221 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
222 {
223   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
224   double rtol, stol;
225   int    ierr;
226   if (!kctx)
227     SETERRQ(1,"SNES_KSP_EW_ComputeRelativeTolerance_Private:No context");
228   if (snes->iter == 1) {
229     rtol = kctx->rtol_0;
230   } else {
231     if (kctx->version == 1) {
232       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
233       if (rtol < 0.0) rtol = -rtol;
234       stol = pow(kctx->rtol_last,kctx->alpha2);
235       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
236     } else if (kctx->version == 2) {
237       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
238       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
239       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
240     } else SETERRQ(1,
241      "SNES_KSP_EW_Converged_Private:Only versions 1 or 2 are supported");
242   }
243   rtol = PetscMin(rtol,kctx->rtol_max);
244   kctx->rtol_last = rtol;
245   PLogInfo((PetscObject)snes,
246     "SNES: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",
247      snes->iter,kctx->version,rtol);
248   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
249   CHKERRQ(ierr);
250   kctx->norm_last = snes->norm;
251   return 0;
252 }
253 
254 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx)
255 {
256   SNES                snes = (SNES)ctx;
257   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
258   int                 convinfo;
259 
260   if (!kctx) SETERRQ(1,"SNES_KSP_EW_Converged_Private:No convergence context");
261   if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);
262   convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx);
263   kctx->lresid_last = rnorm;
264   if (convinfo)
265     PLogInfo((PetscObject)snes,"SNES: KSP iterations=%d, rnorm=%g\n",n,rnorm);
266   return convinfo;
267 }
268 
269 
270