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