Actual source code: snesut.c
1: #include <petsc/private/snesimpl.h>
2: #include <petscdm.h>
3: #include <petscdmshell.h>
4: #include <petscsection.h>
5: #include <petscblaslapack.h>
7: /*@
8: SNESMonitorSolution - Monitors progress of a `SNES` `SNESSolve()` by calling
9: `VecView()` for the approximate solution at each iteration.
11: Collective
13: Input Parameters:
14: + snes - the `SNES` context
15: . its - iteration number
16: . fgnorm - 2-norm of residual
17: - vf - a viewer
19: Options Database Key:
20: . -snes_monitor_solution [ascii binary draw][:filename][:viewer format] - plots solution at each iteration
22: Level: intermediate
24: Note:
25: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
26: to be used during the `SNESSolve()`
28: .seealso: [](ch_snes), `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()`, `VecView()`
29: @*/
30: PetscErrorCode SNESMonitorSolution(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
31: {
32: Vec x;
33: PetscViewer viewer = vf->viewer;
35: PetscFunctionBegin;
37: PetscCall(SNESGetSolution(snes, &x));
38: PetscCall(PetscViewerPushFormat(viewer, vf->format));
39: PetscCall(VecView(x, viewer));
40: PetscCall(PetscViewerPopFormat(viewer));
41: PetscFunctionReturn(PETSC_SUCCESS);
42: }
44: /*@
45: SNESMonitorResidual - Monitors progress of a `SNESSolve()` by calling
46: `VecView()` for the residual at each iteration.
48: Collective
50: Input Parameters:
51: + snes - the `SNES` context
52: . its - iteration number
53: . fgnorm - 2-norm of residual
54: - vf - a viewer
56: Options Database Key:
57: . -snes_monitor_residual [ascii binary draw][:filename][:viewer format] - plots residual (not its norm) at each iteration
59: Level: intermediate
61: Note:
62: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
63: to be used during the `SNES` solve.
65: .seealso: [](ch_snes), `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()`, `VecView()`, `SNESMonitor()`
66: @*/
67: PetscErrorCode SNESMonitorResidual(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
68: {
69: Vec x;
71: PetscFunctionBegin;
73: PetscCall(SNESGetFunction(snes, &x, NULL, NULL));
74: PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
75: PetscCall(VecView(x, vf->viewer));
76: PetscCall(PetscViewerPopFormat(vf->viewer));
77: PetscFunctionReturn(PETSC_SUCCESS);
78: }
80: /*@
81: SNESMonitorSolutionUpdate - Monitors progress of a `SNESSolve()` by calling
82: `VecView()` for the UPDATE to the solution at each iteration.
84: Collective
86: Input Parameters:
87: + snes - the `SNES` context
88: . its - iteration number
89: . fgnorm - 2-norm of residual
90: - vf - a viewer
92: Options Database Key:
93: . -snes_monitor_solution_update [ascii binary draw][:filename][:viewer format] - plots update to solution at each iteration
95: Level: intermediate
97: Note:
98: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
99: to be used during the `SNES` solve.
101: .seealso: [](ch_snes), `SNESMonitorSet()`, `SNESMonitorDefault()`, `VecView()`, `SNESMonitor()`
102: @*/
103: PetscErrorCode SNESMonitorSolutionUpdate(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
104: {
105: Vec x;
106: PetscViewer viewer = vf->viewer;
108: PetscFunctionBegin;
110: PetscCall(SNESGetSolutionUpdate(snes, &x));
111: PetscCall(PetscViewerPushFormat(viewer, vf->format));
112: PetscCall(VecView(x, viewer));
113: PetscCall(PetscViewerPopFormat(viewer));
114: PetscFunctionReturn(PETSC_SUCCESS);
115: }
117: #include <petscdraw.h>
119: /*@
120: KSPMonitorSNESResidual - Prints the `SNES` residual norm, as well as the `KSP` residual norm, at each iteration of a `KSPSolve()` called within a `SNESSolve()`.
122: Collective
124: Input Parameters:
125: + ksp - iterative context
126: . n - iteration number
127: . rnorm - 2-norm (preconditioned) residual value (may be estimated).
128: - vf - The viewer context
130: Options Database Key:
131: . -snes_monitor_ksp - Activates `KSPMonitorSNESResidual()`
133: Level: intermediate
135: Note:
136: This is not called directly by users, rather one calls `KSPMonitorSet()`, with this function as an argument, to cause the monitor
137: to be used during the `KSP` solve.
139: .seealso: [](ch_snes), `SNES`, `KSPMonitorSet()`, `KSPMonitorResidual()`, `KSPMonitorTrueResidualMaxNorm()`, `KSPMonitor()`, `SNESMonitor()`, `PetscViewerAndFormat()`
140: @*/
141: PetscErrorCode KSPMonitorSNESResidual(KSP ksp, PetscInt n, PetscReal rnorm, PetscViewerAndFormat *vf)
142: {
143: PetscViewer viewer = vf->viewer;
144: PetscViewerFormat format = vf->format;
145: SNES snes = (SNES)vf->data;
146: Vec snes_solution, work1, work2;
147: PetscReal snorm;
148: PetscInt tablevel;
149: const char *prefix;
151: PetscFunctionBegin;
153: PetscCall(SNESGetSolution(snes, &snes_solution));
154: PetscCall(VecDuplicate(snes_solution, &work1));
155: PetscCall(VecDuplicate(snes_solution, &work2));
156: PetscCall(KSPBuildSolution(ksp, work1, NULL));
157: PetscCall(VecAYPX(work1, -1.0, snes_solution));
158: PetscCall(SNESComputeFunction(snes, work1, work2));
159: PetscCall(VecNorm(work2, NORM_2, &snorm));
160: PetscCall(VecDestroy(&work1));
161: PetscCall(VecDestroy(&work2));
163: PetscCall(PetscObjectGetTabLevel((PetscObject)ksp, &tablevel));
164: PetscCall(PetscObjectGetOptionsPrefix((PetscObject)ksp, &prefix));
165: PetscCall(PetscViewerPushFormat(viewer, format));
166: PetscCall(PetscViewerASCIIAddTab(viewer, tablevel));
167: if (n == 0 && prefix) PetscCall(PetscViewerASCIIPrintf(viewer, " Residual norms for %s solve.\n", prefix));
168: PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Residual norm %5.3e KSP Residual norm %5.3e\n", n, (double)snorm, (double)rnorm));
169: PetscCall(PetscViewerASCIISubtractTab(viewer, tablevel));
170: PetscCall(PetscViewerPopFormat(viewer));
171: PetscFunctionReturn(PETSC_SUCCESS);
172: }
174: /*@
175: KSPMonitorSNESResidualDrawLG - Plots the linear `KSP` residual norm and the `SNES` residual norm of a `KSPSolve()` called within a `SNESSolve()`.
177: Collective
179: Input Parameters:
180: + ksp - iterative context
181: . n - iteration number
182: . rnorm - 2-norm (preconditioned) residual value (may be estimated).
183: - vf - The viewer context, created with `KSPMonitorSNESResidualDrawLGCreate()`
185: Options Database Key:
186: . -snes_monitor_ksp draw::draw_lg - Activates `KSPMonitorSNESResidualDrawLG()`
188: Level: intermediate
190: Note:
191: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
192: to be used during the `SNESSolve()`
194: .seealso: [](ch_snes), `KSPMonitorSet()`, `KSPMonitorTrueResidual()`, `SNESMonitor()`, `KSPMonitor()`, `KSPMonitorSNESResidualDrawLGCreate()`
195: @*/
196: PetscErrorCode KSPMonitorSNESResidualDrawLG(KSP ksp, PetscInt n, PetscReal rnorm, PetscViewerAndFormat *vf)
197: {
198: PetscViewer viewer = vf->viewer;
199: PetscViewerFormat format = vf->format;
200: PetscDrawLG lg;
201: SNES snes = (SNES)vf->data;
202: Vec snes_solution, work1, work2;
203: PetscReal snorm;
204: KSPConvergedReason reason;
205: PetscReal x[2], y[2];
207: PetscFunctionBegin;
209: PetscCall(PetscViewerDrawGetDrawLG(viewer, 0, &lg));
210: PetscCall(SNESGetSolution(snes, &snes_solution));
211: PetscCall(VecDuplicate(snes_solution, &work1));
212: PetscCall(VecDuplicate(snes_solution, &work2));
213: PetscCall(KSPBuildSolution(ksp, work1, NULL));
214: PetscCall(VecAYPX(work1, -1.0, snes_solution));
215: PetscCall(SNESComputeFunction(snes, work1, work2));
216: PetscCall(VecNorm(work2, NORM_2, &snorm));
217: PetscCall(VecDestroy(&work1));
218: PetscCall(VecDestroy(&work2));
220: PetscCall(PetscViewerPushFormat(viewer, format));
221: if (!n) PetscCall(PetscDrawLGReset(lg));
222: x[0] = (PetscReal)n;
223: if (rnorm > 0.0) y[0] = PetscLog10Real(rnorm);
224: else y[0] = -15.0;
225: x[1] = (PetscReal)n;
226: if (snorm > 0.0) y[1] = PetscLog10Real(snorm);
227: else y[1] = -15.0;
228: PetscCall(PetscDrawLGAddPoint(lg, x, y));
229: PetscCall(KSPGetConvergedReason(ksp, &reason));
230: if (n <= 20 || !(n % 5) || reason) {
231: PetscCall(PetscDrawLGDraw(lg));
232: PetscCall(PetscDrawLGSave(lg));
233: }
234: PetscCall(PetscViewerPopFormat(viewer));
235: PetscFunctionReturn(PETSC_SUCCESS);
236: }
238: /*@
239: KSPMonitorSNESResidualDrawLGCreate - Creates the `PetscViewer` used by `KSPMonitorSNESResidualDrawLG()`
241: Collective
243: Input Parameters:
244: + viewer - The `PetscViewer`
245: . format - The viewer format
246: - ctx - An optional application context
248: Output Parameter:
249: . vf - The viewer context
251: Level: intermediate
253: .seealso: [](ch_snes), `KSP`, `SNES`, `PetscViewerFormat`, `PetscViewerAndFormat`, `KSPMonitorSet()`, `KSPMonitorTrueResidual()`
254: @*/
255: PetscErrorCode KSPMonitorSNESResidualDrawLGCreate(PetscViewer viewer, PetscViewerFormat format, PetscCtx ctx, PetscViewerAndFormat **vf)
256: {
257: const char *names[] = {"linear", "nonlinear"};
259: PetscFunctionBegin;
260: PetscCall(PetscViewerAndFormatCreate(viewer, format, vf));
261: (*vf)->data = ctx;
262: PetscCall(PetscViewerMonitorLGSetUp(viewer, NULL, NULL, "Log Residual Norm", 2, names, PETSC_DECIDE, PETSC_DECIDE, 400, 300));
263: PetscFunctionReturn(PETSC_SUCCESS);
264: }
266: /*@
267: SNESMonitorDefaultSetUp - Prepare the `PetscViewerAndFormat` associated with `SNESMonitorDefault()`, in particular by initializing the underlying `PetscDrawLG` when the viewer format is `PETSC_VIEWER_DRAW_LG`
269: Collective
271: Input Parameters:
272: + snes - the `SNES` context
273: - vf - the viewer/format pair passed to `SNESMonitorSet()` along with `SNESMonitorDefault()`
275: Level: developer
277: .seealso: [](ch_snes), `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()`, `PetscViewerAndFormat`, `PetscViewerMonitorLGSetUp()`
278: @*/
279: PetscErrorCode SNESMonitorDefaultSetUp(SNES snes, PetscViewerAndFormat *vf)
280: {
281: PetscFunctionBegin;
282: if (vf->format == PETSC_VIEWER_DRAW_LG) PetscCall(PetscViewerMonitorLGSetUp(vf->viewer, NULL, NULL, "Log Residual Norm", 1, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300));
283: PetscFunctionReturn(PETSC_SUCCESS);
284: }
286: /*@
287: SNESMonitorDefault - Monitors progress of a `SNESSolve()` (default).
289: Collective
291: Input Parameters:
292: + snes - the `SNES` context
293: . its - iteration number
294: . fgnorm - 2-norm of residual
295: - vf - viewer and format structure
297: Options Database Key:
298: . -snes_monitor - use this function to monitor the convergence of the nonlinear solver
300: Level: intermediate
302: Notes:
303: Prints the residual norm at each iteration.
305: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
306: to be used during the `SNES` solve.
308: .seealso: [](ch_snes), `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorFunction()`, `SNESMonitorResidual()`,
309: `SNESMonitorSolutionUpdate()`, `SNESMonitorScaling()`, `SNESMonitorRange()`, `SNESMonitorRatio()`,
310: `SNESMonitorDefaultField()`, `PetscViewerFormat`, `PetscViewerAndFormat`
311: @*/
312: PetscErrorCode SNESMonitorDefault(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
313: {
314: PetscViewer viewer = vf->viewer;
315: PetscViewerFormat format = vf->format;
316: PetscBool isascii, isdraw;
318: PetscFunctionBegin;
320: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
321: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
322: PetscCall(PetscViewerPushFormat(viewer, format));
323: if (isascii) {
324: PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
325: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
326: Vec dx;
327: PetscReal upnorm;
328: SNESObjectiveFn *objective;
330: PetscCall(SNESGetSolutionUpdate(snes, &dx));
331: PetscCall(VecNorm(dx, NORM_2, &upnorm));
332: PetscCall(SNESGetObjective(snes, &objective, NULL));
333: if (objective) {
334: Vec x;
335: PetscReal obj;
337: PetscCall(SNESGetSolution(snes, &x));
338: PetscCall(SNESComputeObjective(snes, x, &obj));
339: PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e, Update norm %14.12e, Objective %14.12e\n", its, (double)fgnorm, (double)upnorm, (double)obj));
340: } else {
341: PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e, Update norm %14.12e\n", its, (double)fgnorm, (double)upnorm));
342: }
343: } else {
344: PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e\n", its, (double)fgnorm));
345: }
346: PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
347: } else if (isdraw) {
348: if (format == PETSC_VIEWER_DRAW_LG) {
349: PetscDrawLG lg;
350: PetscReal x, y;
352: PetscCall(PetscViewerDrawGetDrawLG(viewer, 0, &lg));
353: if (!its) PetscCall(PetscDrawLGReset(lg));
354: x = (PetscReal)its;
355: if (fgnorm > 0.0) y = PetscLog10Real(fgnorm);
356: else y = -15.0;
357: PetscCall(PetscDrawLGAddPoint(lg, &x, &y));
358: if (its <= 20 || !(its % 5) || snes->reason) {
359: PetscCall(PetscDrawLGDraw(lg));
360: PetscCall(PetscDrawLGSave(lg));
361: }
362: }
363: }
364: PetscCall(PetscViewerPopFormat(viewer));
365: PetscFunctionReturn(PETSC_SUCCESS);
366: }
368: /*@
369: SNESMonitorScaling - Monitors the largest value in each row of the Jacobian of a `SNESSolve()`
371: Collective
373: Input Parameters:
374: + snes - the `SNES` context
375: . its - iteration number
376: . fgnorm - 2-norm of residual
377: - vf - viewer and format structure
379: Level: intermediate
381: Notes:
382: This routine prints the largest value in each row of the Jacobian
384: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
385: to be used during the `SNES` solve.
387: .seealso: [](ch_snes), `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorRange()`, `SNESMonitorJacUpdateSpectrum()`,
388: `PetscViewerFormat`, `PetscViewerAndFormat`
389: @*/
390: PetscErrorCode SNESMonitorScaling(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
391: {
392: PetscViewer viewer = vf->viewer;
393: KSP ksp;
394: Mat J;
395: Vec v;
397: PetscFunctionBegin;
399: PetscCall(SNESGetKSP(snes, &ksp));
400: PetscCall(KSPGetOperators(ksp, &J, NULL));
401: PetscCall(MatCreateVecs(J, &v, NULL));
402: PetscCall(MatGetRowMaxAbs(J, v, NULL));
403: PetscCall(PetscViewerPushFormat(viewer, vf->format));
404: PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
405: PetscCall(PetscViewerASCIIPrintf(viewer, "SNES Jacobian maximum row entries\n"));
406: PetscCall(VecView(v, viewer));
407: PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
408: PetscCall(PetscViewerPopFormat(viewer));
409: PetscCall(VecDestroy(&v));
410: PetscFunctionReturn(PETSC_SUCCESS);
411: }
413: /*@
414: SNESMonitorJacUpdateSpectrum - Monitors the spectrun of the change in the Jacobian from the last Jacobian evaluation of a `SNESSolve()`
416: Collective
418: Input Parameters:
419: + snes - the `SNES` context
420: . it - iteration number
421: . fnorm - 2-norm of residual
422: - vf - viewer and format structure
424: Options Database Key:
425: . -snes_monitor_jacupdate_spectrum - activates this monitor
427: Level: intermediate
429: Notes:
430: This routine prints the eigenvalues of the difference in the Jacobians
432: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
433: to be used during the `SNES` solve.
435: .seealso: [](ch_snes), `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorRange()`, `PetscViewerFormat`, `PetscViewerAndFormat`
436: @*/
437: PetscErrorCode SNESMonitorJacUpdateSpectrum(SNES snes, PetscInt it, PetscReal fnorm, PetscViewerAndFormat *vf)
438: {
439: Vec X;
440: Mat J, dJ, dJdense;
441: PetscErrorCode (*func)(SNES, Vec, Mat, Mat, void *);
442: PetscInt n;
443: PetscBLASInt nb = 0, lwork;
444: PetscReal *eigr, *eigi;
445: PetscScalar *work;
446: PetscScalar *a;
448: PetscFunctionBegin;
449: if (it == 0) PetscFunctionReturn(PETSC_SUCCESS);
450: /* create the difference between the current update and the current Jacobian */
451: PetscCall(SNESGetSolution(snes, &X));
452: PetscCall(SNESGetJacobian(snes, NULL, &J, &func, NULL));
453: PetscCall(MatDuplicate(J, MAT_COPY_VALUES, &dJ));
454: PetscCall(SNESComputeJacobian(snes, X, dJ, dJ));
455: PetscCall(MatAXPY(dJ, -1.0, J, SAME_NONZERO_PATTERN));
457: /* compute the spectrum directly */
458: PetscCall(MatConvert(dJ, MATSEQDENSE, MAT_INITIAL_MATRIX, &dJdense));
459: PetscCall(MatGetSize(dJ, &n, NULL));
460: PetscCall(PetscBLASIntCast(n, &nb));
461: lwork = 3 * nb;
462: PetscCall(PetscMalloc1(n, &eigr));
463: PetscCall(PetscMalloc1(n, &eigi));
464: PetscCall(PetscMalloc1(lwork, &work));
465: PetscCall(MatDenseGetArray(dJdense, &a));
466: #if !PetscDefined(USE_COMPLEX)
467: {
468: PetscInt i;
469: PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
470: PetscCallLAPACKInfo("LAPACKgeev", LAPACKgeev_("N", "N", &nb, a, &nb, eigr, eigi, NULL, &nb, NULL, &nb, work, &lwork, &info));
471: PetscCall(PetscFPTrapPop());
472: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)snes), "Eigenvalues of J_%" PetscInt_FMT " - J_%" PetscInt_FMT ":\n", it, it - 1));
473: 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]));
474: }
475: PetscCall(MatDenseRestoreArray(dJdense, &a));
476: PetscCall(MatDestroy(&dJ));
477: PetscCall(MatDestroy(&dJdense));
478: PetscCall(PetscFree(eigr));
479: PetscCall(PetscFree(eigi));
480: PetscCall(PetscFree(work));
481: PetscFunctionReturn(PETSC_SUCCESS);
482: #else
483: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded for complex");
484: #endif
485: }
487: PETSC_INTERN PetscErrorCode SNESMonitorRange_Private(SNES, PetscInt, PetscReal *);
489: PetscErrorCode SNESMonitorRange_Private(SNES snes, PetscInt it, PetscReal *per)
490: {
491: Vec resid;
492: PetscReal rmax;
493: PetscInt i, n, N;
494: PetscScalar *r;
496: PetscFunctionBegin;
497: PetscCall(SNESGetFunction(snes, &resid, NULL, NULL));
498: PetscCall(VecNorm(resid, NORM_INFINITY, &rmax));
499: PetscCall(VecGetLocalSize(resid, &n));
500: PetscCall(VecGetSize(resid, &N));
501: PetscCall(VecGetArray(resid, &r));
502: *per = 0.0;
503: for (i = 0; i < n; i++) *per += (PetscAbsScalar(r[i]) > .20 * rmax);
504: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, per, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)snes)));
505: PetscCall(VecRestoreArray(resid, &r));
506: *per = *per / N;
507: PetscFunctionReturn(PETSC_SUCCESS);
508: }
510: /*@
511: SNESMonitorRange - Prints the percentage of residual elements that are more than 10 percent of the maximum entry in the residual in each iteration of a `SNESSolve()`
513: Collective
515: Input Parameters:
516: + snes - `SNES` iterative context
517: . it - iteration number
518: . rnorm - 2-norm (preconditioned) residual value (may be estimated).
519: - vf - unused monitor context
521: Options Database Key:
522: . -snes_monitor_range - Activates `SNESMonitorRange()`
524: Level: intermediate
526: Note:
527: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
528: to be used during the `SNES` solve.
530: .seealso: [](ch_snes), `SNESMonitorSet()`, `SNESMonitorDefault()`, `SNESMonitorLGCreate()`, `SNESMonitorScaling()`, `PetscViewerFormat`, `PetscViewerAndFormat`
531: @*/
532: PetscErrorCode SNESMonitorRange(SNES snes, PetscInt it, PetscReal rnorm, PetscViewerAndFormat *vf)
533: {
534: PetscReal perc, rel;
535: PetscViewer viewer = vf->viewer;
536: /* should be in a MonitorRangeContext */
537: static PetscReal prev;
539: PetscFunctionBegin;
541: if (!it) prev = rnorm;
542: PetscCall(SNESMonitorRange_Private(snes, it, &perc));
544: rel = (prev - rnorm) / prev;
545: prev = rnorm;
546: PetscCall(PetscViewerPushFormat(viewer, vf->format));
547: PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
548: 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 * perc), (double)rel, (double)(rel / perc)));
549: PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
550: PetscCall(PetscViewerPopFormat(viewer));
551: PetscFunctionReturn(PETSC_SUCCESS);
552: }
554: /*@
555: SNESMonitorRatio - Monitors progress of a `SNESSolve()` by printing the ratio of residual norm at each iteration to the previous.
557: Collective
559: Input Parameters:
560: + snes - the `SNES` context
561: . its - iteration number
562: . fgnorm - 2-norm of residual (or gradient)
563: - vf - context of monitor
565: Options Database Key:
566: . -snes_monitor_ratio - activate this monitor
568: Level: intermediate
570: Notes:
571: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
572: to be used during the `SNES` solve.
574: Be sure to call `SNESMonitorRationSetUp()` before using this monitor.
576: .seealso: [](ch_snes), `SNESMonitorRationSetUp()`, `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorDefault()`, `PetscViewerFormat`, `PetscViewerAndFormat`
577: @*/
578: PetscErrorCode SNESMonitorRatio(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
579: {
580: PetscInt len;
581: PetscReal *history;
582: PetscViewer viewer = vf->viewer;
584: PetscFunctionBegin;
585: PetscCall(SNESGetConvergenceHistory(snes, &history, NULL, &len));
586: PetscCall(PetscViewerPushFormat(viewer, vf->format));
587: PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel));
588: if (!its || !history || its > len) {
589: PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e\n", its, (double)fgnorm));
590: } else {
591: PetscReal ratio = fgnorm / history[its - 1];
592: PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e %14.12e\n", its, (double)fgnorm, (double)ratio));
593: }
594: PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel));
595: PetscCall(PetscViewerPopFormat(viewer));
596: PetscFunctionReturn(PETSC_SUCCESS);
597: }
599: /*@
600: SNESMonitorRatioSetUp - Insures the `SNES` object is saving its history since this monitor needs access to it
602: Collective
604: Input Parameters:
605: + snes - the `SNES` context
606: - vf - `PetscViewerAndFormat` (ignored)
608: Level: intermediate
610: .seealso: [](ch_snes), `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorDefault()`, `SNESMonitorRatio()`, `PetscViewerFormat`, `PetscViewerAndFormat`
611: @*/
612: PetscErrorCode SNESMonitorRatioSetUp(SNES snes, PetscViewerAndFormat *vf)
613: {
614: PetscReal *history;
616: PetscFunctionBegin;
617: PetscCall(SNESGetConvergenceHistory(snes, &history, NULL, NULL));
618: if (!history) PetscCall(SNESSetConvergenceHistory(snes, NULL, NULL, 100, PETSC_TRUE));
619: PetscFunctionReturn(PETSC_SUCCESS);
620: }
622: /*@
623: SNESMonitorDefaultField - Monitors progress of a `SNESSolve()`, separated into fields.
625: Collective
627: Input Parameters:
628: + snes - the `SNES` context
629: . its - iteration number
630: . fgnorm - 2-norm of residual
631: - vf - the PetscViewer
633: Options Database Key:
634: . -snes_monitor_field - activate this monitor
636: Level: intermediate
638: Notes:
639: This routine uses the `DM` attached to the residual vector to define the fields.
641: This is not called directly by users, rather one calls `SNESMonitorSet()`, with this function as an argument, to cause the monitor
642: to be used during the `SNES` solve.
644: .seealso: [](ch_snes), `SNESMonitorSet()`, `SNESMonitorSolution()`, `SNESMonitorDefault()`, `PetscViewerFormat`, `PetscViewerAndFormat`
645: @*/
646: PetscErrorCode SNESMonitorDefaultField(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf)
647: {
648: PetscViewer viewer = vf->viewer;
649: Vec r;
650: DM dm;
651: PetscReal res[256];
652: PetscInt tablevel;
654: PetscFunctionBegin;
656: PetscCall(SNESGetFunction(snes, &r, NULL, NULL));
657: PetscCall(VecGetDM(r, &dm));
658: if (!dm) PetscCall(SNESMonitorDefault(snes, its, fgnorm, vf));
659: else {
660: PetscSection s, gs;
661: PetscInt Nf;
663: PetscCall(DMGetLocalSection(dm, &s));
664: PetscCall(DMGetGlobalSection(dm, &gs));
665: if (!s || !gs) PetscCall(SNESMonitorDefault(snes, its, fgnorm, vf));
666: PetscCall(PetscSectionGetNumFields(s, &Nf));
667: PetscCheck(Nf <= 256, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Do not support %" PetscInt_FMT " fields > 256", Nf);
668: PetscCall(PetscSectionVecNorm(s, gs, r, NORM_2, res));
669: PetscCall(PetscObjectGetTabLevel((PetscObject)snes, &tablevel));
670: PetscCall(PetscViewerPushFormat(viewer, vf->format));
671: PetscCall(PetscViewerASCIIAddTab(viewer, tablevel));
672: PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm));
673: for (PetscInt f = 0; f < Nf; ++f) {
674: if (f) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
675: PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)res[f]));
676: }
677: PetscCall(PetscViewerASCIIPrintf(viewer, "] \n"));
678: PetscCall(PetscViewerASCIISubtractTab(viewer, tablevel));
679: PetscCall(PetscViewerPopFormat(viewer));
680: }
681: PetscFunctionReturn(PETSC_SUCCESS);
682: }
684: /*@
685: SNESConvergedDefault - Default convergence test for `SNESSolve()`.
687: Collective
689: Input Parameters:
690: + snes - the `SNES` context
691: . it - the iteration (0 indicates before any Newton steps)
692: . xnorm - 2-norm of current iterate
693: . snorm - 2-norm of current step
694: . fnorm - 2-norm of function at current iterate
695: - ctx - unused context
697: Output Parameter:
698: . reason - converged reason, see `SNESConvergedReason`
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, use `unlimited` for no maximum
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
710: Level: developer
712: Notes:
713: This routine is not generally called directly. It is set with `SNESSetConvergenceTest()` automatically before the `SNESSolve()`.
715: It can be called within a custom convergence test that should also apply the standard convergence tests
717: .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetConvergenceTest()`, `SNESConvergedSkip()`, `SNESSetTolerances()`, `SNESSetDivergenceTolerance()`,
718: `SNESConvergedReason`
719: @*/
720: PetscErrorCode SNESConvergedDefault(SNES snes, PetscInt it, PetscReal xnorm, PetscReal snorm, PetscReal fnorm, SNESConvergedReason *reason, PetscCtx ctx)
721: {
722: PetscFunctionBegin;
724: PetscAssertPointer(reason, 6);
726: *reason = SNES_CONVERGED_ITERATING;
727: if (!it) {
728: /* set parameter for default relative tolerance convergence test */
729: snes->ttol = fnorm * snes->rtol;
730: snes->rnorm0 = fnorm;
731: }
732: if (PetscIsInfOrNanReal(fnorm)) {
733: PetscCall(PetscInfo(snes, "Failed to converged, function norm is NaN\n"));
734: *reason = SNES_DIVERGED_FUNCTION_NANORINF;
735: } else if (fnorm < snes->abstol && (it || !snes->forceiteration)) {
736: PetscCall(PetscInfo(snes, "Converged due to function norm %14.12e < %14.12e\n", (double)fnorm, (double)snes->abstol));
737: *reason = SNES_CONVERGED_FNORM_ABS;
738: } else if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
739: PetscCall(PetscInfo(snes, "Exceeded maximum number of function evaluations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", snes->nfuncs, snes->max_funcs));
740: *reason = SNES_DIVERGED_FUNCTION_COUNT;
741: }
743: if (it && !*reason) {
744: if (fnorm <= snes->ttol) {
745: PetscCall(PetscInfo(snes, "Converged due to function norm %14.12e < %14.12e (relative tolerance)\n", (double)fnorm, (double)snes->ttol));
746: *reason = SNES_CONVERGED_FNORM_RELATIVE;
747: } else if (snorm < snes->stol * xnorm) {
748: PetscCall(PetscInfo(snes, "Converged due to small update length: %14.12e < %14.12e * %14.12e\n", (double)snorm, (double)snes->stol, (double)xnorm));
749: *reason = SNES_CONVERGED_SNORM_RELATIVE;
750: } else if (snes->divtol != PETSC_UNLIMITED && (fnorm > snes->divtol * snes->rnorm0)) {
751: 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));
752: *reason = SNES_DIVERGED_DTOL;
753: }
754: }
755: PetscFunctionReturn(PETSC_SUCCESS);
756: }
758: /*@
759: SNESConvergedSkip - Convergence test for `SNES` that NEVER returns as
760: converged, UNLESS the maximum number of iteration have been reached.
762: Logically Collective
764: Input Parameters:
765: + snes - the `SNES` context
766: . it - the iteration (0 indicates before any Newton steps)
767: . xnorm - 2-norm of current iterate
768: . snorm - 2-norm of current step
769: . fnorm - 2-norm of function at current iterate
770: - ctx - unused context
772: Output Parameter:
773: . reason - `SNES_CONVERGED_ITERATING`, `SNES_CONVERGED_ITS`, or `SNES_DIVERGED_FUNCTION_NANORINF`
775: Options Database Key:
776: . -snes_convergence_test skip - see `SNESSetFromOptions()`
778: Level: advanced
780: Note:
781: This is often used if `snes` is being used as a nonlinear smoother in `SNESFAS` or possibly other `SNESType`
783: .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `SNESConvergedReason`
784: @*/
785: PetscErrorCode SNESConvergedSkip(SNES snes, PetscInt it, PetscReal xnorm, PetscReal snorm, PetscReal fnorm, SNESConvergedReason *reason, PetscCtx ctx)
786: {
787: PetscFunctionBegin;
789: PetscAssertPointer(reason, 6);
791: *reason = SNES_CONVERGED_ITERATING;
793: if (fnorm != fnorm) {
794: PetscCall(PetscInfo(snes, "Failed to converged, function norm is NaN\n"));
795: *reason = SNES_DIVERGED_FUNCTION_NANORINF;
796: } else if (it == snes->max_its) {
797: *reason = SNES_CONVERGED_ITS;
798: }
799: PetscFunctionReturn(PETSC_SUCCESS);
800: }
802: /*@
803: SNESSetWorkVecs - Allocates a number of work vectors to be used internally by the `SNES` solver
805: Input Parameters:
806: + snes - the `SNES` context
807: - nw - number of work vectors to allocate
809: Level: developer
811: Note:
812: Each `SNESType` calls this with the number of work vectors that particular type needs.
814: .seealso: [](ch_snes), `SNES`
815: @*/
816: PetscErrorCode SNESSetWorkVecs(SNES snes, PetscInt nw)
817: {
818: DM dm;
819: Vec v;
820: PetscBool restore = PETSC_FALSE;
822: PetscFunctionBegin;
825: if (snes->work) PetscCall(VecDestroyVecs(snes->nwork, &snes->work));
826: snes->nwork = nw;
827: if (!nw) PetscFunctionReturn(PETSC_SUCCESS);
829: PetscCall(SNESGetDM(snes, &dm));
830: if (snes->dmAuto) {
831: PetscCall(DMShellGetGlobalVector(dm, &v));
832: if (!v) v = snes->vec_sol;
833: if (!v) v = snes->vec_func;
834: if (!v) v = snes->vec_rhs;
835: } else {
836: restore = PETSC_TRUE;
837: PetscCall(DMGetGlobalVector(dm, &v));
838: }
839: PetscCheck(v, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Vector to be duplicated not found");
840: PetscCall(VecDuplicateVecs(v, snes->nwork, &snes->work));
841: if (restore) PetscCall(DMRestoreGlobalVector(dm, &v));
842: PetscFunctionReturn(PETSC_SUCCESS);
843: }