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