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