xref: /petsc/src/snes/interface/snesut.c (revision 454a90a3eb7bca6958262e5eca1eb393ad97e108)
1 #ifdef PETSC_RCS_HEADER
2 static char vcid[] = "$Id: snesut.c,v 1.47 1999/05/04 20:35:43 balay Exp bsmith $";
3 #endif
4 
5 #include "src/snes/snesimpl.h"       /*I   "snes.h"   I*/
6 
7 #undef __FUNC__
8 #define __FUNC__ "SNESVecViewMonitor"
9 /*@C
10    SNESVecViewMonitor - Monitors progress of the SNES solvers by calling
11    VecView() for the approximate solution at each iteration.
12 
13    Collective on SNES
14 
15    Input Parameters:
16 +  snes - the SNES context
17 .  its - iteration number
18 .  fgnorm - 2-norm of residual (or gradient)
19 -  dummy - either a viewer or PETSC_NULL
20 
21    Level: intermediate
22 
23 .keywords: SNES, nonlinear, vector, monitor, view
24 
25 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
26 @*/
27 int SNESVecViewMonitor(SNES snes,int its,double fgnorm,void *dummy)
28 {
29   int    ierr;
30   Vec    x;
31   Viewer viewer = (Viewer) dummy;
32 
33   PetscFunctionBegin;
34   ierr = SNESGetSolution(snes,&x);CHKERRQ(ierr);
35   if (!viewer) {
36     MPI_Comm comm;
37     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
38     viewer = VIEWER_DRAW_(comm);
39   }
40   ierr = VecView(x,viewer);CHKERRQ(ierr);
41 
42   PetscFunctionReturn(0);
43 }
44 
45 #undef __FUNC__
46 #define __FUNC__ "SNESVecViewMonitorUpdate"
47 /*@C
48    SNESVecViewMonitorUpdate - Monitors progress of the SNES solvers by calling
49    VecView() for the UPDATE to the solution at each iteration.
50 
51    Collective on SNES
52 
53    Input Parameters:
54 +  snes - the SNES context
55 .  its - iteration number
56 .  fgnorm - 2-norm of residual (or gradient)
57 -  dummy - either a viewer or PETSC_NULL
58 
59    Level: intermediate
60 
61 .keywords: SNES, nonlinear, vector, monitor, view
62 
63 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
64 @*/
65 int SNESVecViewMonitorUpdate(SNES snes,int its,double fgnorm,void *dummy)
66 {
67   int    ierr;
68   Vec    x;
69   Viewer viewer = (Viewer) dummy;
70 
71   PetscFunctionBegin;
72   ierr = SNESGetSolutionUpdate(snes,&x);CHKERRQ(ierr);
73   if (!viewer) {
74     MPI_Comm comm;
75     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
76     viewer = VIEWER_DRAW_(comm);
77   }
78   ierr = VecView(x,viewer);CHKERRQ(ierr);
79 
80   PetscFunctionReturn(0);
81 }
82 
83 #undef __FUNC__
84 #define __FUNC__ "SNESDefaultMonitor"
85 /*@C
86    SNESDefaultMonitor - Monitoring progress of the SNES solvers (default).
87 
88    Collective on SNES
89 
90    Input Parameters:
91 +  snes - the SNES context
92 .  its - iteration number
93 .  fgnorm - 2-norm of residual (or gradient)
94 -  dummy - unused context
95 
96    Notes:
97    For SNES_NONLINEAR_EQUATIONS methods the routine prints the
98    residual norm at each iteration.
99 
100    For SNES_UNCONSTRAINED_MINIMIZATION methods the routine prints the
101    function value and gradient norm at each iteration.
102 
103    Level: intermediate
104 
105 .keywords: SNES, nonlinear, default, monitor, norm
106 
107 .seealso: SNESSetMonitor(), SNESVecViewMonitor()
108 @*/
109 int SNESDefaultMonitor(SNES snes,int its,double fgnorm,void *dummy)
110 {
111   int ierr;
112 
113   PetscFunctionBegin;
114   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
115     ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr);
116   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
117     ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
118   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
119   PetscFunctionReturn(0);
120 }
121 
122 /* ---------------------------------------------------------------- */
123 #undef __FUNC__
124 #define __FUNC__ "SNESDefaultSMonitor"
125 /*
126      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
127   it prints fewer digits of the residual as the residual gets smaller.
128   This is because the later digits are meaningless and are often
129   different on different machines; by using this routine different
130   machines will usually generate the same output.
131 */
132 int SNESDefaultSMonitor(SNES snes,int its, double fgnorm,void *dummy)
133 {
134   int ierr;
135 
136   PetscFunctionBegin;
137   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
138     if (fgnorm > 1.e-9) {
139       ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr);
140     } else if (fgnorm > 1.e-11){
141       ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr);
142     } else {
143       ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr);
144     }
145   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
146     if (fgnorm > 1.e-9) {
147       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
148     } else if (fgnorm > 1.e-11) {
149       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %5.3e \n",its,snes->fc,fgnorm);CHKERRQ(ierr);
150     } else {
151       ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm < 1.e-11\n",its,snes->fc);CHKERRQ(ierr);
152     }
153   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class");
154   PetscFunctionReturn(0);
155 }
156 /* ---------------------------------------------------------------- */
157 #undef __FUNC__
158 #define __FUNC__ "SNESConverged_EQ_LS"
159 /*@C
160    SNESConverged_EQ_LS - Monitors the convergence of the solvers for
161    systems of nonlinear equations (default).
162 
163    Collective on SNES
164 
165    Input Parameters:
166 +  snes - the SNES context
167 .  xnorm - 2-norm of current iterate
168 .  pnorm - 2-norm of current step
169 .  fnorm - 2-norm of function
170 -  dummy - unused context
171 
172    Output Parameter:
173 .   reason  - one of
174 $  SNES_CONVERGED_FNORM_ABS       - ( fnorm < atol ),
175 $  SNES_CONVERGED_PNORM_RELATIVE  - ( pnorm < xtol*xnorm ),
176 $  SNES_CONVERGED_FNORM_RELATIVE  - ( fnorm < rtol*fnorm0 ),
177 $  SNES_DIVERGED_FUNCTION_COUNT   - ( nfct > maxf ),
178 $  SNES_DIVERGED_FNORM_NAN        - ( fnorm == NaN ),
179 $  SNES_CONVERGED_ITERATING       - ( otherwise ),
180 
181    where
182 +    maxf - maximum number of function evaluations,
183             set with SNESSetTolerances()
184 .    nfct - number of function evaluations,
185 .    atol - absolute function norm tolerance,
186             set with SNESSetTolerances()
187 -    rtol - relative function norm tolerance, set with SNESSetTolerances()
188 
189    Level: intermediate
190 
191 .keywords: SNES, nonlinear, default, converged, convergence
192 
193 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
194 @*/
195 int SNESConverged_EQ_LS(SNES snes,double xnorm,double pnorm,double fnorm,SNESConvergedReason *reason,void *dummy)
196 {
197   PetscFunctionBegin;
198   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
199      SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only");
200   }
201 
202   if (fnorm != fnorm) {
203     PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n");
204     *reason = SNES_DIVERGED_FNORM_NAN;
205   } else if (fnorm <= snes->ttol) {
206     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol);
207     *reason = SNES_CONVERGED_FNORM_RELATIVE;
208   } else if (fnorm < snes->atol) {
209     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g\n",fnorm,snes->atol);
210     *reason = SNES_CONVERGED_FNORM_ABS;
211   } else if (pnorm < snes->xtol*(xnorm)) {
212     PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm);
213     *reason = SNES_CONVERGED_PNORM_RELATIVE;
214   } else if (snes->nfuncs > snes->max_funcs) {
215     PLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %d\n",snes->nfuncs, snes->max_funcs);
216     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
217   } else {
218     *reason = SNES_CONVERGED_ITERATING;
219   }
220   PetscFunctionReturn(0);
221 }
222 /* ------------------------------------------------------------ */
223 #undef __FUNC__
224 #define __FUNC__ "SNES_KSP_SetConvergenceTestEW"
225 /*@
226    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
227    for the linear solvers within an inexact Newton method.
228 
229    Collective on SNES
230 
231    Input Parameter:
232 .  snes - SNES context
233 
234    Notes:
235    Currently, the default is to use a constant relative tolerance for
236    the inner linear solvers.  Alternatively, one can use the
237    Eisenstat-Walker method, where the relative convergence tolerance
238    is reset at each Newton iteration according progress of the nonlinear
239    solver.
240 
241    Level: advanced
242 
243    Reference:
244    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
245    inexact Newton method", SISC 17 (1), pp.16-32, 1996.
246 
247 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
248 @*/
249 int SNES_KSP_SetConvergenceTestEW(SNES snes)
250 {
251   PetscFunctionBegin;
252   snes->ksp_ewconv = 1;
253   PetscFunctionReturn(0);
254 }
255 
256 #undef __FUNC__
257 #define __FUNC__ "SNES_KSP_SetParametersEW"
258 /*@
259    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
260    convergence criteria for the linear solvers within an inexact
261    Newton method.
262 
263    Collective on SNES
264 
265    Input Parameters:
266 +    snes - SNES context
267 .    version - version 1 or 2 (default is 2)
268 .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
269 .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
270 .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
271 .    alpha2 - power for safeguard
272 .    gamma2 - multiplicative factor for version 2 rtol computation
273               (0 <= gamma2 <= 1)
274 -    threshold - threshold for imposing safeguard (0 < threshold < 1)
275 
276    Note:
277    Use PETSC_DEFAULT to retain the default for any of the parameters.
278 
279    Level: advanced
280 
281    Reference:
282    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
283    inexact Newton method", Utah State University Math. Stat. Dept. Res.
284    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
285 
286 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
287 
288 .seealso: SNES_KSP_SetConvergenceTestEW()
289 @*/
290 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0,
291                              double rtol_max,double gamma2,double alpha,
292                              double alpha2,double threshold)
293 {
294   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
295 
296   PetscFunctionBegin;
297   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing");
298   if (version != PETSC_DEFAULT)   kctx->version   = version;
299   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
300   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
301   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
302   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
303   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
304   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
305   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
306     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
307   }
308   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
309     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n",kctx->rtol_max);
310   }
311   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
312     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n",kctx->threshold);
313   }
314   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
315     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n",kctx->gamma);
316   }
317   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
318     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n",kctx->alpha);
319   }
320   if (kctx->version != 1 && kctx->version !=2) {
321     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported: %d",kctx->version);
322   }
323   PetscFunctionReturn(0);
324 }
325 
326 #undef __FUNC__
327 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private"
328 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
329 {
330   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
331   double              rtol = 0.0, stol;
332   int                 ierr;
333 
334   PetscFunctionBegin;
335   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists");
336   if (snes->iter == 1) {
337     rtol = kctx->rtol_0;
338   } else {
339     if (kctx->version == 1) {
340       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
341       if (rtol < 0.0) rtol = -rtol;
342       stol = pow(kctx->rtol_last,kctx->alpha2);
343       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
344     } else if (kctx->version == 2) {
345       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
346       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
347       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
348     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported: %d",kctx->version);
349   }
350   rtol = PetscMin(rtol,kctx->rtol_max);
351   kctx->rtol_last = rtol;
352   PLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",snes->iter,kctx->version,rtol);
353   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
354   kctx->norm_last = snes->norm;
355   PetscFunctionReturn(0);
356 }
357 
358 #undef __FUNC__
359 #define __FUNC__ "SNES_KSP_EW_Converged_Private"
360 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx)
361 {
362   SNES                snes = (SNES)ctx;
363   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
364   int                 convinfo,ierr;
365 
366   PetscFunctionBegin;
367   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set");
368   if (n == 0) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);}
369   convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx);
370   kctx->lresid_last = rnorm;
371   if (convinfo) {
372     PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm);
373   }
374   PetscFunctionReturn(convinfo);
375 }
376 
377 
378