xref: /petsc/src/snes/interface/snesut.c (revision 750b007cd8d816cecd9de99077bb0a703b4cf61a)
1 
2 #include <petsc/private/snesimpl.h> /*I   "petsc/private/snesimpl.h"   I*/
3 #include <petscdm.h>
4 #include <petscsection.h>
5 #include <petscblaslapack.h>
6 
7 /*@C
8    SNESMonitorSolution - 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 -  a viewer
18 
19    Options Database Key:
20 .  -snes_monitor_solution [ascii binary draw][:filename][:viewer format] - plots solution at each iteration
21 
22    Note:
23    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
24    to be used during the `SNESSolve()`
25 
26    Level: intermediate
27 
28 .seealso: `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()`, `VecView()`
29 @*/
30 PetscErrorCode SNESMonitorSolution(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
31   Vec         x;
32   PetscViewer viewer = vf->viewer;
33 
34   PetscFunctionBegin;
35   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
36   PetscCall(SNESGetSolution(snes, &x));
37   PetscCall(PetscViewerPushFormat(viewer, vf->format));
38   PetscCall(VecView(x, viewer));
39   PetscCall(PetscViewerPopFormat(viewer));
40   PetscFunctionReturn(0);
41 }
42 
43 /*@C
44    SNESMonitorResidual - Monitors progress of the `SNES` solvers by calling
45    `VecView()` for the residual at each iteration.
46 
47    Collective on snes
48 
49    Input Parameters:
50 +  snes - the `SNES` context
51 .  its - iteration number
52 .  fgnorm - 2-norm of residual
53 -  dummy -  a viewer
54 
55    Options Database Key:
56 .  -snes_monitor_residual [ascii binary draw][:filename][:viewer format] - plots residual (not its norm) at each iteration
57 
58    Note:
59    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
60    to be used during the SNES solve.
61 
62    Level: intermediate
63 
64 .seealso: `SNESMonitorSet()`, `SNESMonitorDefault()`, `VecView()`, `SNESMonitor()`
65 @*/
66 PetscErrorCode SNESMonitorResidual(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
67   Vec x;
68 
69   PetscFunctionBegin;
70   PetscValidHeaderSpecific(vf->viewer, PETSC_VIEWER_CLASSID, 4);
71   PetscCall(SNESGetFunction(snes, &x, NULL, NULL));
72   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
73   PetscCall(VecView(x, vf->viewer));
74   PetscCall(PetscViewerPopFormat(vf->viewer));
75   PetscFunctionReturn(0);
76 }
77 
78 /*@C
79    SNESMonitorSolutionUpdate - Monitors progress of the `SNES` solvers by calling
80    `VecView()` for the UPDATE to the solution at each iteration.
81 
82    Collective on snes
83 
84    Input Parameters:
85 +  snes - the `SNES` context
86 .  its - iteration number
87 .  fgnorm - 2-norm of residual
88 -  dummy - a viewer
89 
90    Options Database Key:
91 .  -snes_monitor_solution_update [ascii binary draw][:filename][:viewer format] - plots update to solution at each iteration
92 
93    Note:
94    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
95    to be used during the SNES solve.
96 
97    Level: intermediate
98 
99 .seealso: `SNESMonitorSet()`, `SNESMonitorDefault()`, `VecView()`, `SNESMonitor()`, `SNESMonitor()`
100 @*/
101 PetscErrorCode SNESMonitorSolutionUpdate(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
102   Vec         x;
103   PetscViewer viewer = vf->viewer;
104 
105   PetscFunctionBegin;
106   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
107   PetscCall(SNESGetSolutionUpdate(snes, &x));
108   PetscCall(PetscViewerPushFormat(viewer, vf->format));
109   PetscCall(VecView(x, viewer));
110   PetscCall(PetscViewerPopFormat(viewer));
111   PetscFunctionReturn(0);
112 }
113 
114 #include <petscdraw.h>
115 
116 /*@C
117   KSPMonitorSNESResidual - Prints the `SNES` residual norm, as well as the `KSP` residual norm, at each iteration of an iterative solver.
118 
119   Collective on ksp
120 
121   Input Parameters:
122 + ksp   - iterative context
123 . n     - iteration number
124 . rnorm - 2-norm (preconditioned) residual value (may be estimated).
125 - vf    - The viewer context
126 
127   Options Database Key:
128 . -snes_monitor_ksp - Activates `KSPMonitorSNESResidual()`
129 
130    Note:
131    This is not called directly by users, rather one calls `KSPMonitorSet()`, with this function as an argument, to cause the monitor
132    to be used during the KSP solve.
133 
134   Level: intermediate
135 
136 .seealso: `KSPMonitorSet()`, `KSPMonitorResidual()`, `KSPMonitorTrueResidualMaxNorm()`, `KSPMonitor()`, `SNESMonitor()`
137 @*/
138 PetscErrorCode KSPMonitorSNESResidual(KSP ksp, PetscInt n, PetscReal rnorm, PetscViewerAndFormat *vf) {
139   PetscViewer       viewer = vf->viewer;
140   PetscViewerFormat format = vf->format;
141   SNES              snes   = (SNES)vf->data;
142   Vec               snes_solution, work1, work2;
143   PetscReal         snorm;
144   PetscInt          tablevel;
145   const char       *prefix;
146 
147   PetscFunctionBegin;
148   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
149   PetscCall(SNESGetSolution(snes, &snes_solution));
150   PetscCall(VecDuplicate(snes_solution, &work1));
151   PetscCall(VecDuplicate(snes_solution, &work2));
152   PetscCall(KSPBuildSolution(ksp, work1, NULL));
153   PetscCall(VecAYPX(work1, -1.0, snes_solution));
154   PetscCall(SNESComputeFunction(snes, work1, work2));
155   PetscCall(VecNorm(work2, NORM_2, &snorm));
156   PetscCall(VecDestroy(&work1));
157   PetscCall(VecDestroy(&work2));
158 
159   PetscCall(PetscObjectGetTabLevel((PetscObject)ksp, &tablevel));
160   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)ksp, &prefix));
161   PetscCall(PetscViewerPushFormat(viewer, format));
162   PetscCall(PetscViewerASCIIAddTab(viewer, tablevel));
163   if (n == 0 && prefix) PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual norms for %s solve.\n", prefix));
164   PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Residual norm %5.3e KSP Residual norm %5.3e \n", n, (double)snorm, (double)rnorm));
165   PetscCall(PetscViewerASCIISubtractTab(viewer, tablevel));
166   PetscCall(PetscViewerPopFormat(viewer));
167   PetscFunctionReturn(0);
168 }
169 
170 /*@C
171   KSPMonitorSNESResidualDrawLG - Plots the linear `KSP` residual norm and the `SNES` residual norm at each iteration of an iterative solver.
172 
173   Collective on ksp
174 
175   Input Parameters:
176 + ksp   - iterative context
177 . n     - iteration number
178 . rnorm - 2-norm (preconditioned) residual value (may be estimated).
179 - vf    - The viewer context, created with `KSPMonitorSNESResidualDrawLGCreate()`
180 
181   Options Database Key:
182 . -snes_monitor_ksp draw::draw_lg - Activates `KSPMonitorSNESResidualDrawLG()`
183 
184    Note:
185    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
186    to be used during the `SNESSolve()`
187 
188   Level: intermediate
189 
190 .seealso: `KSPMonitorSet()`, `KSPMonitorTrueResidual()`, `SNESMonitor()`, `KSPMonitor()`, `KSPMonitorSNESResidualDrawLGCreate()`
191 @*/
192 PetscErrorCode KSPMonitorSNESResidualDrawLG(KSP ksp, PetscInt n, PetscReal rnorm, PetscViewerAndFormat *vf) {
193   PetscViewer        viewer = vf->viewer;
194   PetscViewerFormat  format = vf->format;
195   PetscDrawLG        lg     = vf->lg;
196   SNES               snes   = (SNES)vf->data;
197   Vec                snes_solution, work1, work2;
198   PetscReal          snorm;
199   KSPConvergedReason reason;
200   PetscReal          x[2], y[2];
201 
202   PetscFunctionBegin;
203   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
204   PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 4);
205   PetscCall(SNESGetSolution(snes, &snes_solution));
206   PetscCall(VecDuplicate(snes_solution, &work1));
207   PetscCall(VecDuplicate(snes_solution, &work2));
208   PetscCall(KSPBuildSolution(ksp, work1, NULL));
209   PetscCall(VecAYPX(work1, -1.0, snes_solution));
210   PetscCall(SNESComputeFunction(snes, work1, work2));
211   PetscCall(VecNorm(work2, NORM_2, &snorm));
212   PetscCall(VecDestroy(&work1));
213   PetscCall(VecDestroy(&work2));
214 
215   PetscCall(PetscViewerPushFormat(viewer, format));
216   if (!n) PetscCall(PetscDrawLGReset(lg));
217   x[0] = (PetscReal)n;
218   if (rnorm > 0.0) y[0] = PetscLog10Real(rnorm);
219   else y[0] = -15.0;
220   x[1] = (PetscReal)n;
221   if (snorm > 0.0) y[1] = PetscLog10Real(snorm);
222   else y[1] = -15.0;
223   PetscCall(PetscDrawLGAddPoint(lg, x, y));
224   PetscCall(KSPGetConvergedReason(ksp, &reason));
225   if (n <= 20 || !(n % 5) || reason) {
226     PetscCall(PetscDrawLGDraw(lg));
227     PetscCall(PetscDrawLGSave(lg));
228   }
229   PetscCall(PetscViewerPopFormat(viewer));
230   PetscFunctionReturn(0);
231 }
232 
233 /*@C
234   KSPMonitorSNESResidualDrawLGCreate - Creates the `PetscViewer` used by `KSPMonitorSNESResidualDrawLG()`
235 
236   Collective on ksp
237 
238   Input Parameters:
239 + viewer - The PetscViewer
240 . format - The viewer format
241 - ctx    - An optional user context
242 
243   Output Parameter:
244 . vf    - The viewer context
245 
246   Level: intermediate
247 
248 .seealso: `KSP`, `SNES`, `KSPMonitorSet()`, `KSPMonitorTrueResidual()`
249 @*/
250 PetscErrorCode KSPMonitorSNESResidualDrawLGCreate(PetscViewer viewer, PetscViewerFormat format, void *ctx, PetscViewerAndFormat **vf) {
251   const char *names[] = {"linear", "nonlinear"};
252 
253   PetscFunctionBegin;
254   PetscCall(PetscViewerAndFormatCreate(viewer, format, vf));
255   (*vf)->data = ctx;
256   PetscCall(KSPMonitorLGCreate(PetscObjectComm((PetscObject)viewer), NULL, NULL, "Log Residual Norm", 2, names, PETSC_DECIDE, PETSC_DECIDE, 400, 300, &(*vf)->lg));
257   PetscFunctionReturn(0);
258 }
259 
260 PetscErrorCode SNESMonitorDefaultSetUp(SNES snes, PetscViewerAndFormat *vf) {
261   PetscFunctionBegin;
262   if (vf->format == PETSC_VIEWER_DRAW_LG) PetscCall(KSPMonitorLGCreate(PetscObjectComm((PetscObject)vf->viewer), NULL, NULL, "Log Residual Norm", 1, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, &vf->lg));
263   PetscFunctionReturn(0);
264 }
265 
266 /*@C
267    SNESMonitorDefault - Monitors progress of the `SNES` solvers (default).
268 
269    Collective on snes
270 
271    Input Parameters:
272 +  snes - the `SNES` context
273 .  its - iteration number
274 .  fgnorm - 2-norm of residual
275 -  vf - viewer and format structure
276 
277    Options Database:
278 .  -snes_monitor - use this function to monitor the convergence of the nonlinear solver
279 
280    Notes:
281    This routine prints the residual norm at each iteration.
282 
283    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
284    to be used during the `SNES` solve.
285 
286    Level: intermediate
287 
288 .seealso: `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorFunction()`, `SNESMonitorSolution()`, `SNESMonitorResidual()`,
289           `SNESMonitorSolutionUpdate()`, `SNESMonitorDefault()`, `SNESMonitorScaling()`, `SNESMonitorRange()`, `SNESMonitorRatio()`,
290           `SNESMonitorDefaultField()`
291 @*/
292 PetscErrorCode SNESMonitorDefault(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
293   PetscViewer       viewer = vf->viewer;
294   PetscViewerFormat format = vf->format;
295   PetscBool         isascii, isdraw;
296 
297   PetscFunctionBegin;
298   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
299   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
300   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
301   PetscCall(PetscViewerPushFormat(viewer, format));
302   if (isascii) {
303     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
304     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e \n", its, (double)fgnorm));
305     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
306   } else if (isdraw) {
307     if (format == PETSC_VIEWER_DRAW_LG) {
308       PetscDrawLG lg = (PetscDrawLG)vf->lg;
309       PetscReal   x, y;
310 
311       PetscValidHeaderSpecific(lg, PETSC_DRAWLG_CLASSID, 4);
312       if (!its) PetscCall(PetscDrawLGReset(lg));
313       x = (PetscReal)its;
314       if (fgnorm > 0.0) y = PetscLog10Real(fgnorm);
315       else y = -15.0;
316       PetscCall(PetscDrawLGAddPoint(lg, &x, &y));
317       if (its <= 20 || !(its % 5) || snes->reason) {
318         PetscCall(PetscDrawLGDraw(lg));
319         PetscCall(PetscDrawLGSave(lg));
320       }
321     }
322   }
323   PetscCall(PetscViewerPopFormat(viewer));
324   PetscFunctionReturn(0);
325 }
326 
327 /*@C
328    SNESMonitorScaling - Monitors the largest value in each row of the Jacobian.
329 
330    Collective on snes
331 
332    Input Parameters:
333 +  snes - the `SNES` context
334 .  its - iteration number
335 .  fgnorm - 2-norm of residual
336 -  vf - viewer and format structure
337 
338    Notes:
339    This routine prints the largest value in each row of the Jacobian
340 
341    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
342    to be used during the `SNES` solve.
343 
344    Level: intermediate
345 
346 .seealso: `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorRange()`, `SNESMonitorJacUpdateSpectrum()`
347 @*/
348 PetscErrorCode SNESMonitorScaling(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
349   PetscViewer viewer = vf->viewer;
350   KSP         ksp;
351   Mat         J;
352   Vec         v;
353 
354   PetscFunctionBegin;
355   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
356   PetscCall(SNESGetKSP(snes, &ksp));
357   PetscCall(KSPGetOperators(ksp, &J, NULL));
358   PetscCall(MatCreateVecs(J, &v, NULL));
359   PetscCall(MatGetRowMaxAbs(J, v, NULL));
360   PetscCall(PetscViewerPushFormat(viewer, vf->format));
361   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
362   PetscCall(PetscViewerASCIIPrintf(viewer, "SNES Jacobian maximum row entries\n"));
363   PetscCall(VecView(v, viewer));
364   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
365   PetscCall(PetscViewerPopFormat(viewer));
366   PetscCall(VecDestroy(&v));
367   PetscFunctionReturn(0);
368 }
369 
370 /*@C
371    SNESMonitorJacUpdateSpectrum - Monitors the spectrun of the change in the Jacobian from the last Jacobian evaluation
372 
373    Collective on snes
374 
375    Input Parameters:
376 +  snes - the `SNES` context
377 .  its - iteration number
378 .  fgnorm - 2-norm of residual
379 -  vf - viewer and format structure
380 
381    Option Database Key:
382 .  -snes_monitor_jacupdate_spectrum - activates this monitor
383 
384    Notes:
385    This routine prints the eigenvalues of the difference in the Jacobians
386 
387    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
388    to be used during the `SNES` solve.
389 
390    Level: intermediate
391 
392 .seealso: `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorRange()`
393 @*/
394 PetscErrorCode SNESMonitorJacUpdateSpectrum(SNES snes, PetscInt it, PetscReal fnorm, PetscViewerAndFormat *vf) {
395   Vec X;
396   Mat J, dJ, dJdense;
397   PetscErrorCode (*func)(SNES, Vec, Mat, Mat, void *);
398   PetscInt     n;
399   PetscBLASInt nb = 0, lwork;
400   PetscReal   *eigr, *eigi;
401   PetscScalar *work;
402   PetscScalar *a;
403 
404   PetscFunctionBegin;
405   if (it == 0) PetscFunctionReturn(0);
406   /* create the difference between the current update and the current Jacobian */
407   PetscCall(SNESGetSolution(snes, &X));
408   PetscCall(SNESGetJacobian(snes, NULL, &J, &func, NULL));
409   PetscCall(MatDuplicate(J, MAT_COPY_VALUES, &dJ));
410   PetscCall(SNESComputeJacobian(snes, X, dJ, dJ));
411   PetscCall(MatAXPY(dJ, -1.0, J, SAME_NONZERO_PATTERN));
412 
413   /* compute the spectrum directly */
414   PetscCall(MatConvert(dJ, MATSEQDENSE, MAT_INITIAL_MATRIX, &dJdense));
415   PetscCall(MatGetSize(dJ, &n, NULL));
416   PetscCall(PetscBLASIntCast(n, &nb));
417   lwork = 3 * nb;
418   PetscCall(PetscMalloc1(n, &eigr));
419   PetscCall(PetscMalloc1(n, &eigi));
420   PetscCall(PetscMalloc1(lwork, &work));
421   PetscCall(MatDenseGetArray(dJdense, &a));
422 #if !defined(PETSC_USE_COMPLEX)
423   {
424     PetscBLASInt lierr;
425     PetscInt     i;
426     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
427     PetscCallBLAS("LAPACKgeev", LAPACKgeev_("N", "N", &nb, a, &nb, eigr, eigi, NULL, &nb, NULL, &nb, work, &lwork, &lierr));
428     PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "geev() error %" PetscBLASInt_FMT, lierr);
429     PetscCall(PetscFPTrapPop());
430     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)snes), "Eigenvalues of J_%" PetscInt_FMT " - J_%" PetscInt_FMT ":\n", it, it - 1));
431     for (i = 0; i < n; i++) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)snes), "%5" PetscInt_FMT ": %20.5g + %20.5gi\n", i, (double)eigr[i], (double)eigi[i]));
432   }
433   PetscCall(MatDenseRestoreArray(dJdense, &a));
434   PetscCall(MatDestroy(&dJ));
435   PetscCall(MatDestroy(&dJdense));
436   PetscCall(PetscFree(eigr));
437   PetscCall(PetscFree(eigi));
438   PetscCall(PetscFree(work));
439   PetscFunctionReturn(0);
440 #else
441   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded for complex");
442 #endif
443 }
444 
445 PETSC_INTERN PetscErrorCode SNESMonitorRange_Private(SNES, PetscInt, PetscReal *);
446 
447 PetscErrorCode SNESMonitorRange_Private(SNES snes, PetscInt it, PetscReal *per) {
448   Vec          resid;
449   PetscReal    rmax, pwork;
450   PetscInt     i, n, N;
451   PetscScalar *r;
452 
453   PetscFunctionBegin;
454   PetscCall(SNESGetFunction(snes, &resid, NULL, NULL));
455   PetscCall(VecNorm(resid, NORM_INFINITY, &rmax));
456   PetscCall(VecGetLocalSize(resid, &n));
457   PetscCall(VecGetSize(resid, &N));
458   PetscCall(VecGetArray(resid, &r));
459   pwork = 0.0;
460   for (i = 0; i < n; i++) pwork += (PetscAbsScalar(r[i]) > .20 * rmax);
461   PetscCall(MPIU_Allreduce(&pwork, per, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)snes)));
462   PetscCall(VecRestoreArray(resid, &r));
463   *per = *per / N;
464   PetscFunctionReturn(0);
465 }
466 
467 /*@C
468    SNESMonitorRange - Prints the percentage of residual elements that are more then 10 percent of the maximum entry in the residual
469 
470    Collective on snes
471 
472    Input Parameters:
473 +  snes   - iterative context
474 .  it    - iteration number
475 .  rnorm - 2-norm (preconditioned) residual value (may be estimated).
476 -  dummy - unused monitor context
477 
478    Options Database Key:
479 .  -snes_monitor_range - Activates `SNESMonitorRange()`
480 
481    Note:
482    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
483    to be used during the `SNES` solve.
484 
485    Level: intermediate
486 
487 .seealso: `SNESMonitorSet()`, `SNESMonitorDefault()`, `SNESMonitorLGCreate()`, `SNESMonitorScaling()`
488 @*/
489 PetscErrorCode SNESMonitorRange(SNES snes, PetscInt it, PetscReal rnorm, PetscViewerAndFormat *vf) {
490   PetscReal        perc, rel;
491   PetscViewer      viewer = vf->viewer;
492   /* should be in a MonitorRangeContext */
493   static PetscReal prev;
494 
495   PetscFunctionBegin;
496   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
497   if (!it) prev = rnorm;
498   PetscCall(SNESMonitorRange_Private(snes, it, &perc));
499 
500   rel  = (prev - rnorm) / prev;
501   prev = rnorm;
502   PetscCall(PetscViewerPushFormat(viewer, vf->format));
503   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
504   PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES preconditioned resid norm %14.12e Percent values above 20 percent of maximum %5.2g relative decrease %5.2e ratio %5.2e \n", it, (double)rnorm, (double)(100.0 * perc), (double)rel, (double)(rel / perc)));
505   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
506   PetscCall(PetscViewerPopFormat(viewer));
507   PetscFunctionReturn(0);
508 }
509 
510 /*@C
511    SNESMonitorRatio - Monitors progress of the `SNES` solvers by printing the ratio
512    of residual norm at each iteration to the previous.
513 
514    Collective on snes
515 
516    Input Parameters:
517 +  snes - the `SNES` context
518 .  its - iteration number
519 .  fgnorm - 2-norm of residual (or gradient)
520 -  dummy -  context of monitor
521 
522    Option Database Key:
523 .  -snes_monitor_ratio - activate this monitor
524 
525    Level: intermediate
526 
527    Notes:
528    This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
529    to be used during the `SNES` solve.
530 
531    Be sure to call `SNESMonitorRationSetUp()` before using this monitor.
532 
533 .seealso: `SNESMonitorRationSetUp()`, `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorDefault()`
534 @*/
535 PetscErrorCode SNESMonitorRatio(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
536   PetscInt    len;
537   PetscReal  *history;
538   PetscViewer viewer = vf->viewer;
539 
540   PetscFunctionBegin;
541   PetscCall(SNESGetConvergenceHistory(snes, &history, NULL, &len));
542   PetscCall(PetscViewerPushFormat(viewer, vf->format));
543   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
544   if (!its || !history || its > len) {
545     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e \n", its, (double)fgnorm));
546   } else {
547     PetscReal ratio = fgnorm / history[its - 1];
548     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e %14.12e \n", its, (double)fgnorm, (double)ratio));
549   }
550   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
551   PetscCall(PetscViewerPopFormat(viewer));
552   PetscFunctionReturn(0);
553 }
554 
555 /*@C
556    SNESMonitorRatioSetUp - Insures the `SNES` object is saving its history since this monitor needs access to it
557 
558    Collective on snes
559 
560    Input Parameters:
561 +   snes - the `SNES` context
562 -   viewer - the `PetscViewer` object (ignored)
563 
564    Level: intermediate
565 
566 .seealso: `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorDefault()`, `SNESMonitorRatio()`
567 @*/
568 PetscErrorCode SNESMonitorRatioSetUp(SNES snes, PetscViewerAndFormat *vf) {
569   PetscReal *history;
570 
571   PetscFunctionBegin;
572   PetscCall(SNESGetConvergenceHistory(snes, &history, NULL, NULL));
573   if (!history) PetscCall(SNESSetConvergenceHistory(snes, NULL, NULL, 100, PETSC_TRUE));
574   PetscFunctionReturn(0);
575 }
576 
577 /*
578      Default (short) SNES Monitor, same as SNESMonitorDefault() except
579   it prints fewer digits of the residual as the residual gets smaller.
580   This is because the later digits are meaningless and are often
581   different on different machines; by using this routine different
582   machines will usually generate the same output.
583 
584   Deprecated: Intentionally has no manual page
585 */
586 PetscErrorCode SNESMonitorDefaultShort(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
587   PetscViewer viewer = vf->viewer;
588 
589   PetscFunctionBegin;
590   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
591   PetscCall(PetscViewerPushFormat(viewer, vf->format));
592   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
593   if (fgnorm > 1.e-9) {
594     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %g \n", its, (double)fgnorm));
595   } else if (fgnorm > 1.e-11) {
596     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %5.3e \n", its, (double)fgnorm));
597   } else {
598     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm < 1.e-11\n", its));
599   }
600   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
601   PetscCall(PetscViewerPopFormat(viewer));
602   PetscFunctionReturn(0);
603 }
604 
605 /*@C
606   SNESMonitorDefaultField - Monitors progress of the `SNES` solvers, separated into fields.
607 
608   Collective on snes
609 
610   Input Parameters:
611 + snes   - the `SNES` context
612 . its    - iteration number
613 . fgnorm - 2-norm of residual
614 - ctx    - the PetscViewer
615 
616    Option Database Key:
617 .  -snes_monitor_field - activate this monitor
618 
619   Notes:
620   This routine uses the `DM` attached to the residual vector to define the fields.
621 
622   This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
623   to be used during the `SNES` solve.
624 
625   Level: intermediate
626 
627 .seealso: `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorDefault()`
628 @*/
629 PetscErrorCode SNESMonitorDefaultField(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) {
630   PetscViewer viewer = vf->viewer;
631   Vec         r;
632   DM          dm;
633   PetscReal   res[256];
634   PetscInt    tablevel;
635 
636   PetscFunctionBegin;
637   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
638   PetscCall(SNESGetFunction(snes, &r, NULL, NULL));
639   PetscCall(VecGetDM(r, &dm));
640   if (!dm) PetscCall(SNESMonitorDefault(snes, its, fgnorm, vf));
641   else {
642     PetscSection s, gs;
643     PetscInt     Nf, f;
644 
645     PetscCall(DMGetLocalSection(dm, &s));
646     PetscCall(DMGetGlobalSection(dm, &gs));
647     if (!s || !gs) PetscCall(SNESMonitorDefault(snes, its, fgnorm, vf));
648     PetscCall(PetscSectionGetNumFields(s, &Nf));
649     PetscCheck(Nf <= 256, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Do not support %" PetscInt_FMT " fields > 256", Nf);
650     PetscCall(PetscSectionVecNorm(s, gs, r, NORM_2, res));
651     PetscCall(PetscObjectGetTabLevel((PetscObject)snes, &tablevel));
652     PetscCall(PetscViewerPushFormat(viewer, vf->format));
653     PetscCall(PetscViewerASCIIAddTab(viewer, tablevel));
654     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm));
655     for (f = 0; f < Nf; ++f) {
656       if (f) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
657       PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)res[f]));
658     }
659     PetscCall(PetscViewerASCIIPrintf(viewer, "] \n"));
660     PetscCall(PetscViewerASCIISubtractTab(viewer, tablevel));
661     PetscCall(PetscViewerPopFormat(viewer));
662   }
663   PetscFunctionReturn(0);
664 }
665 
666 /*@C
667    SNESConvergedDefault - Default onvergence test of the solvers for
668    systems of nonlinear equations.
669 
670    Collective on snes
671 
672    Input Parameters:
673 +  snes - the `SNES` context
674 .  it - the iteration (0 indicates before any Newton steps)
675 .  xnorm - 2-norm of current iterate
676 .  snorm - 2-norm of current step
677 .  fnorm - 2-norm of function at current iterate
678 -  dummy - unused context
679 
680    Output Parameter:
681 .   reason  - one of
682 .vb
683    SNES_CONVERGED_FNORM_ABS       - (fnorm < abstol),
684    SNES_CONVERGED_SNORM_RELATIVE  - (snorm < stol*xnorm),
685    SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
686    SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
687    SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
688    SNES_CONVERGED_ITERATING       - (otherwise),
689    SNES_DIVERGED_DTOL             - (fnorm > divtol*snes->fnorm0)
690 .ve
691 
692    where
693 +    maxf - maximum number of function evaluations,  set with `SNESSetTolerances()`
694 .    nfct - number of function evaluations,
695 .    abstol - absolute function norm tolerance, set with `SNESSetTolerances()`
696 .    rtol - relative function norm tolerance, set with `SNESSetTolerances()`
697 .    divtol - divergence tolerance, set with `SNESSetDivergenceTolerance()`
698 -    fnorm0 - 2-norm of the function at the initial solution (initial guess; zeroth iteration)
699 
700   Options Database Keys:
701 +  -snes_convergence_test default - see `SNESSetFromOptions()`
702 .  -snes_stol - convergence tolerance in terms of the norm  of the change in the solution between steps
703 .  -snes_atol <abstol> - absolute tolerance of residual norm
704 .  -snes_rtol <rtol> - relative decrease in tolerance norm from the initial 2-norm of the solution
705 .  -snes_divergence_tolerance <divtol> - if the residual goes above divtol*rnorm0, exit with divergence
706 .  -snes_max_funcs <max_funcs> - maximum number of function evaluations
707 .  -snes_max_fail <max_fail> - maximum number of line search failures allowed before stopping, default is none
708 -  -snes_max_linear_solve_fail - number of linear solver failures before `SNESSolve()` stops
709 
710    Level: intermediate
711 
712 .seealso: `SNES`, `SNESSolve()`, `SNESSetConvergenceTest()`, `SNESConvergedSkip()`, `SNESSetTolerances()`, `SNESSetDivergenceTolerance()`
713 @*/
714 PetscErrorCode SNESConvergedDefault(SNES snes, PetscInt it, PetscReal xnorm, PetscReal snorm, PetscReal fnorm, SNESConvergedReason *reason, void *dummy) {
715   PetscFunctionBegin;
716   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
717   PetscValidPointer(reason, 6);
718 
719   *reason = SNES_CONVERGED_ITERATING;
720   if (!it) {
721     /* set parameter for default relative tolerance convergence test */
722     snes->ttol   = fnorm * snes->rtol;
723     snes->rnorm0 = fnorm;
724   }
725   if (PetscIsInfOrNanReal(fnorm)) {
726     PetscCall(PetscInfo(snes, "Failed to converged, function norm is NaN\n"));
727     *reason = SNES_DIVERGED_FNORM_NAN;
728   } else if (fnorm < snes->abstol && (it || !snes->forceiteration)) {
729     PetscCall(PetscInfo(snes, "Converged due to function norm %14.12e < %14.12e\n", (double)fnorm, (double)snes->abstol));
730     *reason = SNES_CONVERGED_FNORM_ABS;
731   } else if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
732     PetscCall(PetscInfo(snes, "Exceeded maximum number of function evaluations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", snes->nfuncs, snes->max_funcs));
733     *reason = SNES_DIVERGED_FUNCTION_COUNT;
734   }
735 
736   if (it && !*reason) {
737     if (fnorm <= snes->ttol) {
738       PetscCall(PetscInfo(snes, "Converged due to function norm %14.12e < %14.12e (relative tolerance)\n", (double)fnorm, (double)snes->ttol));
739       *reason = SNES_CONVERGED_FNORM_RELATIVE;
740     } else if (snorm < snes->stol * xnorm) {
741       PetscCall(PetscInfo(snes, "Converged due to small update length: %14.12e < %14.12e * %14.12e\n", (double)snorm, (double)snes->stol, (double)xnorm));
742       *reason = SNES_CONVERGED_SNORM_RELATIVE;
743     } else if (snes->divtol > 0 && (fnorm > snes->divtol * snes->rnorm0)) {
744       PetscCall(PetscInfo(snes, "Diverged due to increase in function norm: %14.12e > %14.12e * %14.12e\n", (double)fnorm, (double)snes->divtol, (double)snes->rnorm0));
745       *reason = SNES_DIVERGED_DTOL;
746     }
747   }
748   PetscFunctionReturn(0);
749 }
750 
751 /*@C
752    SNESConvergedSkip - Convergence test for `SNES` that NEVER returns as
753    converged, UNLESS the maximum number of iteration have been reached.
754 
755    Logically Collective on snes
756 
757    Input Parameters:
758 +  snes - the `SNES` context
759 .  it - the iteration (0 indicates before any Newton steps)
760 .  xnorm - 2-norm of current iterate
761 .  snorm - 2-norm of current step
762 .  fnorm - 2-norm of function at current iterate
763 -  dummy - unused context
764 
765    Output Parameter:
766 .   reason  - `SNES_CONVERGED_ITERATING`, `SNES_CONVERGED_ITS`, or `SNES_DIVERGED_FNORM_NAN`
767 
768    Options Database Key:
769 .  -snes_convergence_test skip - see `SNESSetFromOptions()`
770 
771    Level: advanced
772 
773 .seealso: `SNES`, `SNESSolve()`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`
774 @*/
775 PetscErrorCode SNESConvergedSkip(SNES snes, PetscInt it, PetscReal xnorm, PetscReal snorm, PetscReal fnorm, SNESConvergedReason *reason, void *dummy) {
776   PetscFunctionBegin;
777   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
778   PetscValidPointer(reason, 6);
779 
780   *reason = SNES_CONVERGED_ITERATING;
781 
782   if (fnorm != fnorm) {
783     PetscCall(PetscInfo(snes, "Failed to converged, function norm is NaN\n"));
784     *reason = SNES_DIVERGED_FNORM_NAN;
785   } else if (it == snes->max_its) {
786     *reason = SNES_CONVERGED_ITS;
787   }
788   PetscFunctionReturn(0);
789 }
790 
791 /*@C
792   SNESSetWorkVecs - Gets a number of work vectors to be used internally by `SNES` solvers
793 
794   Input Parameters:
795 + snes  - the `SNES` context
796 - nw - number of work vectors to allocate
797 
798   Level: developer
799 
800 @*/
801 PetscErrorCode SNESSetWorkVecs(SNES snes, PetscInt nw) {
802   DM  dm;
803   Vec v;
804 
805   PetscFunctionBegin;
806   if (snes->work) PetscCall(VecDestroyVecs(snes->nwork, &snes->work));
807   snes->nwork = nw;
808 
809   PetscCall(SNESGetDM(snes, &dm));
810   PetscCall(DMGetGlobalVector(dm, &v));
811   PetscCall(VecDuplicateVecs(v, snes->nwork, &snes->work));
812   PetscCall(DMRestoreGlobalVector(dm, &v));
813   PetscFunctionReturn(0);
814 }
815