xref: /petsc/src/snes/interface/snesut.c (revision e0e703c18709862a0d755d6cf34ba2e20a8376a1)
1 #ifdef PETSC_RCS_HEADER
2 static char vcid[] = "$Id: snesut.c,v 1.37 1998/02/10 19:49:03 curfman 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    Collective on SNES
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    Input Parameters:
85 .  snes - the SNES context
86 .  xnorm - 2-norm of current iterate
87 .  pnorm - 2-norm of current step
88 .  fnorm - 2-norm of function
89 .  dummy - unused context
90 
91    Returns:
92 $  2  if  ( fnorm < atol ),
93 $  3  if  ( pnorm < xtol*xnorm ),
94 $  4  if  ( fnorm < rtol*fnorm0 ),
95 $ -2  if  ( nfct > maxf ),
96 $  0  otherwise,
97 
98    where
99 $    maxf - maximum number of function evaluations,
100 $           set with SNESSetTolerances()
101 $    nfct - number of function evaluations,
102 $    atol - absolute function norm tolerance,
103 $           set with SNESSetTolerances()
104 $    rtol - relative function norm tolerance,
105 $           set with SNESSetTolerances()
106 
107    Collective on SNES
108 
109 .keywords: SNES, nonlinear, default, converged, convergence
110 
111 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
112 @*/
113 int SNESConverged_EQ_LS(SNES snes,double xnorm,double pnorm,double fnorm,void *dummy)
114 {
115   PetscFunctionBegin;
116   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
117      SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only");
118   }
119   /* Note:  Reserve return code 1, -1 for compatibility with SNESConverged_EQ_TR */
120   if (fnorm != fnorm) {
121     PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n");
122     PetscFunctionReturn(-3);
123   }
124   if (fnorm <= snes->ttol) {
125     PLogInfo(snes,
126     "SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol);
127     PetscFunctionReturn(4);
128   }
129 
130   if (fnorm < snes->atol) {
131     PLogInfo(snes,
132       "SNESConverged_EQ_LS: Converged due to function norm %g < %g\n",fnorm,snes->atol);
133     PetscFunctionReturn(2);
134   }
135   if (pnorm < snes->xtol*(xnorm)) {
136     PLogInfo(snes,
137       "SNESConverged_EQ_LS: Converged due to small update length: %g < %g * %g\n",
138        pnorm,snes->xtol,xnorm);
139     PetscFunctionReturn(3);
140   }
141   if (snes->nfuncs > snes->max_funcs) {
142     PLogInfo(snes,"SNESConverged_EQ_LS: Exceeded maximum number of function evaluations: %d > %d\n",
143       snes->nfuncs, snes->max_funcs );
144     PetscFunctionReturn(-2);
145   }
146   PetscFunctionReturn(0);
147 }
148 /* ------------------------------------------------------------ */
149 #undef __FUNC__
150 #define __FUNC__ "SNES_KSP_SetConvergenceTestEW"
151 /*@
152    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
153    for the linear solvers within an inexact Newton method.
154 
155    Input Parameter:
156 .  snes - SNES context
157 
158    Collective on SNES
159 
160    Notes:
161    Currently, the default is to use a constant relative tolerance for
162    the inner linear solvers.  Alternatively, one can use the
163    Eisenstat-Walker method, where the relative convergence tolerance
164    is reset at each Newton iteration according progress of the nonlinear
165    solver.
166 
167    Reference:
168    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
169    inexact Newton method", SISC 17 (1), pp.16-32, 1996.
170 
171 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
172 @*/
173 int SNES_KSP_SetConvergenceTestEW(SNES snes)
174 {
175   PetscFunctionBegin;
176   snes->ksp_ewconv = 1;
177   PetscFunctionReturn(0);
178 }
179 
180 #undef __FUNC__
181 #define __FUNC__ "SNES_KSP_SetParametersEW"
182 /*@
183    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
184    convergence criteria for the linear solvers within an inexact
185    Newton method.
186 
187    Input Parameters:
188 .    snes - SNES context
189 .    version - version 1 or 2 (default is 2)
190 .    rtol_0 - initial relative tolerance
191 $      (0 <= rtol_0 < 1)
192 .    rtol_max - maximum relative tolerance
193 $      (0 <= rtol_max < 1)
194 .    alpha - power for version 2 rtol computation
195 $      (1 < alpha <= 2)
196 .    alpha2 - power for safeguard
197 .    gamma2 - multiplicative factor for version 2 rtol computation
198 $      (0 <= gamma2 <= 1)
199 .    threshold - threshold for imposing safeguard
200 $      (0 < threshold < 1)
201 
202    Collective on SNES
203 
204    Note:
205    Use PETSC_DEFAULT to retain the default for any of the parameters.
206 
207    Reference:
208    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
209    inexact Newton method", Utah State University Math. Stat. Dept. Res.
210    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
211 
212 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
213 
214 .seealso: SNES_KSP_SetConvergenceTestEW()
215 @*/
216 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0,
217                              double rtol_max,double gamma2,double alpha,
218                              double alpha2,double threshold)
219 {
220   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
221 
222   PetscFunctionBegin;
223   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing");
224   if (version != PETSC_DEFAULT)   kctx->version = version;
225   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0 = rtol_0;
226   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max = rtol_max;
227   if (gamma2 != PETSC_DEFAULT)    kctx->gamma = gamma2;
228   if (alpha != PETSC_DEFAULT)     kctx->alpha = alpha;
229   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2 = alpha2;
230   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
231   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
232     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0\n");
233   }
234   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
235     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n");
236   }
237   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
238     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n");
239   }
240   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
241     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n");
242   }
243   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
244     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n");
245   }
246   if (kctx->version != 1 && kctx->version !=2) {
247     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported");
248   }
249   PetscFunctionReturn(0);
250 }
251 
252 #undef __FUNC__
253 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private"
254 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
255 {
256   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
257   double rtol, stol;
258   int    ierr;
259 
260   PetscFunctionBegin;
261   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists");
262   if (snes->iter == 1) {
263     rtol = kctx->rtol_0;
264   } else {
265     if (kctx->version == 1) {
266       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
267       if (rtol < 0.0) rtol = -rtol;
268       stol = pow(kctx->rtol_last,kctx->alpha2);
269       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
270     } else if (kctx->version == 2) {
271       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
272       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
273       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
274     } else SETERRQ( PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported");
275   }
276   rtol = PetscMin(rtol,kctx->rtol_max);
277   kctx->rtol_last = rtol;
278   PLogInfo(snes,"SNESConverged_EQ_LS: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",
279            snes->iter,kctx->version,rtol);
280   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT); CHKERRQ(ierr);
281   kctx->norm_last = snes->norm;
282   PetscFunctionReturn(0);
283 }
284 
285 #undef __FUNC__
286 #define __FUNC__ "SNES_KSP_EW_Converged_Private"
287 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx)
288 {
289   SNES                snes = (SNES)ctx;
290   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
291   int                 convinfo;
292 
293   PetscFunctionBegin;
294   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set");
295   if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);
296   convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx);
297   kctx->lresid_last = rnorm;
298   if (convinfo) {
299     PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm);
300   }
301   PetscFunctionReturn(convinfo);
302 }
303 
304 
305