xref: /petsc/src/ts/interface/tsmon.c (revision 66c9fbdd036b1e887ebf0d2bef6dbdcafd086d45)
1 #include <petsc/private/tsimpl.h> /*I "petscts.h"  I*/
2 #include <petscdm.h>
3 #include <petscds.h>
4 #include <petscdmswarm.h>
5 #include <petscdraw.h>
6 
7 /*@C
8    TSMonitor - Runs all user-provided monitor routines set using `TSMonitorSet()`
9 
10    Collective
11 
12    Input Parameters:
13 +  ts - time stepping context obtained from `TSCreate()`
14 .  step - step number that has just completed
15 .  ptime - model time of the state
16 -  u - state at the current model time
17 
18    Level: developer
19 
20    Notes:
21    `TSMonitor()` is typically used automatically within the time stepping implementations.
22    Users would almost never call this routine directly.
23 
24    A step of -1 indicates that the monitor is being called on a solution obtained by interpolating from computed solutions
25 
26 .seealso: `TS`, `TSMonitorSet()`, `TSMonitorSetFromOptions()`
27 @*/
28 PetscErrorCode TSMonitor(TS ts, PetscInt step, PetscReal ptime, Vec u)
29 {
30   DM       dm;
31   PetscInt i, n = ts->numbermonitors;
32 
33   PetscFunctionBegin;
34   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
35   PetscValidHeaderSpecific(u, VEC_CLASSID, 4);
36 
37   PetscCall(TSGetDM(ts, &dm));
38   PetscCall(DMSetOutputSequenceNumber(dm, step, ptime));
39 
40   PetscCall(VecLockReadPush(u));
41   for (i = 0; i < n; i++) PetscCall((*ts->monitor[i])(ts, step, ptime, u, ts->monitorcontext[i]));
42   PetscCall(VecLockReadPop(u));
43   PetscFunctionReturn(0);
44 }
45 
46 /*@C
47    TSMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
48 
49    Collective
50 
51    Input Parameters:
52 +  ts - `TS` object you wish to monitor
53 .  name - the monitor type one is seeking
54 .  help - message indicating what monitoring is done
55 .  manual - manual page for the monitor
56 .  monitor - the monitor function
57 -  monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `TS` or `PetscViewer` objects
58 
59    Level: developer
60 
61 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
62           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
63           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
64           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
65           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
66           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
67           `PetscOptionsFList()`, `PetscOptionsEList()`
68 @*/
69 PetscErrorCode TSMonitorSetFromOptions(TS ts, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(TS, PetscInt, PetscReal, Vec, PetscViewerAndFormat *), PetscErrorCode (*monitorsetup)(TS, PetscViewerAndFormat *))
70 {
71   PetscViewer       viewer;
72   PetscViewerFormat format;
73   PetscBool         flg;
74 
75   PetscFunctionBegin;
76   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts), ((PetscObject)ts)->options, ((PetscObject)ts)->prefix, name, &viewer, &format, &flg));
77   if (flg) {
78     PetscViewerAndFormat *vf;
79     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
80     PetscCall(PetscObjectDereference((PetscObject)viewer));
81     if (monitorsetup) PetscCall((*monitorsetup)(ts, vf));
82     PetscCall(TSMonitorSet(ts, (PetscErrorCode(*)(TS, PetscInt, PetscReal, Vec, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
83   }
84   PetscFunctionReturn(0);
85 }
86 
87 /*@C
88    TSMonitorSet - Sets an ADDITIONAL function that is to be used at every
89    timestep to display the iteration's  progress.
90 
91    Logically Collective
92 
93    Input Parameters:
94 +  ts - the `TS` context obtained from `TSCreate()`
95 .  monitor - monitoring routine
96 .  mctx - [optional] user-defined context for private data for the
97              monitor routine (use NULL if no context is desired)
98 -  monitordestroy - [optional] routine that frees monitor context
99           (may be NULL)
100 
101    Calling sequence of monitor:
102 $    PetscErrorCode monitor(TS ts,PetscInt steps,PetscReal time,Vec u,void *mctx)
103 
104 +    ts - the TS context
105 .    steps - iteration number (after the final time step the monitor routine may be called with a step of -1, this indicates the solution has been interpolated to this time)
106 .    time - current time
107 .    u - current iterate
108 -    mctx - [optional] monitoring context
109 
110    Level: intermediate
111 
112    Note:
113    This routine adds an additional monitor to the list of monitors that
114    already has been loaded.
115 
116    Fortran Note:
117     Only a single monitor function can be set for each `TS` object
118 
119 .seealso: [](chapter_ts), `TSMonitorDefault()`, `TSMonitorCancel()`, `TSDMSwarmMonitorMoments()`, `TSMonitorExtreme()`, `TSMonitorDrawSolution()`,
120           `TSMonitorDrawSolutionPhase()`, `TSMonitorDrawSolutionFunction()`, `TSMonitorDrawError()`, `TSMonitorSolution()`, `TSMonitorSolutionVTK()`,
121           `TSMonitorLGSolution()`, `TSMonitorLGError()`, `TSMonitorSPSwarmSolution()`, `TSMonitorError()`, `TSMonitorEnvelope()`, `TSDMSwarmMonitorMoments()`
122 @*/
123 PetscErrorCode TSMonitorSet(TS ts, PetscErrorCode (*monitor)(TS, PetscInt, PetscReal, Vec, void *), void *mctx, PetscErrorCode (*mdestroy)(void **))
124 {
125   PetscInt  i;
126   PetscBool identical;
127 
128   PetscFunctionBegin;
129   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
130   for (i = 0; i < ts->numbermonitors; i++) {
131     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))monitor, mctx, mdestroy, (PetscErrorCode(*)(void))ts->monitor[i], ts->monitorcontext[i], ts->monitordestroy[i], &identical));
132     if (identical) PetscFunctionReturn(0);
133   }
134   PetscCheck(ts->numbermonitors < MAXTSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
135   ts->monitor[ts->numbermonitors]          = monitor;
136   ts->monitordestroy[ts->numbermonitors]   = mdestroy;
137   ts->monitorcontext[ts->numbermonitors++] = (void *)mctx;
138   PetscFunctionReturn(0);
139 }
140 
141 /*@C
142    TSMonitorCancel - Clears all the monitors that have been set on a time-step object.
143 
144    Logically Collective
145 
146    Input Parameters:
147 .  ts - the `TS` context obtained from `TSCreate()`
148 
149    Level: intermediate
150 
151    Note:
152    There is no way to remove a single, specific monitor.
153 
154 .seealso: [](chapter_ts), `TS`, `TSMonitorDefault()`, `TSMonitorSet()`
155 @*/
156 PetscErrorCode TSMonitorCancel(TS ts)
157 {
158   PetscInt i;
159 
160   PetscFunctionBegin;
161   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
162   for (i = 0; i < ts->numbermonitors; i++) {
163     if (ts->monitordestroy[i]) PetscCall((*ts->monitordestroy[i])(&ts->monitorcontext[i]));
164   }
165   ts->numbermonitors = 0;
166   PetscFunctionReturn(0);
167 }
168 
169 /*@C
170    TSMonitorDefault - The Default monitor, prints the timestep and time for each step
171 
172    Options Database Key:
173 .  -ts_monitor - monitors the time integration
174 
175    Level: intermediate
176 
177    Notes:
178    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
179    to be used during the `TS` integration.
180 
181 .seealso: [](chapter_ts), `TSMonitorSet()`, `TSDMSwarmMonitorMoments()`, `TSMonitorExtreme()`, `TSMonitorDrawSolution()`,
182           `TSMonitorDrawSolutionPhase()`, `TSMonitorDrawSolutionFunction()`, `TSMonitorDrawError()`, `TSMonitorSolution()`, `TSMonitorSolutionVTK()`,
183           `TSMonitorLGSolution()`, `TSMonitorLGError()`, `TSMonitorSPSwarmSolution()`, `TSMonitorError()`, `TSMonitorEnvelope()`, `TSDMSwarmMonitorMoments()`
184 @*/
185 PetscErrorCode TSMonitorDefault(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscViewerAndFormat *vf)
186 {
187   PetscViewer viewer = vf->viewer;
188   PetscBool   iascii, ibinary;
189 
190   PetscFunctionBegin;
191   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 5);
192   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
193   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
194   PetscCall(PetscViewerPushFormat(viewer, vf->format));
195   if (iascii) {
196     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
197     if (step == -1) { /* this indicates it is an interpolated solution */
198       PetscCall(PetscViewerASCIIPrintf(viewer, "Interpolated solution at time %g between steps %" PetscInt_FMT " and %" PetscInt_FMT "\n", (double)ptime, ts->steps - 1, ts->steps));
199     } else {
200       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " TS dt %g time %g%s", step, (double)ts->time_step, (double)ptime, ts->steprollback ? " (r)\n" : "\n"));
201     }
202     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
203   } else if (ibinary) {
204     PetscMPIInt rank;
205     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
206     if (rank == 0) {
207       PetscBool skipHeader;
208       PetscInt  classid = REAL_FILE_CLASSID;
209 
210       PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
211       if (!skipHeader) PetscCall(PetscViewerBinaryWrite(viewer, &classid, 1, PETSC_INT));
212       PetscCall(PetscRealView(1, &ptime, viewer));
213     } else {
214       PetscCall(PetscRealView(0, &ptime, viewer));
215     }
216   }
217   PetscCall(PetscViewerPopFormat(viewer));
218   PetscFunctionReturn(0);
219 }
220 
221 /*@C
222    TSMonitorExtreme - Prints the extreme values of the solution at each timestep
223 
224    Level: intermediate
225 
226    Notes:
227    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
228    to be used during the TS integration.
229 
230 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`
231 @*/
232 PetscErrorCode TSMonitorExtreme(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscViewerAndFormat *vf)
233 {
234   PetscViewer viewer = vf->viewer;
235   PetscBool   iascii;
236   PetscReal   max, min;
237 
238   PetscFunctionBegin;
239   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 5);
240   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
241   PetscCall(PetscViewerPushFormat(viewer, vf->format));
242   if (iascii) {
243     PetscCall(VecMax(v, NULL, &max));
244     PetscCall(VecMin(v, NULL, &min));
245     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
246     PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " TS dt %g time %g%s max %g min %g\n", step, (double)ts->time_step, (double)ptime, ts->steprollback ? " (r)" : "", (double)max, (double)min));
247     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
248   }
249   PetscCall(PetscViewerPopFormat(viewer));
250   PetscFunctionReturn(0);
251 }
252 
253 /*@C
254    TSMonitorLGCtxCreate - Creates a `TSMonitorLGCtx` context for use with
255    `TS` to monitor the solution process graphically in various ways
256 
257    Collective
258 
259    Input Parameters:
260 +  host - the X display to open, or null for the local machine
261 .  label - the title to put in the title bar
262 .  x, y - the screen coordinates of the upper left coordinate of the window
263 .  m, n - the screen width and height in pixels
264 -  howoften - if positive then determines the frequency of the plotting, if -1 then only at the final time
265 
266    Output Parameter:
267 .  ctx - the context
268 
269    Options Database Keys:
270 +  -ts_monitor_lg_timestep - automatically sets line graph monitor
271 +  -ts_monitor_lg_timestep_log - automatically sets line graph monitor
272 .  -ts_monitor_lg_solution - monitor the solution (or certain values of the solution by calling `TSMonitorLGSetDisplayVariables()` or `TSMonitorLGCtxSetDisplayVariables()`)
273 .  -ts_monitor_lg_error -  monitor the error
274 .  -ts_monitor_lg_ksp_iterations - monitor the number of `KSP` iterations needed for each timestep
275 .  -ts_monitor_lg_snes_iterations - monitor the number of `SNES` iterations needed for each timestep
276 -  -lg_use_markers <true,false> - mark the data points (at each time step) on the plot; default is true
277 
278    Level: intermediate
279 
280    Notes:
281    Pass the context and `TSMonitorLGCtxDestroy()` to `TSMonitorSet()` to have the context destroyed when no longer needed.
282 
283    One can provide a function that transforms the solution before plotting it with `TSMonitorLGCtxSetTransform()` or `TSMonitorLGSetTransform()`
284 
285    Many of the functions that control the monitoring have two forms: TSMonitorLGSet/GetXXXX() and TSMonitorLGCtxSet/GetXXXX() the first take a `TS` object as the
286    first argument (if that `TS` object does not have a `TSMonitorLGCtx` associated with it the function call is ignored) and the second takes a `TSMonitorLGCtx` object
287    as the first argument.
288 
289    One can control the names displayed for each solution or error variable with `TSMonitorLGCtxSetVariableNames()` or `TSMonitorLGSetVariableNames()`
290 
291 .seealso: [](chapter_ts), `TSMonitorLGTimeStep()`, `TSMonitorSet()`, `TSMonitorLGSolution()`, `TSMonitorLGError()`, `TSMonitorDefault()`, `VecView()`,
292           `TSMonitorLGCtxCreate()`, `TSMonitorLGCtxSetVariableNames()`, `TSMonitorLGCtxGetVariableNames()`,
293           `TSMonitorLGSetVariableNames()`, `TSMonitorLGGetVariableNames()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGCtxSetDisplayVariables()`,
294           `TSMonitorLGCtxSetTransform()`, `TSMonitorLGSetTransform()`, `TSMonitorLGError()`, `TSMonitorLGSNESIterations()`, `TSMonitorLGKSPIterations()`,
295           `TSMonitorEnvelopeCtxCreate()`, `TSMonitorEnvelopeGetBounds()`, `TSMonitorEnvelopeCtxDestroy()`, `TSMonitorEnvelop()`
296 @*/
297 PetscErrorCode TSMonitorLGCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, TSMonitorLGCtx *ctx)
298 {
299   PetscDraw draw;
300 
301   PetscFunctionBegin;
302   PetscCall(PetscNew(ctx));
303   PetscCall(PetscDrawCreate(comm, host, label, x, y, m, n, &draw));
304   PetscCall(PetscDrawSetFromOptions(draw));
305   PetscCall(PetscDrawLGCreate(draw, 1, &(*ctx)->lg));
306   PetscCall(PetscDrawLGSetFromOptions((*ctx)->lg));
307   PetscCall(PetscDrawDestroy(&draw));
308   (*ctx)->howoften = howoften;
309   PetscFunctionReturn(0);
310 }
311 
312 PetscErrorCode TSMonitorLGTimeStep(TS ts, PetscInt step, PetscReal ptime, Vec v, void *monctx)
313 {
314   TSMonitorLGCtx ctx = (TSMonitorLGCtx)monctx;
315   PetscReal      x   = ptime, y;
316 
317   PetscFunctionBegin;
318   if (step < 0) PetscFunctionReturn(0); /* -1 indicates an interpolated solution */
319   if (!step) {
320     PetscDrawAxis axis;
321     const char   *ylabel = ctx->semilogy ? "Log Time Step" : "Time Step";
322     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
323     PetscCall(PetscDrawAxisSetLabels(axis, "Timestep as function of time", "Time", ylabel));
324     PetscCall(PetscDrawLGReset(ctx->lg));
325   }
326   PetscCall(TSGetTimeStep(ts, &y));
327   if (ctx->semilogy) y = PetscLog10Real(y);
328   PetscCall(PetscDrawLGAddPoint(ctx->lg, &x, &y));
329   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
330     PetscCall(PetscDrawLGDraw(ctx->lg));
331     PetscCall(PetscDrawLGSave(ctx->lg));
332   }
333   PetscFunctionReturn(0);
334 }
335 
336 /*@C
337    TSMonitorLGCtxDestroy - Destroys a line graph context that was created
338    with `TSMonitorLGCtxCreate()`.
339 
340    Collective
341 
342    Input Parameter:
343 .  ctx - the monitor context
344 
345    Level: intermediate
346 
347    Note:
348    Pass to `TSMonitorSet()` along with the context and `TSMonitorLGTimeStep()`
349 
350 .seealso: [](chapter_ts), `TS`, `TSMonitorLGCtxCreate()`, `TSMonitorSet()`, `TSMonitorLGTimeStep();`
351 @*/
352 PetscErrorCode TSMonitorLGCtxDestroy(TSMonitorLGCtx *ctx)
353 {
354   PetscFunctionBegin;
355   if ((*ctx)->transformdestroy) PetscCall(((*ctx)->transformdestroy)((*ctx)->transformctx));
356   PetscCall(PetscDrawLGDestroy(&(*ctx)->lg));
357   PetscCall(PetscStrArrayDestroy(&(*ctx)->names));
358   PetscCall(PetscStrArrayDestroy(&(*ctx)->displaynames));
359   PetscCall(PetscFree((*ctx)->displayvariables));
360   PetscCall(PetscFree((*ctx)->displayvalues));
361   PetscCall(PetscFree(*ctx));
362   PetscFunctionReturn(0);
363 }
364 
365 /* Creates a TS Monitor SPCtx for use with DMSwarm particle visualizations */
366 PetscErrorCode TSMonitorSPCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, PetscInt retain, PetscBool phase, TSMonitorSPCtx *ctx)
367 {
368   PetscDraw draw;
369 
370   PetscFunctionBegin;
371   PetscCall(PetscNew(ctx));
372   PetscCall(PetscDrawCreate(comm, host, label, x, y, m, n, &draw));
373   PetscCall(PetscDrawSetFromOptions(draw));
374   PetscCall(PetscDrawSPCreate(draw, 1, &(*ctx)->sp));
375   PetscCall(PetscDrawDestroy(&draw));
376   (*ctx)->howoften = howoften;
377   (*ctx)->retain   = retain;
378   (*ctx)->phase    = phase;
379   PetscFunctionReturn(0);
380 }
381 
382 /*
383   Destroys a TSMonitorSPCtx that was created with TSMonitorSPCtxCreate
384 */
385 PetscErrorCode TSMonitorSPCtxDestroy(TSMonitorSPCtx *ctx)
386 {
387   PetscFunctionBegin;
388 
389   PetscCall(PetscDrawSPDestroy(&(*ctx)->sp));
390   PetscCall(PetscFree(*ctx));
391 
392   PetscFunctionReturn(0);
393 }
394 
395 /*@C
396    TSMonitorDrawSolution - Monitors progress of the `TS` solvers by calling
397    `VecView()` for the solution at each timestep
398 
399    Collective
400 
401    Input Parameters:
402 +  ts - the `TS` context
403 .  step - current time-step
404 .  ptime - current time
405 -  dummy - either a viewer or NULL
406 
407    Options Database Keys:
408 +   -ts_monitor_draw_solution - draw the solution at each time-step
409 -   -ts_monitor_draw_solution_initial - show initial solution as well as current solution
410 
411    Level: intermediate
412 
413    Notes:
414    The initial solution and current solution are not displayed with a common axis scaling so generally the option -ts_monitor_draw_solution_initial
415    will look bad
416 
417    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, as well as the context created with
418    `TSMonitorDrawCtxCreate()` and the function `TSMonitorDrawCtxDestroy()` to cause the monitor to be used during the `TS` integration.
419 
420 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorDrawCtxCreate()`, `TSMonitorDrawCtxDestroy()`
421 @*/
422 PetscErrorCode TSMonitorDrawSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dummy)
423 {
424   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
425   PetscDraw        draw;
426 
427   PetscFunctionBegin;
428   if (!step && ictx->showinitial) {
429     if (!ictx->initialsolution) PetscCall(VecDuplicate(u, &ictx->initialsolution));
430     PetscCall(VecCopy(u, ictx->initialsolution));
431   }
432   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
433 
434   if (ictx->showinitial) {
435     PetscReal pause;
436     PetscCall(PetscViewerDrawGetPause(ictx->viewer, &pause));
437     PetscCall(PetscViewerDrawSetPause(ictx->viewer, 0.0));
438     PetscCall(VecView(ictx->initialsolution, ictx->viewer));
439     PetscCall(PetscViewerDrawSetPause(ictx->viewer, pause));
440     PetscCall(PetscViewerDrawSetHold(ictx->viewer, PETSC_TRUE));
441   }
442   PetscCall(VecView(u, ictx->viewer));
443   if (ictx->showtimestepandtime) {
444     PetscReal xl, yl, xr, yr, h;
445     char      time[32];
446 
447     PetscCall(PetscViewerDrawGetDraw(ictx->viewer, 0, &draw));
448     PetscCall(PetscSNPrintf(time, 32, "Timestep %d Time %g", (int)step, (double)ptime));
449     PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr));
450     h = yl + .95 * (yr - yl);
451     PetscCall(PetscDrawStringCentered(draw, .5 * (xl + xr), h, PETSC_DRAW_BLACK, time));
452     PetscCall(PetscDrawFlush(draw));
453   }
454 
455   if (ictx->showinitial) PetscCall(PetscViewerDrawSetHold(ictx->viewer, PETSC_FALSE));
456   PetscFunctionReturn(0);
457 }
458 
459 /*@C
460    TSMonitorDrawSolutionPhase - Monitors progress of the `TS` solvers by plotting the solution as a phase diagram
461 
462    Collective
463 
464    Input Parameters:
465 +  ts - the `TS` context
466 .  step - current time-step
467 .  ptime - current time
468 -  dummy - either a viewer or NULL
469 
470    Level: intermediate
471 
472    Notes:
473    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
474    to be used during the `TS` integration.
475 
476 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`
477 @*/
478 PetscErrorCode TSMonitorDrawSolutionPhase(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dummy)
479 {
480   TSMonitorDrawCtx   ictx = (TSMonitorDrawCtx)dummy;
481   PetscDraw          draw;
482   PetscDrawAxis      axis;
483   PetscInt           n;
484   PetscMPIInt        size;
485   PetscReal          U0, U1, xl, yl, xr, yr, h;
486   char               time[32];
487   const PetscScalar *U;
488 
489   PetscFunctionBegin;
490   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)ts), &size));
491   PetscCheck(size == 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Only allowed for sequential runs");
492   PetscCall(VecGetSize(u, &n));
493   PetscCheck(n == 2, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Only for ODEs with two unknowns");
494 
495   PetscCall(PetscViewerDrawGetDraw(ictx->viewer, 0, &draw));
496   PetscCall(PetscViewerDrawGetDrawAxis(ictx->viewer, 0, &axis));
497   PetscCall(PetscDrawAxisGetLimits(axis, &xl, &xr, &yl, &yr));
498   if (!step) {
499     PetscCall(PetscDrawClear(draw));
500     PetscCall(PetscDrawAxisDraw(axis));
501   }
502 
503   PetscCall(VecGetArrayRead(u, &U));
504   U0 = PetscRealPart(U[0]);
505   U1 = PetscRealPart(U[1]);
506   PetscCall(VecRestoreArrayRead(u, &U));
507   if ((U0 < xl) || (U1 < yl) || (U0 > xr) || (U1 > yr)) PetscFunctionReturn(0);
508 
509   PetscDrawCollectiveBegin(draw);
510   PetscCall(PetscDrawPoint(draw, U0, U1, PETSC_DRAW_BLACK));
511   if (ictx->showtimestepandtime) {
512     PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr));
513     PetscCall(PetscSNPrintf(time, 32, "Timestep %d Time %g", (int)step, (double)ptime));
514     h = yl + .95 * (yr - yl);
515     PetscCall(PetscDrawStringCentered(draw, .5 * (xl + xr), h, PETSC_DRAW_BLACK, time));
516   }
517   PetscDrawCollectiveEnd(draw);
518   PetscCall(PetscDrawFlush(draw));
519   PetscCall(PetscDrawPause(draw));
520   PetscCall(PetscDrawSave(draw));
521   PetscFunctionReturn(0);
522 }
523 
524 /*@C
525    TSMonitorDrawCtxDestroy - Destroys the monitor context for `TSMonitorDrawSolution()`
526 
527    Collective
528 
529    Input Parameters:
530 .    ctx - the monitor context
531 
532    Level: intermediate
533 
534 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorDrawSolution()`, `TSMonitorDrawError()`, `TSMonitorDrawCtx`
535 @*/
536 PetscErrorCode TSMonitorDrawCtxDestroy(TSMonitorDrawCtx *ictx)
537 {
538   PetscFunctionBegin;
539   PetscCall(PetscViewerDestroy(&(*ictx)->viewer));
540   PetscCall(VecDestroy(&(*ictx)->initialsolution));
541   PetscCall(PetscFree(*ictx));
542   PetscFunctionReturn(0);
543 }
544 
545 /*@C
546    TSMonitorDrawCtxCreate - Creates the monitor context for `TSMonitorDrawCtx`
547 
548    Collective
549 
550    Input Parameter:
551 .    ts - time-step context
552 
553    Output Parameter:
554 .    ctx - the monitor context
555 
556    Options Database Keys:
557 +   -ts_monitor_draw_solution - draw the solution at each time-step
558 -   -ts_monitor_draw_solution_initial - show initial solution as well as current solution
559 
560    Level: intermediate
561 
562    Note:
563    The context created by this function,  `PetscMonitorDrawSolution()`, and `TSMonitorDrawCtxDestroy()` should be passed together to `TSMonitorSet()`.
564 
565 .seealso: [](chapter_ts), `TS`, `TSMonitorDrawCtxDestroy()`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorDrawCtx`, `PetscMonitorDrawSolution()`
566 @*/
567 PetscErrorCode TSMonitorDrawCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, TSMonitorDrawCtx *ctx)
568 {
569   PetscFunctionBegin;
570   PetscCall(PetscNew(ctx));
571   PetscCall(PetscViewerDrawOpen(comm, host, label, x, y, m, n, &(*ctx)->viewer));
572   PetscCall(PetscViewerSetFromOptions((*ctx)->viewer));
573 
574   (*ctx)->howoften    = howoften;
575   (*ctx)->showinitial = PETSC_FALSE;
576   PetscCall(PetscOptionsGetBool(NULL, NULL, "-ts_monitor_draw_solution_initial", &(*ctx)->showinitial, NULL));
577 
578   (*ctx)->showtimestepandtime = PETSC_FALSE;
579   PetscCall(PetscOptionsGetBool(NULL, NULL, "-ts_monitor_draw_solution_show_time", &(*ctx)->showtimestepandtime, NULL));
580   PetscFunctionReturn(0);
581 }
582 
583 /*@C
584    TSMonitorDrawSolutionFunction - Monitors progress of the `TS` solvers by calling
585    `VecView()` for the solution provided by `TSSetSolutionFunction()` at each timestep
586 
587    Collective
588 
589    Input Parameters:
590 +  ts - the `TS` context
591 .  step - current time-step
592 .  ptime - current time
593 -  dummy - either a viewer or NULL
594 
595    Options Database Key:
596 .  -ts_monitor_draw_solution_function - Monitor error graphically, requires user to have provided `TSSetSolutionFunction()`
597 
598    Level: intermediate
599 
600    Note:
601    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
602    to be used during the `TS` integration.
603 
604 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
605 @*/
606 PetscErrorCode TSMonitorDrawSolutionFunction(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dummy)
607 {
608   TSMonitorDrawCtx ctx    = (TSMonitorDrawCtx)dummy;
609   PetscViewer      viewer = ctx->viewer;
610   Vec              work;
611 
612   PetscFunctionBegin;
613   if (!(((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
614   PetscCall(VecDuplicate(u, &work));
615   PetscCall(TSComputeSolutionFunction(ts, ptime, work));
616   PetscCall(VecView(work, viewer));
617   PetscCall(VecDestroy(&work));
618   PetscFunctionReturn(0);
619 }
620 
621 /*@C
622    TSMonitorDrawError - Monitors progress of the `TS` solvers by calling
623    `VecView()` for the error at each timestep
624 
625    Collective
626 
627    Input Parameters:
628 +  ts - the `TS` context
629 .  step - current time-step
630 .  ptime - current time
631 -  dummy - either a viewer or NULL
632 
633    Options Database Key:
634 .  -ts_monitor_draw_error - Monitor error graphically, requires user to have provided `TSSetSolutionFunction()`
635 
636    Level: intermediate
637 
638    Notes:
639    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
640    to be used during the `TS` integration.
641 
642 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
643 @*/
644 PetscErrorCode TSMonitorDrawError(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dummy)
645 {
646   TSMonitorDrawCtx ctx    = (TSMonitorDrawCtx)dummy;
647   PetscViewer      viewer = ctx->viewer;
648   Vec              work;
649 
650   PetscFunctionBegin;
651   if (!(((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason))) PetscFunctionReturn(0);
652   PetscCall(VecDuplicate(u, &work));
653   PetscCall(TSComputeSolutionFunction(ts, ptime, work));
654   PetscCall(VecAXPY(work, -1.0, u));
655   PetscCall(VecView(work, viewer));
656   PetscCall(VecDestroy(&work));
657   PetscFunctionReturn(0);
658 }
659 
660 /*@C
661    TSMonitorSolution - Monitors progress of the TS solvers by `VecView()` for the solution at each timestep. Normally the viewer is a binary file or a `PetscDraw` object
662 
663    Collective
664 
665    Input Parameters:
666 +  ts - the `TS` context
667 .  step - current time-step
668 .  ptime - current time
669 .  u - current state
670 -  vf - viewer and its format
671 
672    Level: intermediate
673 
674    Notes:
675    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
676    to be used during the `TS` integration.
677 
678 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`
679 @*/
680 PetscErrorCode TSMonitorSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscViewerAndFormat *vf)
681 {
682   PetscFunctionBegin;
683   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
684   PetscCall(VecView(u, vf->viewer));
685   PetscCall(PetscViewerPopFormat(vf->viewer));
686   PetscFunctionReturn(0);
687 }
688 
689 /*@C
690    TSMonitorSolutionVTK - Monitors progress of the `TS` solvers by `VecView()` for the solution at each timestep.
691 
692    Collective
693 
694    Input Parameters:
695 +  ts - the `TS` context
696 .  step - current time-step
697 .  ptime - current time
698 .  u - current state
699 -  filenametemplate - string containing a format specifier for the integer time step (e.g. %03" PetscInt_FMT ")
700 
701    Level: intermediate
702 
703    Notes:
704    The VTK format does not allow writing multiple time steps in the same file, therefore a different file will be written for each time step.
705    These are named according to the file name template.
706 
707    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
708    to be used during the `TS` integration.
709 
710 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`
711 @*/
712 PetscErrorCode TSMonitorSolutionVTK(TS ts, PetscInt step, PetscReal ptime, Vec u, void *filenametemplate)
713 {
714   char        filename[PETSC_MAX_PATH_LEN];
715   PetscViewer viewer;
716 
717   PetscFunctionBegin;
718   if (step < 0) PetscFunctionReturn(0); /* -1 indicates interpolated solution */
719   PetscCall(PetscSNPrintf(filename, sizeof(filename), (const char *)filenametemplate, step));
720   PetscCall(PetscViewerVTKOpen(PetscObjectComm((PetscObject)ts), filename, FILE_MODE_WRITE, &viewer));
721   PetscCall(VecView(u, viewer));
722   PetscCall(PetscViewerDestroy(&viewer));
723   PetscFunctionReturn(0);
724 }
725 
726 /*@C
727    TSMonitorSolutionVTKDestroy - Destroy filename template string created for use with `TSMonitorSolutionVTK()`
728 
729    Not Collective
730 
731    Input Parameters:
732 .  filenametemplate - string containing a format specifier for the integer time step (e.g. %03" PetscInt_FMT ")
733 
734    Level: intermediate
735 
736    Note:
737    This function is normally passed to `TSMonitorSet()` along with `TSMonitorSolutionVTK()`.
738 
739 .seealso: [](chapter_ts), `TSMonitorSet()`, `TSMonitorSolutionVTK()`
740 @*/
741 PetscErrorCode TSMonitorSolutionVTKDestroy(void *filenametemplate)
742 {
743   PetscFunctionBegin;
744   PetscCall(PetscFree(*(char **)filenametemplate));
745   PetscFunctionReturn(0);
746 }
747 
748 /*@C
749    TSMonitorLGSolution - Monitors progress of the `TS` solvers by plotting each component of the solution vector
750        in a time based line graph
751 
752    Collective
753 
754    Input Parameters:
755 +  ts - the `TS` context
756 .  step - current time-step
757 .  ptime - current time
758 .  u - current solution
759 -  dctx - the `TSMonitorLGCtx` object that contains all the options for the monitoring, this is created with `TSMonitorLGCtxCreate()`
760 
761    Options Database Key:
762 .   -ts_monitor_lg_solution_variables - enable monitor of lg solution variables
763 
764    Level: intermediate
765 
766    Notes:
767    Each process in a parallel run displays its component solutions in a separate window
768 
769    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
770    to be used during the `TS` integration.
771 
772 .seealso: [](chapter_ts), `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGCtxCreate()`, `TSMonitorLGCtxSetVariableNames()`, `TSMonitorLGCtxGetVariableNames()`,
773           `TSMonitorLGSetVariableNames()`, `TSMonitorLGGetVariableNames()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGCtxSetDisplayVariables()`,
774           `TSMonitorLGCtxSetTransform()`, `TSMonitorLGSetTransform()`, `TSMonitorLGError()`, `TSMonitorLGSNESIterations()`, `TSMonitorLGKSPIterations()`,
775           `TSMonitorEnvelopeCtxCreate()`, `TSMonitorEnvelopeGetBounds()`, `TSMonitorEnvelopeCtxDestroy()`, `TSMonitorEnvelop()`
776 @*/
777 PetscErrorCode TSMonitorLGSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dctx)
778 {
779   TSMonitorLGCtx     ctx = (TSMonitorLGCtx)dctx;
780   const PetscScalar *yy;
781   Vec                v;
782 
783   PetscFunctionBegin;
784   if (step < 0) PetscFunctionReturn(0); /* -1 indicates interpolated solution */
785   if (!step) {
786     PetscDrawAxis axis;
787     PetscInt      dim;
788     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
789     PetscCall(PetscDrawAxisSetLabels(axis, "Solution as function of time", "Time", "Solution"));
790     if (!ctx->names) {
791       PetscBool flg;
792       /* user provides names of variables to plot but no names has been set so assume names are integer values */
793       PetscCall(PetscOptionsHasName(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_monitor_lg_solution_variables", &flg));
794       if (flg) {
795         PetscInt i, n;
796         char   **names;
797         PetscCall(VecGetSize(u, &n));
798         PetscCall(PetscMalloc1(n + 1, &names));
799         for (i = 0; i < n; i++) {
800           PetscCall(PetscMalloc1(5, &names[i]));
801           PetscCall(PetscSNPrintf(names[i], 5, "%" PetscInt_FMT, i));
802         }
803         names[n]   = NULL;
804         ctx->names = names;
805       }
806     }
807     if (ctx->names && !ctx->displaynames) {
808       char    **displaynames;
809       PetscBool flg;
810       PetscCall(VecGetLocalSize(u, &dim));
811       PetscCall(PetscCalloc1(dim + 1, &displaynames));
812       PetscCall(PetscOptionsGetStringArray(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_monitor_lg_solution_variables", displaynames, &dim, &flg));
813       if (flg) PetscCall(TSMonitorLGCtxSetDisplayVariables(ctx, (const char *const *)displaynames));
814       PetscCall(PetscStrArrayDestroy(&displaynames));
815     }
816     if (ctx->displaynames) {
817       PetscCall(PetscDrawLGSetDimension(ctx->lg, ctx->ndisplayvariables));
818       PetscCall(PetscDrawLGSetLegend(ctx->lg, (const char *const *)ctx->displaynames));
819     } else if (ctx->names) {
820       PetscCall(VecGetLocalSize(u, &dim));
821       PetscCall(PetscDrawLGSetDimension(ctx->lg, dim));
822       PetscCall(PetscDrawLGSetLegend(ctx->lg, (const char *const *)ctx->names));
823     } else {
824       PetscCall(VecGetLocalSize(u, &dim));
825       PetscCall(PetscDrawLGSetDimension(ctx->lg, dim));
826     }
827     PetscCall(PetscDrawLGReset(ctx->lg));
828   }
829 
830   if (!ctx->transform) v = u;
831   else PetscCall((*ctx->transform)(ctx->transformctx, u, &v));
832   PetscCall(VecGetArrayRead(v, &yy));
833   if (ctx->displaynames) {
834     PetscInt i;
835     for (i = 0; i < ctx->ndisplayvariables; i++) ctx->displayvalues[i] = PetscRealPart(yy[ctx->displayvariables[i]]);
836     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, ctx->displayvalues));
837   } else {
838 #if defined(PETSC_USE_COMPLEX)
839     PetscInt   i, n;
840     PetscReal *yreal;
841     PetscCall(VecGetLocalSize(v, &n));
842     PetscCall(PetscMalloc1(n, &yreal));
843     for (i = 0; i < n; i++) yreal[i] = PetscRealPart(yy[i]);
844     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yreal));
845     PetscCall(PetscFree(yreal));
846 #else
847     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yy));
848 #endif
849   }
850   PetscCall(VecRestoreArrayRead(v, &yy));
851   if (ctx->transform) PetscCall(VecDestroy(&v));
852 
853   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
854     PetscCall(PetscDrawLGDraw(ctx->lg));
855     PetscCall(PetscDrawLGSave(ctx->lg));
856   }
857   PetscFunctionReturn(0);
858 }
859 
860 /*@C
861    TSMonitorLGSetVariableNames - Sets the name of each component in the solution vector so that it may be displayed in the plot
862 
863    Collective
864 
865    Input Parameters:
866 +  ts - the `TS` context
867 -  names - the names of the components, final string must be NULL
868 
869    Level: intermediate
870 
871    Notes:
872     If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored
873 
874 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGCtxSetVariableNames()`
875 @*/
876 PetscErrorCode TSMonitorLGSetVariableNames(TS ts, const char *const *names)
877 {
878   PetscInt i;
879 
880   PetscFunctionBegin;
881   for (i = 0; i < ts->numbermonitors; i++) {
882     if (ts->monitor[i] == TSMonitorLGSolution) {
883       PetscCall(TSMonitorLGCtxSetVariableNames((TSMonitorLGCtx)ts->monitorcontext[i], names));
884       break;
885     }
886   }
887   PetscFunctionReturn(0);
888 }
889 
890 /*@C
891    TSMonitorLGCtxSetVariableNames - Sets the name of each component in the solution vector so that it may be displayed in the plot
892 
893    Collective
894 
895    Input Parameters:
896 +  ts - the `TS` context
897 -  names - the names of the components, final string must be NULL
898 
899    Level: intermediate
900 
901 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGSetVariableNames()`
902 @*/
903 PetscErrorCode TSMonitorLGCtxSetVariableNames(TSMonitorLGCtx ctx, const char *const *names)
904 {
905   PetscFunctionBegin;
906   PetscCall(PetscStrArrayDestroy(&ctx->names));
907   PetscCall(PetscStrArrayallocpy(names, &ctx->names));
908   PetscFunctionReturn(0);
909 }
910 
911 /*@C
912    TSMonitorLGGetVariableNames - Gets the name of each component in the solution vector so that it may be displayed in the plot
913 
914    Collective
915 
916    Input Parameter:
917 .  ts - the `TS` context
918 
919    Output Parameter:
920 .  names - the names of the components, final string must be NULL
921 
922    Level: intermediate
923 
924    Note:
925     If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored
926 
927 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`
928 @*/
929 PetscErrorCode TSMonitorLGGetVariableNames(TS ts, const char *const **names)
930 {
931   PetscInt i;
932 
933   PetscFunctionBegin;
934   *names = NULL;
935   for (i = 0; i < ts->numbermonitors; i++) {
936     if (ts->monitor[i] == TSMonitorLGSolution) {
937       TSMonitorLGCtx ctx = (TSMonitorLGCtx)ts->monitorcontext[i];
938       *names             = (const char *const *)ctx->names;
939       break;
940     }
941   }
942   PetscFunctionReturn(0);
943 }
944 
945 /*@C
946    TSMonitorLGCtxSetDisplayVariables - Sets the variables that are to be display in the monitor
947 
948    Collective
949 
950    Input Parameters:
951 +  ctx - the `TSMonitorLG` context
952 -  displaynames - the names of the components, final string must be NULL
953 
954    Level: intermediate
955 
956 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`
957 @*/
958 PetscErrorCode TSMonitorLGCtxSetDisplayVariables(TSMonitorLGCtx ctx, const char *const *displaynames)
959 {
960   PetscInt j = 0, k;
961 
962   PetscFunctionBegin;
963   if (!ctx->names) PetscFunctionReturn(0);
964   PetscCall(PetscStrArrayDestroy(&ctx->displaynames));
965   PetscCall(PetscStrArrayallocpy(displaynames, &ctx->displaynames));
966   while (displaynames[j]) j++;
967   ctx->ndisplayvariables = j;
968   PetscCall(PetscMalloc1(ctx->ndisplayvariables, &ctx->displayvariables));
969   PetscCall(PetscMalloc1(ctx->ndisplayvariables, &ctx->displayvalues));
970   j = 0;
971   while (displaynames[j]) {
972     k = 0;
973     while (ctx->names[k]) {
974       PetscBool flg;
975       PetscCall(PetscStrcmp(displaynames[j], ctx->names[k], &flg));
976       if (flg) {
977         ctx->displayvariables[j] = k;
978         break;
979       }
980       k++;
981     }
982     j++;
983   }
984   PetscFunctionReturn(0);
985 }
986 
987 /*@C
988    TSMonitorLGSetDisplayVariables - Sets the variables that are to be display in the monitor
989 
990    Collective
991 
992    Input Parameters:
993 +  ts - the `TS` context
994 -  displaynames - the names of the components, final string must be NULL
995 
996    Level: intermediate
997 
998    Note:
999     If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored
1000 
1001 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`
1002 @*/
1003 PetscErrorCode TSMonitorLGSetDisplayVariables(TS ts, const char *const *displaynames)
1004 {
1005   PetscInt i;
1006 
1007   PetscFunctionBegin;
1008   for (i = 0; i < ts->numbermonitors; i++) {
1009     if (ts->monitor[i] == TSMonitorLGSolution) {
1010       PetscCall(TSMonitorLGCtxSetDisplayVariables((TSMonitorLGCtx)ts->monitorcontext[i], displaynames));
1011       break;
1012     }
1013   }
1014   PetscFunctionReturn(0);
1015 }
1016 
1017 /*@C
1018    TSMonitorLGSetTransform - Solution vector will be transformed by provided function before being displayed
1019 
1020    Collective
1021 
1022    Input Parameters:
1023 +  ts - the `TS` context
1024 .  transform - the transform function
1025 .  destroy - function to destroy the optional context
1026 -  ctx - optional context used by transform function
1027 
1028    Level: intermediate
1029 
1030    Note:
1031     If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored
1032 
1033 .seealso: [](chapter_ts), `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`, `TSMonitorLGCtxSetTransform()`
1034 @*/
1035 PetscErrorCode TSMonitorLGSetTransform(TS ts, PetscErrorCode (*transform)(void *, Vec, Vec *), PetscErrorCode (*destroy)(void *), void *tctx)
1036 {
1037   PetscInt i;
1038 
1039   PetscFunctionBegin;
1040   for (i = 0; i < ts->numbermonitors; i++) {
1041     if (ts->monitor[i] == TSMonitorLGSolution) PetscCall(TSMonitorLGCtxSetTransform((TSMonitorLGCtx)ts->monitorcontext[i], transform, destroy, tctx));
1042   }
1043   PetscFunctionReturn(0);
1044 }
1045 
1046 /*@C
1047    TSMonitorLGCtxSetTransform - Solution vector will be transformed by provided function before being displayed
1048 
1049    Collective
1050 
1051    Input Parameters:
1052 +  ts - the `TS` context
1053 .  transform - the transform function
1054 .  destroy - function to destroy the optional context
1055 -  ctx - optional context used by transform function
1056 
1057    Level: intermediate
1058 
1059 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`, `TSMonitorLGSetTransform()`
1060 @*/
1061 PetscErrorCode TSMonitorLGCtxSetTransform(TSMonitorLGCtx ctx, PetscErrorCode (*transform)(void *, Vec, Vec *), PetscErrorCode (*destroy)(void *), void *tctx)
1062 {
1063   PetscFunctionBegin;
1064   ctx->transform        = transform;
1065   ctx->transformdestroy = destroy;
1066   ctx->transformctx     = tctx;
1067   PetscFunctionReturn(0);
1068 }
1069 
1070 /*@C
1071    TSMonitorLGError - Monitors progress of the `TS` solvers by plotting each component of the error
1072        in a time based line graph
1073 
1074    Collective
1075 
1076    Input Parameters:
1077 +  ts - the `TS` context
1078 .  step - current time-step
1079 .  ptime - current time
1080 .  u - current solution
1081 -  dctx - `TSMonitorLGCtx` object created with `TSMonitorLGCtxCreate()`
1082 
1083    Options Database Key:
1084 .  -ts_monitor_lg_error - create a graphical monitor of error history
1085 
1086    Level: intermediate
1087 
1088    Notes:
1089     Each process in a parallel run displays its component errors in a separate window
1090 
1091    The user must provide the solution using `TSSetSolutionFunction()` to use this monitor.
1092 
1093    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1094    to be used during the TS integration.
1095 
1096 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
1097 @*/
1098 PetscErrorCode TSMonitorLGError(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dummy)
1099 {
1100   TSMonitorLGCtx     ctx = (TSMonitorLGCtx)dummy;
1101   const PetscScalar *yy;
1102   Vec                y;
1103 
1104   PetscFunctionBegin;
1105   if (!step) {
1106     PetscDrawAxis axis;
1107     PetscInt      dim;
1108     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
1109     PetscCall(PetscDrawAxisSetLabels(axis, "Error in solution as function of time", "Time", "Error"));
1110     PetscCall(VecGetLocalSize(u, &dim));
1111     PetscCall(PetscDrawLGSetDimension(ctx->lg, dim));
1112     PetscCall(PetscDrawLGReset(ctx->lg));
1113   }
1114   PetscCall(VecDuplicate(u, &y));
1115   PetscCall(TSComputeSolutionFunction(ts, ptime, y));
1116   PetscCall(VecAXPY(y, -1.0, u));
1117   PetscCall(VecGetArrayRead(y, &yy));
1118 #if defined(PETSC_USE_COMPLEX)
1119   {
1120     PetscReal *yreal;
1121     PetscInt   i, n;
1122     PetscCall(VecGetLocalSize(y, &n));
1123     PetscCall(PetscMalloc1(n, &yreal));
1124     for (i = 0; i < n; i++) yreal[i] = PetscRealPart(yy[i]);
1125     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yreal));
1126     PetscCall(PetscFree(yreal));
1127   }
1128 #else
1129   PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yy));
1130 #endif
1131   PetscCall(VecRestoreArrayRead(y, &yy));
1132   PetscCall(VecDestroy(&y));
1133   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
1134     PetscCall(PetscDrawLGDraw(ctx->lg));
1135     PetscCall(PetscDrawLGSave(ctx->lg));
1136   }
1137   PetscFunctionReturn(0);
1138 }
1139 
1140 /*@C
1141    TSMonitorSPSwarmSolution - Graphically displays phase plots of `DMSWARM` particles on a scatter plot
1142 
1143    Input Parameters:
1144 +  ts - the `TS` context
1145 .  step - current time-step
1146 .  ptime - current time
1147 .  u - current solution
1148 -  dctx - the `TSMonitorSPCtx` object that contains all the options for the monitoring, this is created with `TSMonitorSPCtxCreate()`
1149 
1150    Options Database Keys:
1151 + -ts_monitor_sp_swarm <n>          - Monitor the solution every n steps, or -1 for plotting only the final solution
1152 . -ts_monitor_sp_swarm_retain <n>   - Retain n old points so we can see the history, or -1 for all points
1153 - -ts_monitor_sp_swarm_phase <bool> - Plot in phase space, as opposed to coordinate space
1154 
1155    Level: intermediate
1156 
1157    Notes:
1158    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1159    to be used during the `TS` integration.
1160 
1161 .seealso: [](chapter_ts), `TS`, `TSMonitoSet()`, `DMSWARM`, `TSMonitorSPCtxCreate()`
1162 @*/
1163 PetscErrorCode TSMonitorSPSwarmSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dctx)
1164 {
1165   TSMonitorSPCtx     ctx = (TSMonitorSPCtx)dctx;
1166   PetscDraw          draw;
1167   DM                 dm, cdm;
1168   const PetscScalar *yy;
1169   PetscInt           Np, p, dim = 2;
1170 
1171   PetscFunctionBegin;
1172   if (step < 0) PetscFunctionReturn(0); /* -1 indicates interpolated solution */
1173   if (!step) {
1174     PetscDrawAxis axis;
1175     PetscReal     dmboxlower[2], dmboxupper[2];
1176 
1177     PetscCall(TSGetDM(ts, &dm));
1178     PetscCall(DMGetDimension(dm, &dim));
1179     PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Monitor only supports two dimensional fields");
1180     PetscCall(DMSwarmGetCellDM(dm, &cdm));
1181     PetscCall(DMGetBoundingBox(cdm, dmboxlower, dmboxupper));
1182     PetscCall(VecGetLocalSize(u, &Np));
1183     Np /= dim * 2;
1184     PetscCall(PetscDrawSPGetAxis(ctx->sp, &axis));
1185     if (ctx->phase) {
1186       PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "X", "V"));
1187       PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], -5, 5));
1188     } else {
1189       PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "X", "Y"));
1190       PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], dmboxlower[1], dmboxupper[1]));
1191     }
1192     PetscCall(PetscDrawAxisSetHoldLimits(axis, PETSC_TRUE));
1193     PetscCall(PetscDrawSPReset(ctx->sp));
1194   }
1195   PetscCall(VecGetLocalSize(u, &Np));
1196   Np /= dim * 2;
1197   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
1198     PetscCall(PetscDrawSPGetDraw(ctx->sp, &draw));
1199     if ((ctx->retain == 0) || (ctx->retain > 0 && !(step % ctx->retain))) PetscCall(PetscDrawClear(draw));
1200     PetscCall(PetscDrawFlush(draw));
1201     PetscCall(PetscDrawSPReset(ctx->sp));
1202     PetscCall(VecGetArrayRead(u, &yy));
1203     for (p = 0; p < Np; ++p) {
1204       PetscReal x, y;
1205 
1206       if (ctx->phase) {
1207         x = PetscRealPart(yy[p * dim * 2]);
1208         y = PetscRealPart(yy[p * dim * 2 + dim]);
1209       } else {
1210         x = PetscRealPart(yy[p * dim * 2]);
1211         y = PetscRealPart(yy[p * dim * 2 + 1]);
1212       }
1213       PetscCall(PetscDrawSPAddPoint(ctx->sp, &x, &y));
1214     }
1215     PetscCall(VecRestoreArrayRead(u, &yy));
1216     PetscCall(PetscDrawSPDraw(ctx->sp, PETSC_FALSE));
1217     PetscCall(PetscDrawSPSave(ctx->sp));
1218   }
1219   PetscFunctionReturn(0);
1220 }
1221 
1222 /*@C
1223    TSMonitorError - Monitors progress of the `TS` solvers by printing the 2 norm of the error at each timestep
1224 
1225    Collective
1226 
1227    Input Parameters:
1228 +  ts - the `TS` context
1229 .  step - current time-step
1230 .  ptime - current time
1231 .  u - current solution
1232 -  dctx - unused context
1233 
1234    Options Database Key:
1235 .  -ts_monitor_error - create a graphical monitor of error history
1236 
1237    Level: intermediate
1238 
1239    Notes:
1240    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1241    to be used during the `TS` integration.
1242 
1243    The user must provide the solution using `TSSetSolutionFunction()` to use this monitor.
1244 
1245 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
1246 @*/
1247 PetscErrorCode TSMonitorError(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscViewerAndFormat *vf)
1248 {
1249   DM        dm;
1250   PetscDS   ds = NULL;
1251   PetscInt  Nf = -1, f;
1252   PetscBool flg;
1253 
1254   PetscFunctionBegin;
1255   PetscCall(TSGetDM(ts, &dm));
1256   if (dm) PetscCall(DMGetDS(dm, &ds));
1257   if (ds) PetscCall(PetscDSGetNumFields(ds, &Nf));
1258   if (Nf <= 0) {
1259     Vec       y;
1260     PetscReal nrm;
1261 
1262     PetscCall(VecDuplicate(u, &y));
1263     PetscCall(TSComputeSolutionFunction(ts, ptime, y));
1264     PetscCall(VecAXPY(y, -1.0, u));
1265     PetscCall(PetscObjectTypeCompare((PetscObject)vf->viewer, PETSCVIEWERASCII, &flg));
1266     if (flg) {
1267       PetscCall(VecNorm(y, NORM_2, &nrm));
1268       PetscCall(PetscViewerASCIIPrintf(vf->viewer, "2-norm of error %g\n", (double)nrm));
1269     }
1270     PetscCall(PetscObjectTypeCompare((PetscObject)vf->viewer, PETSCVIEWERDRAW, &flg));
1271     if (flg) PetscCall(VecView(y, vf->viewer));
1272     PetscCall(VecDestroy(&y));
1273   } else {
1274     PetscErrorCode (**exactFuncs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx);
1275     void    **ctxs;
1276     Vec       v;
1277     PetscReal ferrors[1];
1278 
1279     PetscCall(PetscMalloc2(Nf, &exactFuncs, Nf, &ctxs));
1280     for (f = 0; f < Nf; ++f) PetscCall(PetscDSGetExactSolution(ds, f, &exactFuncs[f], &ctxs[f]));
1281     PetscCall(DMComputeL2FieldDiff(dm, ptime, exactFuncs, ctxs, u, ferrors));
1282     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Timestep: %04d time = %-8.4g \t L_2 Error: [", (int)step, (double)ptime));
1283     for (f = 0; f < Nf; ++f) {
1284       if (f > 0) PetscCall(PetscPrintf(PETSC_COMM_WORLD, ", "));
1285       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%2.3g", (double)ferrors[f]));
1286     }
1287     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "]\n"));
1288 
1289     PetscCall(VecViewFromOptions(u, NULL, "-sol_vec_view"));
1290 
1291     PetscCall(PetscOptionsHasName(NULL, NULL, "-exact_vec_view", &flg));
1292     if (flg) {
1293       PetscCall(DMGetGlobalVector(dm, &v));
1294       PetscCall(DMProjectFunction(dm, ptime, exactFuncs, ctxs, INSERT_ALL_VALUES, v));
1295       PetscCall(PetscObjectSetName((PetscObject)v, "Exact Solution"));
1296       PetscCall(VecViewFromOptions(v, NULL, "-exact_vec_view"));
1297       PetscCall(DMRestoreGlobalVector(dm, &v));
1298     }
1299     PetscCall(PetscFree2(exactFuncs, ctxs));
1300   }
1301   PetscFunctionReturn(0);
1302 }
1303 
1304 PetscErrorCode TSMonitorLGSNESIterations(TS ts, PetscInt n, PetscReal ptime, Vec v, void *monctx)
1305 {
1306   TSMonitorLGCtx ctx = (TSMonitorLGCtx)monctx;
1307   PetscReal      x   = ptime, y;
1308   PetscInt       its;
1309 
1310   PetscFunctionBegin;
1311   if (n < 0) PetscFunctionReturn(0); /* -1 indicates interpolated solution */
1312   if (!n) {
1313     PetscDrawAxis axis;
1314     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
1315     PetscCall(PetscDrawAxisSetLabels(axis, "Nonlinear iterations as function of time", "Time", "SNES Iterations"));
1316     PetscCall(PetscDrawLGReset(ctx->lg));
1317     ctx->snes_its = 0;
1318   }
1319   PetscCall(TSGetSNESIterations(ts, &its));
1320   y = its - ctx->snes_its;
1321   PetscCall(PetscDrawLGAddPoint(ctx->lg, &x, &y));
1322   if (((ctx->howoften > 0) && (!(n % ctx->howoften)) && (n > -1)) || ((ctx->howoften == -1) && (n == -1))) {
1323     PetscCall(PetscDrawLGDraw(ctx->lg));
1324     PetscCall(PetscDrawLGSave(ctx->lg));
1325   }
1326   ctx->snes_its = its;
1327   PetscFunctionReturn(0);
1328 }
1329 
1330 PetscErrorCode TSMonitorLGKSPIterations(TS ts, PetscInt n, PetscReal ptime, Vec v, void *monctx)
1331 {
1332   TSMonitorLGCtx ctx = (TSMonitorLGCtx)monctx;
1333   PetscReal      x   = ptime, y;
1334   PetscInt       its;
1335 
1336   PetscFunctionBegin;
1337   if (n < 0) PetscFunctionReturn(0); /* -1 indicates interpolated solution */
1338   if (!n) {
1339     PetscDrawAxis axis;
1340     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
1341     PetscCall(PetscDrawAxisSetLabels(axis, "Linear iterations as function of time", "Time", "KSP Iterations"));
1342     PetscCall(PetscDrawLGReset(ctx->lg));
1343     ctx->ksp_its = 0;
1344   }
1345   PetscCall(TSGetKSPIterations(ts, &its));
1346   y = its - ctx->ksp_its;
1347   PetscCall(PetscDrawLGAddPoint(ctx->lg, &x, &y));
1348   if (((ctx->howoften > 0) && (!(n % ctx->howoften)) && (n > -1)) || ((ctx->howoften == -1) && (n == -1))) {
1349     PetscCall(PetscDrawLGDraw(ctx->lg));
1350     PetscCall(PetscDrawLGSave(ctx->lg));
1351   }
1352   ctx->ksp_its = its;
1353   PetscFunctionReturn(0);
1354 }
1355 
1356 /*@C
1357    TSMonitorEnvelopeCtxCreate - Creates a context for use with `TSMonitorEnvelope()`
1358 
1359    Collective
1360 
1361    Input Parameters:
1362 .  ts  - the `TS` solver object
1363 
1364    Output Parameter:
1365 .  ctx - the context
1366 
1367    Level: intermediate
1368 
1369 .seealso: [](chapter_ts), `TS`, `TSMonitorLGTimeStep()`, `TSMonitorSet()`, `TSMonitorLGSolution()`, `TSMonitorLGError()`
1370 @*/
1371 PetscErrorCode TSMonitorEnvelopeCtxCreate(TS ts, TSMonitorEnvelopeCtx *ctx)
1372 {
1373   PetscFunctionBegin;
1374   PetscCall(PetscNew(ctx));
1375   PetscFunctionReturn(0);
1376 }
1377 
1378 /*@C
1379    TSMonitorEnvelope - Monitors the maximum and minimum value of each component of the solution
1380 
1381    Collective
1382 
1383    Input Parameters:
1384 +  ts - the TS context
1385 .  step - current time-step
1386 .  ptime - current time
1387 .  u  - current solution
1388 -  dctx - the envelope context
1389 
1390    Options Database Key:
1391 .  -ts_monitor_envelope - determine maximum and minimum value of each component of the solution over the solution time
1392 
1393    Level: intermediate
1394 
1395    Notes:
1396    After a solve you can use `TSMonitorEnvelopeGetBounds()` to access the envelope
1397 
1398    This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1399    to be used during the `TS` integration.
1400 
1401 .seealso: [](chapter_ts), `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorEnvelopeGetBounds()`, `TSMonitorEnvelopeCtxCreate()`
1402 @*/
1403 PetscErrorCode TSMonitorEnvelope(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dctx)
1404 {
1405   TSMonitorEnvelopeCtx ctx = (TSMonitorEnvelopeCtx)dctx;
1406 
1407   PetscFunctionBegin;
1408   if (!ctx->max) {
1409     PetscCall(VecDuplicate(u, &ctx->max));
1410     PetscCall(VecDuplicate(u, &ctx->min));
1411     PetscCall(VecCopy(u, ctx->max));
1412     PetscCall(VecCopy(u, ctx->min));
1413   } else {
1414     PetscCall(VecPointwiseMax(ctx->max, u, ctx->max));
1415     PetscCall(VecPointwiseMin(ctx->min, u, ctx->min));
1416   }
1417   PetscFunctionReturn(0);
1418 }
1419 
1420 /*@C
1421    TSMonitorEnvelopeGetBounds - Gets the bounds for the components of the solution
1422 
1423    Collective
1424 
1425    Input Parameter:
1426 .  ts - the `TS` context
1427 
1428    Output Parameters:
1429 +  max - the maximum values
1430 -  min - the minimum values
1431 
1432    Notes:
1433     If the `TS` does not have a `TSMonitorEnvelopeCtx` associated with it then this function is ignored
1434 
1435    Level: intermediate
1436 
1437 .seealso: [](chapter_ts), `TSMonitorEnvelopeCtx`, `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`
1438 @*/
1439 PetscErrorCode TSMonitorEnvelopeGetBounds(TS ts, Vec *max, Vec *min)
1440 {
1441   PetscInt i;
1442 
1443   PetscFunctionBegin;
1444   if (max) *max = NULL;
1445   if (min) *min = NULL;
1446   for (i = 0; i < ts->numbermonitors; i++) {
1447     if (ts->monitor[i] == TSMonitorEnvelope) {
1448       TSMonitorEnvelopeCtx ctx = (TSMonitorEnvelopeCtx)ts->monitorcontext[i];
1449       if (max) *max = ctx->max;
1450       if (min) *min = ctx->min;
1451       break;
1452     }
1453   }
1454   PetscFunctionReturn(0);
1455 }
1456 
1457 /*@C
1458    TSMonitorEnvelopeCtxDestroy - Destroys a context that was created  with `TSMonitorEnvelopeCtxCreate()`.
1459 
1460    Collective
1461 
1462    Input Parameter:
1463 .  ctx - the monitor context
1464 
1465    Level: intermediate
1466 
1467 .seealso: [](chapter_ts), `TS`, `TSMonitorLGCtxCreate()`, `TSMonitorSet()`, `TSMonitorLGTimeStep()`
1468 @*/
1469 PetscErrorCode TSMonitorEnvelopeCtxDestroy(TSMonitorEnvelopeCtx *ctx)
1470 {
1471   PetscFunctionBegin;
1472   PetscCall(VecDestroy(&(*ctx)->min));
1473   PetscCall(VecDestroy(&(*ctx)->max));
1474   PetscCall(PetscFree(*ctx));
1475   PetscFunctionReturn(0);
1476 }
1477 
1478 /*@C
1479   TSDMSwarmMonitorMoments - Monitors the first three moments of a `DMSWARM` being evolved by the `TS`
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + ts   - the `TS` context
1485 . step - current timestep
1486 . t    - current time
1487 . u    - current solution
1488 - ctx  - not used
1489 
1490   Options Database Key:
1491 . -ts_dmswarm_monitor_moments - Monitor moments of particle distribution
1492 
1493   Level: intermediate
1494 
1495   Notes:
1496   This requires a `DMSWARM` be attached to the `TS`.
1497 
1498   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1499   to be used during the TS integration.
1500 
1501 .seealso: [](chapter_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `DMSWARM`
1502 @*/
1503 PetscErrorCode TSDMSwarmMonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, PetscViewerAndFormat *vf)
1504 {
1505   DM                 sw;
1506   const PetscScalar *u;
1507   PetscReal          m = 1.0, totE = 0., totMom[3] = {0., 0., 0.};
1508   PetscInt           dim, d, Np, p;
1509   MPI_Comm           comm;
1510 
1511   PetscFunctionBeginUser;
1512   PetscCall(TSGetDM(ts, &sw));
1513   if (!sw || step % ts->monitorFrequency != 0) PetscFunctionReturn(0);
1514   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
1515   PetscCall(DMGetDimension(sw, &dim));
1516   PetscCall(VecGetLocalSize(U, &Np));
1517   Np /= dim;
1518   PetscCall(VecGetArrayRead(U, &u));
1519   for (p = 0; p < Np; ++p) {
1520     for (d = 0; d < dim; ++d) {
1521       totE += PetscRealPart(u[p * dim + d] * u[p * dim + d]);
1522       totMom[d] += PetscRealPart(u[p * dim + d]);
1523     }
1524   }
1525   PetscCall(VecRestoreArrayRead(U, &u));
1526   for (d = 0; d < dim; ++d) totMom[d] *= m;
1527   totE *= 0.5 * m;
1528   PetscCall(PetscPrintf(comm, "Step %4" PetscInt_FMT " Total Energy: %10.8lf", step, (double)totE));
1529   for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(comm, "    Total Momentum %c: %10.8lf", (char)('x' + d), (double)totMom[d]));
1530   PetscCall(PetscPrintf(comm, "\n"));
1531   PetscFunctionReturn(0);
1532 }
1533