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