xref: /petsc/src/snes/interface/snesut.c (revision 2a6744eb01855f5aa328eb8fdf4b0d01e72ad151)
1 #define PETSCSNES_DLL
2 
3 #include "src/snes/snesimpl.h"       /*I   "petscsnes.h"   I*/
4 
5 #undef __FUNCT__
6 #define __FUNCT__ "SNESVecViewMonitor"
7 /*@C
8    SNESVecViewMonitor - Monitors progress of the SNES solvers by calling
9    VecView() for the approximate solution at each iteration.
10 
11    Collective on SNES
12 
13    Input Parameters:
14 +  snes - the SNES context
15 .  its - iteration number
16 .  fgnorm - 2-norm of residual
17 -  dummy - either a viewer or PETSC_NULL
18 
19    Level: intermediate
20 
21 .keywords: SNES, nonlinear, vector, monitor, view
22 
23 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
24 @*/
25 PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
26 {
27   PetscErrorCode ierr;
28   Vec            x;
29   PetscViewer    viewer = (PetscViewer) dummy;
30 
31   PetscFunctionBegin;
32   ierr = SNESGetSolution(snes,&x);CHKERRQ(ierr);
33   if (!viewer) {
34     MPI_Comm comm;
35     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
36     viewer = PETSC_VIEWER_DRAW_(comm);
37   }
38   ierr = VecView(x,viewer);CHKERRQ(ierr);
39 
40   PetscFunctionReturn(0);
41 }
42 
43 #undef __FUNCT__
44 #define __FUNCT__ "SNESVecViewResidualMonitor"
45 /*@C
46    SNESVecViewResidualMonitor - Monitors progress of the SNES solvers by calling
47    VecView() for the residual at each iteration.
48 
49    Collective on SNES
50 
51    Input Parameters:
52 +  snes - the SNES context
53 .  its - iteration number
54 .  fgnorm - 2-norm of residual
55 -  dummy - either a viewer or PETSC_NULL
56 
57    Level: intermediate
58 
59 .keywords: SNES, nonlinear, vector, monitor, view
60 
61 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
62 @*/
63 PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewResidualMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
64 {
65   PetscErrorCode ierr;
66   Vec            x;
67   PetscViewer    viewer = (PetscViewer) dummy;
68 
69   PetscFunctionBegin;
70   ierr = SNESGetFunction(snes,&x,0,0);CHKERRQ(ierr);
71   if (!viewer) {
72     MPI_Comm comm;
73     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
74     viewer = PETSC_VIEWER_DRAW_(comm);
75   }
76   ierr = VecView(x,viewer);CHKERRQ(ierr);
77 
78   PetscFunctionReturn(0);
79 }
80 
81 #undef __FUNCT__
82 #define __FUNCT__ "SNESVecViewUpdateMonitor"
83 /*@C
84    SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling
85    VecView() for the UPDATE to the solution at each iteration.
86 
87    Collective on SNES
88 
89    Input Parameters:
90 +  snes - the SNES context
91 .  its - iteration number
92 .  fgnorm - 2-norm of residual
93 -  dummy - either a viewer or PETSC_NULL
94 
95    Level: intermediate
96 
97 .keywords: SNES, nonlinear, vector, monitor, view
98 
99 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
100 @*/
101 PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewUpdateMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
102 {
103   PetscErrorCode ierr;
104   Vec            x;
105   PetscViewer    viewer = (PetscViewer) dummy;
106 
107   PetscFunctionBegin;
108   ierr = SNESGetSolutionUpdate(snes,&x);CHKERRQ(ierr);
109   if (!viewer) {
110     MPI_Comm comm;
111     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
112     viewer = PETSC_VIEWER_DRAW_(comm);
113   }
114   ierr = VecView(x,viewer);CHKERRQ(ierr);
115 
116   PetscFunctionReturn(0);
117 }
118 
119 #undef __FUNCT__
120 #define __FUNCT__ "SNESDefaultMonitor"
121 /*@C
122    SNESDefaultMonitor - Monitors progress of the SNES solvers (default).
123 
124    Collective on SNES
125 
126    Input Parameters:
127 +  snes - the SNES context
128 .  its - iteration number
129 .  fgnorm - 2-norm of residual
130 -  dummy - unused context
131 
132    Notes:
133    This routine prints the residual norm at each iteration.
134 
135    Level: intermediate
136 
137 .keywords: SNES, nonlinear, default, monitor, norm
138 
139 .seealso: SNESSetMonitor(), SNESVecViewMonitor()
140 @*/
141 PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
142 {
143   PetscErrorCode ierr;
144   PetscViewer    viewer = (PetscViewer) dummy;
145 
146   PetscFunctionBegin;
147   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
148   ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr);
149   PetscFunctionReturn(0);
150 }
151 
152 typedef struct {
153   PetscViewer viewer;
154   PetscReal   *history;
155 } SNESRatioMonitorContext;
156 
157 #undef __FUNCT__
158 #define __FUNCT__ "SNESRatioMonitor"
159 /*@C
160    SNESRatioMonitor - Monitors progress of the SNES solvers by printing the ratio
161    of residual norm at each iteration to the previous.
162 
163    Collective on SNES
164 
165    Input Parameters:
166 +  snes - the SNES context
167 .  its - iteration number
168 .  fgnorm - 2-norm of residual (or gradient)
169 -  dummy -  context of monitor
170 
171    Level: intermediate
172 
173 .keywords: SNES, nonlinear, monitor, norm
174 
175 .seealso: SNESSetMonitor(), SNESVecViewMonitor()
176 @*/
177 PetscErrorCode PETSCSNES_DLLEXPORT SNESRatioMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
178 {
179   PetscErrorCode          ierr;
180   PetscInt                len;
181   PetscReal               *history;
182   SNESRatioMonitorContext *ctx = (SNESRatioMonitorContext*)dummy;
183 
184   PetscFunctionBegin;
185   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);CHKERRQ(ierr);
186   if (!its || !history || its > len) {
187     ierr = PetscViewerASCIIPrintf(ctx->viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr);
188   } else {
189     PetscReal ratio = fgnorm/history[its-1];
190     ierr = PetscViewerASCIIPrintf(ctx->viewer,"%3D SNES Function norm %14.12e %G \n",its,fgnorm,ratio);CHKERRQ(ierr);
191   }
192   PetscFunctionReturn(0);
193 }
194 
195 /*
196    If the we set the history monitor space then we must destroy it
197 */
198 #undef __FUNCT__
199 #define __FUNCT__ "SNESRatioMonitorDestroy"
200 PetscErrorCode SNESRatioMonitorDestroy(void *ct)
201 {
202   PetscErrorCode          ierr;
203   SNESRatioMonitorContext *ctx = (SNESRatioMonitorContext*)ct;
204 
205   PetscFunctionBegin;
206   ierr = PetscFree(ctx->history);CHKERRQ(ierr);
207   ierr = PetscViewerDestroy(ctx->viewer);CHKERRQ(ierr);
208   ierr = PetscFree(ctx);CHKERRQ(ierr);
209   PetscFunctionReturn(0);
210 }
211 
212 #undef __FUNCT__
213 #define __FUNCT__ "SNESSetRatioMonitor"
214 /*@C
215    SNESSetRatioMonitor - Sets SNES to use a monitor that prints the
216    ratio of the function norm at each iteration.
217 
218    Collective on SNES
219 
220    Input Parameters:
221 +   snes - the SNES context
222 -   viewer - ASCII viewer to print output
223 
224    Level: intermediate
225 
226 .keywords: SNES, nonlinear, monitor, norm
227 
228 .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
229 @*/
230 PetscErrorCode PETSCSNES_DLLEXPORT SNESSetRatioMonitor(SNES snes,PetscViewer viewer)
231 {
232   PetscErrorCode          ierr;
233   SNESRatioMonitorContext *ctx;
234   PetscReal               *history;
235 
236   PetscFunctionBegin;
237   if (!viewer) {
238     viewer = PETSC_VIEWER_STDOUT_(snes->comm);
239     ierr   = PetscObjectReference((PetscObject)viewer);CHKERRQ(ierr);
240   }
241   ierr = PetscNew(SNESRatioMonitorContext,&ctx);
242   ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
243   if (!history) {
244     ierr = PetscMalloc(100*sizeof(PetscReal),&ctx->history);CHKERRQ(ierr);
245     ierr = SNESSetConvergenceHistory(snes,ctx->history,0,100,PETSC_TRUE);CHKERRQ(ierr);
246   }
247   ctx->viewer = viewer;
248   ierr = SNESSetMonitor(snes,SNESRatioMonitor,ctx,SNESRatioMonitorDestroy);CHKERRQ(ierr);
249   PetscFunctionReturn(0);
250 }
251 
252 /* ---------------------------------------------------------------- */
253 #undef __FUNCT__
254 #define __FUNCT__ "SNESDefaultSMonitor"
255 /*
256      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
257   it prints fewer digits of the residual as the residual gets smaller.
258   This is because the later digits are meaningless and are often
259   different on different machines; by using this routine different
260   machines will usually generate the same output.
261 */
262 PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultSMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
263 {
264   PetscErrorCode ierr;
265   PetscViewer    viewer = (PetscViewer) dummy;
266 
267   PetscFunctionBegin;
268   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
269   if (fgnorm > 1.e-9) {
270     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %G \n",its,fgnorm);CHKERRQ(ierr);
271   } else if (fgnorm > 1.e-11){
272     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr);
273   } else {
274     ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr);
275   }
276   PetscFunctionReturn(0);
277 }
278 /* ---------------------------------------------------------------- */
279 #undef __FUNCT__
280 #define __FUNCT__ "SNESConverged_LS"
281 /*@C
282    SNESConverged_LS - Monitors the convergence of the solvers for
283    systems of nonlinear equations (default).
284 
285    Collective on SNES
286 
287    Input Parameters:
288 +  snes - the SNES context
289 .  it - the iteration (0 indicates before any Newton steps)
290 .  xnorm - 2-norm of current iterate
291 .  pnorm - 2-norm of current step
292 .  fnorm - 2-norm of function at current iterate
293 -  dummy - unused context
294 
295    Output Parameter:
296 .   reason  - one of
297 $  SNES_CONVERGED_FNORM_ABS       - (fnorm < abstol),
298 $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
299 $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
300 $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
301 $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
302 $  SNES_CONVERGED_ITERATING       - (otherwise),
303 
304    where
305 +    maxf - maximum number of function evaluations,
306             set with SNESSetTolerances()
307 .    nfct - number of function evaluations,
308 .    abstol - absolute function norm tolerance,
309             set with SNESSetTolerances()
310 -    rtol - relative function norm tolerance, set with SNESSetTolerances()
311 
312    Level: intermediate
313 
314 .keywords: SNES, nonlinear, default, converged, convergence
315 
316 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
317 @*/
318 PetscErrorCode PETSCSNES_DLLEXPORT SNESConverged_LS(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
319 {
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   *reason = SNES_CONVERGED_ITERATING;
324 
325   if (!it) {
326     /* set parameter for default relative tolerance convergence test */
327     snes->ttol = fnorm*snes->rtol;
328   }
329   if (fnorm != fnorm) {
330     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
331     *reason = SNES_DIVERGED_FNORM_NAN;
332   } else if (fnorm < snes->abstol) {
333     ierr = PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);CHKERRQ(ierr);
334     *reason = SNES_CONVERGED_FNORM_ABS;
335   } else if (snes->nfuncs >= snes->max_funcs) {
336     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
337     *reason = SNES_DIVERGED_FUNCTION_COUNT;
338   }
339 
340   if (it && !*reason) {
341     if (fnorm <= snes->ttol) {
342       ierr = PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);CHKERRQ(ierr);
343       *reason = SNES_CONVERGED_FNORM_RELATIVE;
344     } else if (pnorm < snes->xtol*xnorm) {
345       ierr = PetscInfo3(snes,"Converged due to small update length: %G < %G * %G\n",pnorm,snes->xtol,xnorm);CHKERRQ(ierr);
346       *reason = SNES_CONVERGED_PNORM_RELATIVE;
347     }
348   }
349   PetscFunctionReturn(0);
350 }
351 /* ------------------------------------------------------------ */
352 #undef __FUNCT__
353 #define __FUNCT__ "SNES_KSP_SetConvergenceTestEW"
354 /*@
355    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
356    for the linear solvers within an inexact Newton method.
357 
358    Collective on SNES
359 
360    Input Parameter:
361 .  snes - SNES context
362 
363    Notes:
364    Currently, the default is to use a constant relative tolerance for
365    the inner linear solvers.  Alternatively, one can use the
366    Eisenstat-Walker method, where the relative convergence tolerance
367    is reset at each Newton iteration according progress of the nonlinear
368    solver.
369 
370    Level: advanced
371 
372    Reference:
373    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
374    inexact Newton method", SISC 17 (1), pp.16-32, 1996.
375 
376 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
377 @*/
378 PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetConvergenceTestEW(SNES snes)
379 {
380   PetscFunctionBegin;
381   snes->ksp_ewconv = PETSC_TRUE;
382   PetscFunctionReturn(0);
383 }
384 
385 #undef __FUNCT__
386 #define __FUNCT__ "SNES_KSP_SetParametersEW"
387 /*@
388    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
389    convergence criteria for the linear solvers within an inexact
390    Newton method.
391 
392    Collective on SNES
393 
394    Input Parameters:
395 +    snes - SNES context
396 .    version - version 1, 2 (default is 2) or 3
397 .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
398 .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
399 .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
400 .    alpha2 - power for safeguard
401 .    gamma2 - multiplicative factor for version 2 rtol computation
402               (0 <= gamma2 <= 1)
403 -    threshold - threshold for imposing safeguard (0 < threshold < 1)
404 
405    Note:
406    Version 3 was contributed by .....
407 
408    Use PETSC_DEFAULT to retain the default for any of the parameters.
409 
410    Level: advanced
411 
412    Reference:
413    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an
414    inexact Newton method", Utah State University Math. Stat. Dept. Res.
415    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput.
416 
417 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters
418 
419 .seealso: SNES_KSP_SetConvergenceTestEW()
420 @*/
421 PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetParametersEW(SNES snes,PetscInt version,PetscReal rtol_0,PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
422                                         PetscReal alpha2,PetscReal threshold)
423 {
424   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
425 
426   PetscFunctionBegin;
427   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
428   if (version != PETSC_DEFAULT)   kctx->version   = version;
429   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
430   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
431   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
432   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
433   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
434   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
435   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
436     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %G",kctx->rtol_0);
437   }
438   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
439     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%G) < 1.0\n",kctx->rtol_max);
440   }
441   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
442     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%G) < 1.0\n",kctx->threshold);
443   }
444   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
445     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%G) <= 1.0\n",kctx->gamma);
446   }
447   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
448     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%G) <= 2.0\n",kctx->alpha);
449   }
450   if (kctx->version != 1 && kctx->version !=2) {
451     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %D",kctx->version);
452   }
453   PetscFunctionReturn(0);
454 }
455 
456 #undef __FUNCT__
457 #define __FUNCT__ "SNES_KSP_EW_ComputeRelativeTolerance_Private"
458 PetscErrorCode SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
459 {
460   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
461   PetscReal           rtol = 0.0,stol;
462   PetscErrorCode      ierr;
463 
464   PetscFunctionBegin;
465   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
466   if (!snes->iter) { /* first time in, so use the original user rtol */
467     rtol = kctx->rtol_0;
468   } else {
469     if (kctx->version == 1) {
470       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
471       if (rtol < 0.0) rtol = -rtol;
472       stol = pow(kctx->rtol_last,kctx->alpha2);
473       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
474     } else if (kctx->version == 2) {
475       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
476       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
477       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
478     } else if (kctx->version == 3) {
479       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
480       /* safeguard: avoid sharp decrease of rtol */
481       rtol = PetscMin(kctx->rtol_0,PetscMax(rtol,kctx->gamma*pow(kctx->rtol_last,kctx->alpha)));
482       /* safeguard: avoid oversolving */
483       rtol = PetscMin(kctx->rtol_0,PetscMax(rtol,kctx->gamma*(snes->ttol)/snes->norm));
484 
485     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1, 2 or 3 are supported: %D",kctx->version);
486   }
487   rtol = PetscMin(rtol,kctx->rtol_max);
488   kctx->rtol_last = rtol;
489   ierr = PetscInfo3(snes,"iter %D, Eisenstat-Walker (version %D) KSP rtol = %G\n",snes->iter,kctx->version,rtol);CHKERRQ(ierr);
490   ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
491   kctx->norm_last = snes->norm;
492   PetscFunctionReturn(0);
493 }
494 
495 #undef __FUNCT__
496 #define __FUNCT__ "SNES_KSP_EW_Converged_Private"
497 PetscErrorCode SNES_KSP_EW_Converged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
498 {
499   SNES                snes = (SNES)ctx;
500   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
501   PetscErrorCode      ierr;
502 
503   PetscFunctionBegin;
504   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
505   if (!n) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);}
506   ierr = KSPDefaultConverged(ksp,n,rnorm,reason,ctx);CHKERRQ(ierr);
507   kctx->lresid_last = rnorm;
508   if (*reason) {
509     ierr = PetscInfo2(snes,"KSP iterations=%D, rnorm=%G\n",n,rnorm);CHKERRQ(ierr);
510   }
511   PetscFunctionReturn(0);
512 }
513 
514 
515