Actual source code: tsmon.c

  1: #include <petsc/private/tsimpl.h>
  2: #include <petscdm.h>
  3: #include <petscds.h>
  4: #include <petscdmswarm.h>
  5: #include <petscdraw.h>

  7: /*@C
  8:   TSMonitor - Runs all user-provided monitor routines set using `TSMonitorSet()`

 10:   Collective

 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

 18:   Level: developer

 20:   Notes:
 21:   `TSMonitor()` is typically used automatically within the time stepping implementations.
 22:   Users would almost never call this routine directly.

 24:   A step of -1 indicates that the monitor is being called on a solution obtained by interpolating from computed solutions

 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;

 33:   PetscFunctionBegin;

 37:   PetscCall(TSGetDM(ts, &dm));
 38:   PetscCall(DMSetOutputSequenceNumber(dm, step, ptime));

 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(PETSC_SUCCESS);
 44: }

 46: /*@C
 47:   TSMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

 49:   Collective

 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, this must use a `PetscViewerFormat` as its context
 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

 59:   Calling sequence of `monitor`:
 60: + ts   - the `TS` to monitor
 61: . step - the current time-step
 62: . time - the current time
 63: . u    - the current solution
 64: - vf   - the `PetscViewer` and format to monitor with

 66:   Calling sequence of `monitorsetup`:
 67: + ts - the `TS` to monitor
 68: - vf - the `PetscViewer` and format to monitor with

 70:   Level: developer

 72: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
 73:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
 74:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
 75:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
 76:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
 77:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
 78:           `PetscOptionsFList()`, `PetscOptionsEList()`
 79: @*/
 80: PetscErrorCode TSMonitorSetFromOptions(TS ts, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(TS ts, PetscInt step, PetscReal time, Vec u, PetscViewerAndFormat *vf), PetscErrorCode (*monitorsetup)(TS ts, PetscViewerAndFormat *vf))
 81: {
 82:   PetscViewer       viewer;
 83:   PetscViewerFormat format;
 84:   PetscBool         flg;

 86:   PetscFunctionBegin;
 87:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)ts), ((PetscObject)ts)->options, ((PetscObject)ts)->prefix, name, &viewer, &format, &flg));
 88:   if (flg) {
 89:     PetscViewerAndFormat *vf;
 90:     char                  interval_key[1024];

 92:     PetscCall(PetscSNPrintf(interval_key, sizeof interval_key, "%s_interval", name));
 93:     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
 94:     vf->view_interval = 1;
 95:     PetscCall(PetscOptionsGetInt(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, interval_key, &vf->view_interval, NULL));

 97:     PetscCall(PetscViewerDestroy(&viewer));
 98:     if (monitorsetup) PetscCall((*monitorsetup)(ts, vf));
 99:     PetscCall(TSMonitorSet(ts, (PetscErrorCode (*)(TS, PetscInt, PetscReal, Vec, PetscCtx))monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
100:   }
101:   PetscFunctionReturn(PETSC_SUCCESS);
102: }

104: /*@C
105:   TSMonitorSet - Sets an ADDITIONAL function that is to be used at every
106:   timestep to display the iteration's  progress.

108:   Logically Collective

110:   Input Parameters:
111: + ts       - the `TS` context obtained from `TSCreate()`
112: . monitor  - monitoring routine
113: . mctx     - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
114: - mdestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence

116:   Calling sequence of `monitor`:
117: + ts    - the `TS` context
118: . 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)
119: . time  - current time
120: . u     - current iterate
121: - ctx   - [optional] monitoring context

123:   Level: intermediate

125:   Note:
126:   This routine adds an additional monitor to the list of monitors that already has been loaded.

128:   Fortran Notes:
129:   Only a single monitor function can be set for each `TS` object

131: .seealso: [](ch_ts), `TSMonitorDefault()`, `TSMonitorCancel()`, `TSDMSwarmMonitorMoments()`, `TSMonitorExtreme()`, `TSMonitorDrawSolution()`,
132:           `TSMonitorDrawSolutionPhase()`, `TSMonitorDrawSolutionFunction()`, `TSMonitorDrawError()`, `TSMonitorSolution()`, `TSMonitorSolutionVTK()`,
133:           `TSMonitorLGSolution()`, `TSMonitorLGError()`, `TSMonitorSPSwarmSolution()`, `TSMonitorError()`, `TSMonitorEnvelope()`, `PetscCtxDestroyFn`
134: @*/
135: PetscErrorCode TSMonitorSet(TS ts, PetscErrorCode (*monitor)(TS ts, PetscInt steps, PetscReal time, Vec u, PetscCtx ctx), PetscCtx mctx, PetscCtxDestroyFn *mdestroy)
136: {
137:   PetscFunctionBegin;
139:   for (PetscInt i = 0; i < ts->numbermonitors; i++) {
140:     PetscBool identical;

142:     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))(PetscVoidFn *)monitor, mctx, mdestroy, (PetscErrorCode (*)(void))(PetscVoidFn *)ts->monitor[i], ts->monitorcontext[i], ts->monitordestroy[i], &identical));
143:     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
144:   }
145:   PetscCheck(ts->numbermonitors < MAXTSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
146:   ts->monitor[ts->numbermonitors]          = monitor;
147:   ts->monitordestroy[ts->numbermonitors]   = mdestroy;
148:   ts->monitorcontext[ts->numbermonitors++] = mctx;
149:   PetscFunctionReturn(PETSC_SUCCESS);
150: }

152: /*@C
153:   TSMonitorCancel - Clears all the monitors that have been set on a time-step object.

155:   Logically Collective

157:   Input Parameter:
158: . ts - the `TS` context obtained from `TSCreate()`

160:   Level: intermediate

162:   Note:
163:   There is no way to remove a single, specific monitor.

165: .seealso: [](ch_ts), `TS`, `TSMonitorDefault()`, `TSMonitorSet()`
166: @*/
167: PetscErrorCode TSMonitorCancel(TS ts)
168: {
169:   PetscInt i;

171:   PetscFunctionBegin;
173:   for (i = 0; i < ts->numbermonitors; i++) {
174:     if (ts->monitordestroy[i]) PetscCall((*ts->monitordestroy[i])(&ts->monitorcontext[i]));
175:   }
176:   ts->numbermonitors = 0;
177:   PetscFunctionReturn(PETSC_SUCCESS);
178: }

180: /*@C
181:   TSMonitorDefault - The default monitor, prints the timestep and time for each step

183:   Input Parameters:
184: + ts    - the `TS` context
185: . step  - 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)
186: . ptime - current time
187: . v     - current iterate
188: - vf    - the viewer and format

190:   Options Database Key:
191: . -ts_monitor - monitors the time integration

193:   Level: intermediate

195:   Notes:
196:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
197:   to be used during the `TS` integration.

199: .seealso: [](ch_ts), `TSMonitorSet()`, `TSDMSwarmMonitorMoments()`, `TSMonitorWallClockTime()`, `TSMonitorExtreme()`, `TSMonitorDrawSolution()`,
200:           `TSMonitorDrawSolutionPhase()`, `TSMonitorDrawSolutionFunction()`, `TSMonitorDrawError()`, `TSMonitorSolution()`, `TSMonitorSolutionVTK()`,
201:           `TSMonitorLGSolution()`, `TSMonitorLGError()`, `TSMonitorSPSwarmSolution()`, `TSMonitorError()`, `TSMonitorEnvelope()`
202: @*/
203: PetscErrorCode TSMonitorDefault(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscViewerAndFormat *vf)
204: {
205:   PetscViewer viewer = vf->viewer;
206:   PetscBool   isascii, ibinary;

208:   PetscFunctionBegin;
210:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
211:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary));
212:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
213:   if (isascii) {
214:     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
215:     if (step == -1) { /* this indicates it is an interpolated solution */
216:       PetscCall(PetscViewerASCIIPrintf(viewer, "Interpolated solution at time %g between steps %" PetscInt_FMT " and %" PetscInt_FMT "\n", (double)ptime, ts->steps - 1, ts->steps));
217:     } else {
218:       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " TS dt %g time %g%s", step, (double)ts->time_step, (double)ptime, ts->steprollback ? " (r)\n" : "\n"));
219:     }
220:     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
221:   } else if (ibinary) {
222:     PetscMPIInt rank;
223:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
224:     if (rank == 0) {
225:       PetscBool skipHeader;
226:       PetscInt  classid = REAL_FILE_CLASSID;

228:       PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
229:       if (!skipHeader) PetscCall(PetscViewerBinaryWrite(viewer, &classid, 1, PETSC_INT));
230:       PetscCall(PetscRealView(1, &ptime, viewer));
231:     } else {
232:       PetscCall(PetscRealView(0, &ptime, viewer));
233:     }
234:   }
235:   PetscCall(PetscViewerPopFormat(viewer));
236:   PetscFunctionReturn(PETSC_SUCCESS);
237: }

239: typedef struct {
240:   PetscLogDouble time_start;
241:   PetscLogDouble time_last;
242:   PetscInt       snes_its;
243:   PetscInt       ksp_its;
244: } *TSMonitorWallClockTimeContext;

246: /*@C
247:   TSMonitorWallClockTimeSetUp - Setup routine passed to `TSMonitorSetFromOptions()` when using `-ts_monitor_wall_clock_time`

249:   Input Parameters:
250: + ts - the `TS` context
251: - vf - the viewer and format

253:   Level: intermediate

255:   Note:
256:   This is not called directly by users, rather one calls `TSMonitorSetFromOptions()`, with `TSMonitorWallClockTime()` and this function as arguments, to cause the monitor
257:   to be used during the `TS` integration.

259: .seealso: [](ch_ts), `TSMonitorSet()`
260: @*/
261: PetscErrorCode TSMonitorWallClockTimeSetUp(TS ts, PetscViewerAndFormat *vf)
262: {
263:   TSMonitorWallClockTimeContext speed;

265:   PetscFunctionBegin;
266:   PetscCall(PetscNew(&speed));
267:   speed->time_start = PETSC_DECIDE;
268:   vf->data_destroy  = PetscCtxDestroyDefault;
269:   vf->data          = speed;
270:   PetscFunctionReturn(PETSC_SUCCESS);
271: }

273: /*@C
274:   TSMonitorWallClockTime - Monitor wall-clock time, KSP iterations, and SNES iterations per step.

276:   Input Parameters:
277: + ts    - the `TS` context
278: . step  - 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)
279: . ptime - current time
280: . v     - current solution
281: - vf    - the viewer and format

283:   Options Database Key:
284: . -ts_monitor_wall_clock_time - Monitor wall-clock time, KSP iterations, and SNES iterations per step.

286:   Level: intermediate

288:   Note:
289:   This is not called directly by users, rather one calls `TSMonitorSetFromOptions()`, with this function and `TSMonitorWallClockTimeSetUp()` as arguments, to cause the monitor
290:   to be used during the `TS` integration.

292: .seealso: [](ch_ts), `TSMonitorSet()`, `TSMonitorDefault()`, `TSMonitorExtreme()`, `TSMonitorDrawSolution()`,
293:           `TSMonitorDrawSolutionPhase()`, `TSMonitorDrawSolutionFunction()`, `TSMonitorDrawError()`, `TSMonitorSolution()`, `TSMonitorSolutionVTK()`,
294:           `TSMonitorLGSolution()`, `TSMonitorLGError()`, `TSMonitorSPSwarmSolution()`, `TSMonitorError()`, `TSMonitorEnvelope()`, `TSDMSwarmMonitorMoments()`
295: @*/
296: PetscErrorCode TSMonitorWallClockTime(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscViewerAndFormat *vf)
297: {
298:   PetscViewer                   viewer = vf->viewer;
299:   TSMonitorWallClockTimeContext speed  = (TSMonitorWallClockTimeContext)vf->data;
300:   PetscBool                     isascii;
301:   PetscLogDouble                now;
302:   PetscInt                      snes_its, ksp_its;

304:   PetscFunctionBegin;
306:   PetscCall(PetscTime(&now));
307:   if (speed->time_start == PETSC_DECIDE) {
308:     speed->time_start = now;
309:     speed->time_last  = now;
310:   }
311:   PetscCall(TSGetSNESIterations(ts, &snes_its));
312:   PetscCall(TSGetKSPIterations(ts, &ksp_its));
313:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
314:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
315:   if (isascii) {
316:     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
317:     PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " TS dt %g time %g%s elapsed %.6f of %.6f snes %" PetscInt_FMT " ksp %" PetscInt_FMT "\n", step, (double)ts->time_step, (double)ptime, ts->steprollback ? " (r)" : "", now - speed->time_last,
318:                                      now - speed->time_start, snes_its - speed->snes_its, ksp_its - speed->ksp_its));
319:     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
320:   }
321:   PetscCall(PetscViewerPopFormat(viewer));
322:   speed->time_last = now;
323:   speed->snes_its  = snes_its;
324:   speed->ksp_its   = ksp_its;
325:   PetscFunctionReturn(PETSC_SUCCESS);
326: }

328: /*@C
329:   TSMonitorExtreme - Prints the extreme values of the solution at each timestep

331:   Input Parameters:
332: + ts    - the `TS` context
333: . step  - 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)
334: . ptime - current time
335: . v     - current iterate
336: - vf    - the viewer and format

338:   Level: intermediate

340:   Note:
341:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
342:   to be used during the `TS` integration.

344: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`
345: @*/
346: PetscErrorCode TSMonitorExtreme(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscViewerAndFormat *vf)
347: {
348:   PetscViewer viewer = vf->viewer;
349:   PetscBool   isascii;
350:   PetscReal   max, min;

352:   PetscFunctionBegin;
354:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
355:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
356:   if (isascii) {
357:     PetscCall(VecMax(v, NULL, &max));
358:     PetscCall(VecMin(v, NULL, &min));
359:     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
360:     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));
361:     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
362:   }
363:   PetscCall(PetscViewerPopFormat(viewer));
364:   PetscFunctionReturn(PETSC_SUCCESS);
365: }

367: /*@C
368:   TSMonitorLGCtxCreate - Creates a `TSMonitorLGCtx` context for use with
369:   `TS` to monitor the solution process graphically in various ways

371:   Collective

373:   Input Parameters:
374: + comm     - the MPI communicator to use
375: . host     - the X display to open, or `NULL` for the local machine
376: . label    - the title to put in the title bar
377: . x        - the x screen coordinates of the upper left coordinate of the window
378: . y        - the y screen coordinates of the upper left coordinate of the window
379: . m        - the screen width in pixels
380: . n        - the screen height in pixels
381: - howoften - if positive then determines the frequency of the plotting, if -1 then only at the final time

383:   Output Parameter:
384: . ctx - the context

386:   Options Database Keys:
387: + -ts_monitor_lg_timestep        - automatically sets line graph monitor
388: . -ts_monitor_lg_timestep_log    - automatically sets line graph monitor
389: . -ts_monitor_lg_solution        - monitor the solution (or certain values of the solution by calling `TSMonitorLGSetDisplayVariables()` or `TSMonitorLGCtxSetDisplayVariables()`)
390: . -ts_monitor_lg_error           - monitor the error
391: . -ts_monitor_lg_ksp_iterations  - monitor the number of `KSP` iterations needed for each timestep
392: . -ts_monitor_lg_snes_iterations - monitor the number of `SNES` iterations needed for each timestep
393: - -lg_use_markers (true|false)   - mark the data points (at each time step) on the plot; default is true

395:   Level: intermediate

397:   Notes:
398:   Pass the context and `TSMonitorLGCtxDestroy()` to `TSMonitorSet()` to have the context destroyed when no longer needed.

400:   One can provide a function that transforms the solution before plotting it with `TSMonitorLGCtxSetTransform()` or `TSMonitorLGSetTransform()`

402:   Many of the functions that control the monitoring have two forms\: TSMonitorLGSet/GetXXXX() and TSMonitorLGCtxSet/GetXXXX() the first take a `TS` object as the
403:   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
404:   as the first argument.

406:   One can control the names displayed for each solution or error variable with `TSMonitorLGCtxSetVariableNames()` or `TSMonitorLGSetVariableNames()`

408: .seealso: [](ch_ts), `TSMonitorLGTimeStep()`, `TSMonitorSet()`, `TSMonitorLGSolution()`, `TSMonitorLGError()`, `TSMonitorDefault()`, `VecView()`,
409:           `TSMonitorLGCtxSetVariableNames()`, `TSMonitorLGCtxGetVariableNames()`,
410:           `TSMonitorLGSetVariableNames()`, `TSMonitorLGGetVariableNames()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGCtxSetDisplayVariables()`,
411:           `TSMonitorLGCtxSetTransform()`, `TSMonitorLGSetTransform()`, `TSMonitorLGSNESIterations()`, `TSMonitorLGKSPIterations()`,
412:           `TSMonitorEnvelopeCtxCreate()`, `TSMonitorEnvelopeGetBounds()`, `TSMonitorEnvelopeCtxDestroy()`, `TSMonitorEnvelop()`
413: @*/
414: PetscErrorCode TSMonitorLGCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, TSMonitorLGCtx *ctx)
415: {
416:   PetscDraw draw;

418:   PetscFunctionBegin;
419:   PetscCall(PetscNew(ctx));
420:   PetscCall(PetscDrawCreate(comm, host, label, x, y, m, n, &draw));
421:   PetscCall(PetscDrawSetFromOptions(draw));
422:   PetscCall(PetscDrawLGCreate(draw, 1, &(*ctx)->lg));
423:   PetscCall(PetscDrawLGSetFromOptions((*ctx)->lg));
424:   PetscCall(PetscDrawDestroy(&draw));
425:   (*ctx)->howoften = howoften;
426:   PetscFunctionReturn(PETSC_SUCCESS);
427: }

429: /*@C
430:   TSMonitorLGTimeStep - Monitors a `TS` by printing the time-steps

432:   Collective

434:   Input Parameters:
435: + ts     - the time integrator
436: . step   - the current time step
437: . ptime  - the current time
438: . v      - the current state
439: - monctx - the monitor context obtained with `TSMonitorLGCtxCreate()`

441:   Level: advanced

443:   Note:
444:   This is not called directly by users, rather one calls `TSMonitorSet()` along the `ctx` created by `TSMonitorLGCtxCreate()`
445:   and `TSMonitorLGCtxDestroy()`

447: .seealso: [](ch_ts), `TS`, `TSMonitorLGCtxCreate()`, `TSMonitorSet()`, `TSMonitorLGCtxDestroy()`
448: @*/
449: PetscErrorCode TSMonitorLGTimeStep(TS ts, PetscInt step, PetscReal ptime, Vec v, PetscCtx monctx)
450: {
451:   TSMonitorLGCtx ctx = (TSMonitorLGCtx)monctx;
452:   PetscReal      x   = ptime, y;

454:   PetscFunctionBegin;
455:   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates an interpolated solution */
456:   if (!step) {
457:     PetscDrawAxis axis;
458:     const char   *ylabel = ctx->semilogy ? "Log Time Step" : "Time Step";
459:     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
460:     PetscCall(PetscDrawAxisSetLabels(axis, "Timestep as function of time", "Time", ylabel));
461:     PetscCall(PetscDrawLGReset(ctx->lg));
462:   }
463:   PetscCall(TSGetTimeStep(ts, &y));
464:   if (ctx->semilogy) y = PetscLog10Real(y);
465:   PetscCall(PetscDrawLGAddPoint(ctx->lg, &x, &y));
466:   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
467:     PetscCall(PetscDrawLGDraw(ctx->lg));
468:     PetscCall(PetscDrawLGSave(ctx->lg));
469:   }
470:   PetscFunctionReturn(PETSC_SUCCESS);
471: }

473: /*@C
474:   TSMonitorLGCtxDestroy - Destroys a line graph context that was created with `TSMonitorLGCtxCreate()`.

476:   Collective

478:   Input Parameter:
479: . ctx - the monitor context

481:   Level: intermediate

483:   Note:
484:   Pass to `TSMonitorSet()` along with the context and `TSMonitorLGTimeStep()`

486: .seealso: [](ch_ts), `TS`, `TSMonitorLGCtxCreate()`, `TSMonitorSet()`, `TSMonitorLGTimeStep()`
487: @*/
488: PetscErrorCode TSMonitorLGCtxDestroy(TSMonitorLGCtx *ctx)
489: {
490:   PetscFunctionBegin;
491:   if ((*ctx)->transformdestroy) PetscCall(((*ctx)->transformdestroy)(&(*ctx)->transformctx));
492:   PetscCall(PetscDrawLGDestroy(&(*ctx)->lg));
493:   PetscCall(PetscStrArrayDestroy(&(*ctx)->names));
494:   PetscCall(PetscStrArrayDestroy(&(*ctx)->displaynames));
495:   PetscCall(PetscFree((*ctx)->displayvariables));
496:   PetscCall(PetscFree((*ctx)->displayvalues));
497:   PetscCall(PetscFree(*ctx));
498:   PetscFunctionReturn(PETSC_SUCCESS);
499: }

501: /*@C
502:   TSMonitorSPCtxCreate - Creates a `TSMonitorSPCtx` scatter-plot monitor context for use with `DMSWARM` particle visualizations

504:   Collective

506:   Input Parameters:
507: + comm         - the MPI communicator to use
508: . host         - the X display to open, or `NULL` for the local machine
509: . label        - the title to put in the title bar
510: . x            - the x screen coordinates of the upper left coordinate of the window
511: . y            - the y screen coordinates of the upper left coordinate of the window
512: . m            - the screen width in pixels
513: . n            - the screen height in pixels
514: . howoften     - if positive then determines the frequency of the plotting, if -1 then only at the final time
515: . retain       - the number of old points to retain in the plot, or 0 to clear, or -1 to retain all
516: . phase        - `PETSC_TRUE` to plot in phase space rather than coordinate space
517: - multispecies - `PETSC_TRUE` to color particles by species

519:   Output Parameter:
520: . ctx - the newly created scatter plot monitor context

522:   Level: intermediate

524:   Note:
525:   Pass this context and `TSMonitorSPCtxDestroy()` to `TSMonitorSet()` with `TSMonitorSPSwarmSolution()` to display particles during the integration.

527: .seealso: [](ch_ts), `TS`, `DMSWARM`, `TSMonitorSet()`, `TSMonitorSPSwarmSolution()`, `TSMonitorSPCtxDestroy()`
528: @*/
529: 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, PetscBool multispecies, TSMonitorSPCtx *ctx)
530: {
531:   PetscDraw draw;

533:   PetscFunctionBegin;
534:   PetscCall(PetscNew(ctx));
535:   PetscCall(PetscDrawCreate(comm, host, label, x, y, m, n, &draw));
536:   PetscCall(PetscDrawSetFromOptions(draw));
537:   PetscCall(PetscDrawSPCreate(draw, 1, &(*ctx)->sp));
538:   PetscCall(PetscDrawDestroy(&draw));
539:   (*ctx)->howoften     = howoften;
540:   (*ctx)->retain       = retain;
541:   (*ctx)->phase        = phase;
542:   (*ctx)->multispecies = multispecies;
543:   PetscFunctionReturn(PETSC_SUCCESS);
544: }

546: /*@C
547:   TSMonitorSPCtxDestroy - Destroys a `TSMonitorSPCtx` that was created with `TSMonitorSPCtxCreate()`

549:   Not Collective

551:   Input Parameter:
552: . ctx - the scatter plot monitor context

554:   Level: intermediate

556: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorSPCtxCreate()`, `TSMonitorSPSwarmSolution()`
557: @*/
558: PetscErrorCode TSMonitorSPCtxDestroy(TSMonitorSPCtx *ctx)
559: {
560:   PetscFunctionBegin;
561:   PetscCall(PetscDrawSPDestroy(&(*ctx)->sp));
562:   PetscCall(PetscFree(*ctx));
563:   PetscFunctionReturn(PETSC_SUCCESS);
564: }

566: /*@C
567:   TSMonitorHGCtxCreate - Creates a `TSMonitorHGCtx` histogram monitor context for use with `DMSWARM` particle visualizations

569:   Collective

571:   Input Parameters:
572: + comm     - the MPI communicator to use
573: . host     - the X display to open, or `NULL` for the local machine
574: . label    - the title to put in the title bar
575: . x        - the x screen coordinates of the upper left coordinate of the window
576: . y        - the y screen coordinates of the upper left coordinate of the window
577: . m        - the screen width in pixels
578: . n        - the screen height in pixels
579: . howoften - if positive then determines the frequency of the plotting, if -1 then only at the final time
580: . Ns       - the number of species to histogram
581: . Nb       - the number of histogram bins
582: - velocity - `PETSC_TRUE` to plot histograms in velocity space, `PETSC_FALSE` for coordinate space

584:   Output Parameter:
585: . ctx - the newly created histogram monitor context

587:   Level: intermediate

589:   Note:
590:   Pass this context and `TSMonitorHGCtxDestroy()` to `TSMonitorSet()` with `TSMonitorHGSwarmSolution()` to display particle histograms during integration.

592: .seealso: [](ch_ts), `TS`, `DMSWARM`, `TSMonitorSet()`, `TSMonitorHGSwarmSolution()`, `TSMonitorHGCtxDestroy()`
593: @*/
594: PetscErrorCode TSMonitorHGCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, PetscInt Ns, PetscInt Nb, PetscBool velocity, TSMonitorHGCtx *ctx)
595: {
596:   PetscDraw draw;
597:   int       Nsi, Nbi;

599:   PetscFunctionBegin;
600:   PetscCall(PetscMPIIntCast(Ns, &Nsi));
601:   PetscCall(PetscMPIIntCast(Nb, &Nbi));
602:   PetscCall(PetscNew(ctx));
603:   PetscCall(PetscMalloc1(Ns, &(*ctx)->hg));
604:   for (int s = 0; s < Nsi; ++s) {
605:     PetscCall(PetscDrawCreate(comm, host, label, x + s * m, y, m, n, &draw));
606:     PetscCall(PetscDrawSetFromOptions(draw));
607:     PetscCall(PetscDrawHGCreate(draw, Nbi, &(*ctx)->hg[s]));
608:     PetscCall(PetscDrawHGCalcStats((*ctx)->hg[s], PETSC_TRUE));
609:     PetscCall(PetscDrawDestroy(&draw));
610:   }
611:   (*ctx)->howoften = howoften;
612:   (*ctx)->Ns       = Ns;
613:   (*ctx)->velocity = velocity;
614:   PetscFunctionReturn(PETSC_SUCCESS);
615: }

617: /*@C
618:   TSMonitorHGCtxDestroy - Destroys a `TSMonitorHGCtx` that was created with `TSMonitorHGCtxCreate()`

620:   Not Collective

622:   Input Parameter:
623: . ctx - the histogram monitor context

625:   Level: intermediate

627: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorHGCtxCreate()`, `TSMonitorHGSwarmSolution()`
628: @*/
629: PetscErrorCode TSMonitorHGCtxDestroy(TSMonitorHGCtx *ctx)
630: {
631:   PetscInt s;

633:   PetscFunctionBegin;
634:   for (s = 0; s < (*ctx)->Ns; ++s) PetscCall(PetscDrawHGDestroy(&(*ctx)->hg[s]));
635:   PetscCall(PetscFree((*ctx)->hg));
636:   PetscCall(PetscFree(*ctx));
637:   PetscFunctionReturn(PETSC_SUCCESS);
638: }

640: /*@C
641:   TSMonitorDrawSolution - Monitors progress of the `TS` solvers by calling
642:   `VecView()` for the solution at each timestep

644:   Collective

646:   Input Parameters:
647: + ts    - the `TS` context
648: . step  - current time-step
649: . ptime - current time
650: . u     - the solution at the current time
651: - ctx   - either a viewer or `NULL`

653:   Options Database Keys:
654: + -ts_monitor_draw_solution         - draw the solution at each time-step
655: - -ts_monitor_draw_solution_initial - show initial solution as well as current solution

657:   Level: intermediate

659:   Notes:
660:   The initial solution and current solution are not displayed with a common axis scaling so generally the option `-ts_monitor_draw_solution_initial`
661:   will look bad

663:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, as well as the context created with
664:   `TSMonitorDrawCtxCreate()` and the function `TSMonitorDrawCtxDestroy()` to cause the monitor to be used during the `TS` integration.

666: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorDrawCtxCreate()`, `TSMonitorDrawCtxDestroy()`
667: @*/
668: PetscErrorCode TSMonitorDrawSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx ctx)
669: {
670:   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)ctx;
671:   PetscDraw        draw;

673:   PetscFunctionBegin;
674:   if (!step && ictx->showinitial) {
675:     if (!ictx->initialsolution) PetscCall(VecDuplicate(u, &ictx->initialsolution));
676:     PetscCall(VecCopy(u, ictx->initialsolution));
677:   }
678:   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) PetscFunctionReturn(PETSC_SUCCESS);

680:   if (ictx->showinitial) {
681:     PetscReal pause;
682:     PetscCall(PetscViewerDrawGetPause(ictx->viewer, &pause));
683:     PetscCall(PetscViewerDrawSetPause(ictx->viewer, 0.0));
684:     PetscCall(VecView(ictx->initialsolution, ictx->viewer));
685:     PetscCall(PetscViewerDrawSetPause(ictx->viewer, pause));
686:     PetscCall(PetscViewerDrawSetHold(ictx->viewer, PETSC_TRUE));
687:   }
688:   PetscCall(VecView(u, ictx->viewer));
689:   if (ictx->showtimestepandtime) {
690:     PetscReal xl, yl, xr, yr, h;
691:     char      time[32];

693:     PetscCall(PetscViewerDrawGetDraw(ictx->viewer, 0, &draw));
694:     PetscCall(PetscSNPrintf(time, 32, "Timestep %" PetscInt_FMT " Time %g", step, (double)ptime));
695:     PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr));
696:     h = yl + .95 * (yr - yl);
697:     PetscCall(PetscDrawStringCentered(draw, .5 * (xl + xr), h, PETSC_DRAW_BLACK, time));
698:     PetscCall(PetscDrawFlush(draw));
699:   }

701:   if (ictx->showinitial) PetscCall(PetscViewerDrawSetHold(ictx->viewer, PETSC_FALSE));
702:   PetscFunctionReturn(PETSC_SUCCESS);
703: }

705: /*@C
706:   TSMonitorDrawSolutionPhase - Monitors progress of the `TS` solvers by plotting the solution as a phase diagram

708:   Collective

710:   Input Parameters:
711: + ts    - the `TS` context
712: . step  - current time-step
713: . ptime - current time
714: . u     - the solution at the current time
715: - ctx   - either a viewer or `NULL`

717:   Level: intermediate

719:   Notes:
720:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
721:   to be used during the `TS` integration.

723: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`
724: @*/
725: PetscErrorCode TSMonitorDrawSolutionPhase(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx ctx)
726: {
727:   TSMonitorDrawCtx   ictx = (TSMonitorDrawCtx)ctx;
728:   PetscDraw          draw;
729:   PetscDrawAxis      axis;
730:   PetscInt           n;
731:   PetscMPIInt        size;
732:   PetscReal          U0, U1, xl, yl, xr, yr, h;
733:   char               time[32];
734:   const PetscScalar *U;

736:   PetscFunctionBegin;
737:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)ts), &size));
738:   PetscCheck(size == 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Only allowed for sequential runs");
739:   PetscCall(VecGetSize(u, &n));
740:   PetscCheck(n == 2, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Only for ODEs with two unknowns");

742:   PetscCall(PetscViewerDrawGetDraw(ictx->viewer, 0, &draw));
743:   PetscCall(PetscViewerDrawGetDrawAxis(ictx->viewer, 0, &axis));
744:   PetscCall(PetscDrawAxisGetLimits(axis, &xl, &xr, &yl, &yr));
745:   if (!step) {
746:     PetscCall(PetscDrawClear(draw));
747:     PetscCall(PetscDrawAxisDraw(axis));
748:   }

750:   PetscCall(VecGetArrayRead(u, &U));
751:   U0 = PetscRealPart(U[0]);
752:   U1 = PetscRealPart(U[1]);
753:   PetscCall(VecRestoreArrayRead(u, &U));
754:   if ((U0 < xl) || (U1 < yl) || (U0 > xr) || (U1 > yr)) PetscFunctionReturn(PETSC_SUCCESS);

756:   PetscDrawCollectiveBegin(draw);
757:   PetscCall(PetscDrawPoint(draw, U0, U1, PETSC_DRAW_BLACK));
758:   if (ictx->showtimestepandtime) {
759:     PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr));
760:     PetscCall(PetscSNPrintf(time, 32, "Timestep %" PetscInt_FMT " Time %g", step, (double)ptime));
761:     h = yl + .95 * (yr - yl);
762:     PetscCall(PetscDrawStringCentered(draw, .5 * (xl + xr), h, PETSC_DRAW_BLACK, time));
763:   }
764:   PetscDrawCollectiveEnd(draw);
765:   PetscCall(PetscDrawFlush(draw));
766:   PetscCall(PetscDrawPause(draw));
767:   PetscCall(PetscDrawSave(draw));
768:   PetscFunctionReturn(PETSC_SUCCESS);
769: }

771: /*@C
772:   TSMonitorDrawCtxDestroy - Destroys the monitor context for `TSMonitorDrawSolution()`

774:   Collective

776:   Input Parameter:
777: . ictx - the monitor context

779:   Level: intermediate

781: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorDrawSolution()`, `TSMonitorDrawError()`, `TSMonitorDrawCtx`
782: @*/
783: PetscErrorCode TSMonitorDrawCtxDestroy(TSMonitorDrawCtx *ictx)
784: {
785:   PetscFunctionBegin;
786:   PetscCall(PetscViewerDestroy(&(*ictx)->viewer));
787:   PetscCall(VecDestroy(&(*ictx)->initialsolution));
788:   PetscCall(PetscFree(*ictx));
789:   PetscFunctionReturn(PETSC_SUCCESS);
790: }

792: /*@C
793:   TSMonitorDrawCtxCreate - Creates the monitor context for `TSMonitorDrawCtx`

795:   Collective

797:   Input Parameters:
798: + comm     - the MPI communicator to use
799: . host     - the X display to open, or `NULL` for the local machine
800: . label    - the title to put in the title bar
801: . x        - the x screen coordinates of the upper left coordinate of the window
802: . y        - the y screen coordinates of the upper left coordinate of the window
803: . m        - the screen width in pixels
804: . n        - the screen height in pixels
805: - howoften - if positive then determines the frequency of the plotting, if -1 then only at the final time

807:   Output Parameter:
808: . ctx - the monitor context

810:   Options Database Keys:
811: + -ts_monitor_draw_solution         - draw the solution at each time-step
812: - -ts_monitor_draw_solution_initial - show initial solution as well as current solution

814:   Level: intermediate

816:   Note:
817:   The context created by this function, `PetscMonitorDrawSolution()`, and `TSMonitorDrawCtxDestroy()` should be passed together to `TSMonitorSet()`.

819: .seealso: [](ch_ts), `TS`, `TSMonitorDrawCtxDestroy()`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorDrawCtx`, `PetscMonitorDrawSolution()`
820: @*/
821: PetscErrorCode TSMonitorDrawCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, TSMonitorDrawCtx *ctx)
822: {
823:   PetscFunctionBegin;
824:   PetscCall(PetscNew(ctx));
825:   PetscCall(PetscViewerDrawOpen(comm, host, label, x, y, m, n, &(*ctx)->viewer));
826:   PetscCall(PetscViewerSetFromOptions((*ctx)->viewer));

828:   (*ctx)->howoften    = howoften;
829:   (*ctx)->showinitial = PETSC_FALSE;
830:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-ts_monitor_draw_solution_initial", &(*ctx)->showinitial, NULL));

832:   (*ctx)->showtimestepandtime = PETSC_FALSE;
833:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-ts_monitor_draw_solution_show_time", &(*ctx)->showtimestepandtime, NULL));
834:   PetscFunctionReturn(PETSC_SUCCESS);
835: }

837: /*@C
838:   TSMonitorDrawSolutionFunction - Monitors progress of the `TS` solvers by calling
839:   `VecView()` for the solution provided by `TSSetSolutionFunction()` at each timestep

841:   Collective

843:   Input Parameters:
844: + ts    - the `TS` context
845: . step  - current time-step
846: . ptime - current time
847: . u     - solution at current time
848: - Ctx   - either a viewer or `NULL`

850:   Options Database Key:
851: . -ts_monitor_draw_solution_function - Monitor error graphically, requires user to have provided `TSSetSolutionFunction()`

853:   Level: intermediate

855:   Note:
856:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
857:   to be used during the `TS` integration.

859: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
860: @*/
861: PetscErrorCode TSMonitorDrawSolutionFunction(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx Ctx)
862: {
863:   TSMonitorDrawCtx ctx    = (TSMonitorDrawCtx)Ctx;
864:   PetscViewer      viewer = ctx->viewer;
865:   Vec              work;

867:   PetscFunctionBegin;
868:   if (!(((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason))) PetscFunctionReturn(PETSC_SUCCESS);
869:   PetscCall(VecDuplicate(u, &work));
870:   PetscCall(TSComputeSolutionFunction(ts, ptime, work));
871:   PetscCall(VecView(work, viewer));
872:   PetscCall(VecDestroy(&work));
873:   PetscFunctionReturn(PETSC_SUCCESS);
874: }

876: /*@C
877:   TSMonitorDrawError - Monitors progress of the `TS` solvers by calling
878:   `VecView()` for the error at each timestep

880:   Collective

882:   Input Parameters:
883: + ts    - the `TS` context
884: . step  - current time-step
885: . ptime - current time
886: . u     - solution at current time
887: - Ctx   - either a viewer or `NULL`

889:   Options Database Key:
890: . -ts_monitor_draw_error - Monitor error graphically, requires user to have provided `TSSetSolutionFunction()`

892:   Level: intermediate

894:   Notes:
895:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
896:   to be used during the `TS` integration.

898: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
899: @*/
900: PetscErrorCode TSMonitorDrawError(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx Ctx)
901: {
902:   TSMonitorDrawCtx ctx    = (TSMonitorDrawCtx)Ctx;
903:   PetscViewer      viewer = ctx->viewer;
904:   Vec              work;

906:   PetscFunctionBegin;
907:   if (!(((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason))) PetscFunctionReturn(PETSC_SUCCESS);
908:   PetscCall(VecDuplicate(u, &work));
909:   PetscCall(TSComputeSolutionFunction(ts, ptime, work));
910:   PetscCall(VecAXPY(work, -1.0, u));
911:   PetscCall(VecView(work, viewer));
912:   PetscCall(VecDestroy(&work));
913:   PetscFunctionReturn(PETSC_SUCCESS);
914: }

916: /*@C
917:   TSMonitorSolutionSetup - Setups the context for `TSMonitorSolution()`

919:   Collective

921:   Input Parameters:
922: + ts - the `TS` context
923: - vf - viewer and its format

925:   Level: intermediate

927: .seealso: [](ch_ts), `TS`, `TSMonitorSolution()`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorSetFromOptions()`
928: @*/
929: PetscErrorCode TSMonitorSolutionSetup(TS ts, PetscViewerAndFormat *vf)
930: {
931:   TSMonitorSolutionCtx ctx;

933:   PetscFunctionBegin;
934:   PetscCall(PetscNew(&ctx));
935:   PetscCall(PetscOptionsGetBool(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_monitor_solution_skip_initial", &ctx->skip_initial, NULL));
936:   vf->data         = ctx;
937:   vf->data_destroy = PetscCtxDestroyDefault;
938:   PetscFunctionReturn(PETSC_SUCCESS);
939: }

941: /*@C
942:   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

944:   Collective

946:   Input Parameters:
947: + ts    - the `TS` context
948: . step  - current time-step
949: . ptime - current time
950: . u     - current state
951: - vf    - viewer and its format

953:   Level: intermediate

955:   Notes:
956:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
957:   to be used during the `TS` integration.

959: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorSolutionSetup()`
960: @*/
961: PetscErrorCode TSMonitorSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscViewerAndFormat *vf)
962: {
963:   TSMonitorSolutionCtx ctx = (TSMonitorSolutionCtx)vf->data;

965:   PetscFunctionBegin;
966:   if (ctx->skip_initial && step == ts->start_step) PetscFunctionReturn(PETSC_SUCCESS);
967:   if ((vf->view_interval > 0 && !(step % vf->view_interval)) || (vf->view_interval && ts->reason)) {
968:     PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
969:     PetscCall(VecView(u, vf->viewer));
970:     PetscCall(PetscViewerPopFormat(vf->viewer));
971:   }
972:   PetscFunctionReturn(PETSC_SUCCESS);
973: }

975: /*@C
976:   TSMonitorSolutionVTK - Monitors progress of the `TS` solvers by `VecView()` for the solution at selected timesteps.

978:   Collective

980:   Input Parameters:
981: + ts    - the `TS` context
982: . step  - current time-step
983: . ptime - current time
984: . u     - current state
985: - ctx   - monitor context obtained with `TSMonitorSolutionVTKCtxCreate()`

987:   Level: developer

989:   Notes:
990:   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.
991:   These are named according to the file name template.

993:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
994:   to be used during the `TS` integration.

996: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`
997: @*/
998: PetscErrorCode TSMonitorSolutionVTK(TS ts, PetscInt step, PetscReal ptime, Vec u, TSMonitorVTKCtx ctx)
999: {
1000:   char        filename[PETSC_MAX_PATH_LEN];
1001:   PetscViewer viewer;

1003:   PetscFunctionBegin;
1004:   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
1005:   if (((ctx->interval > 0) && (!(step % ctx->interval))) || (ctx->interval && ts->reason)) {
1006:     PetscCall(PetscSNPrintf(filename, sizeof(filename), (const char *)ctx->filenametemplate, step));
1007:     PetscCall(PetscViewerVTKOpen(PetscObjectComm((PetscObject)ts), filename, FILE_MODE_WRITE, &viewer));
1008:     PetscCall(VecView(u, viewer));
1009:     PetscCall(PetscViewerDestroy(&viewer));
1010:   }
1011:   PetscFunctionReturn(PETSC_SUCCESS);
1012: }

1014: /*@C
1015:   TSMonitorSolutionVTKDestroy - Destroy the monitor context created with `TSMonitorSolutionVTKCtxCreate()`

1017:   Not Collective

1019:   Input Parameter:
1020: . ctx - the monitor context

1022:   Level: developer

1024:   Note:
1025:   This function is normally passed to `TSMonitorSet()` along with `TSMonitorSolutionVTK()`.

1027: .seealso: [](ch_ts), `TSMonitorSet()`, `TSMonitorSolutionVTK()`
1028: @*/
1029: PetscErrorCode TSMonitorSolutionVTKDestroy(TSMonitorVTKCtx *ctx)
1030: {
1031:   PetscFunctionBegin;
1032:   if (!*ctx) PetscFunctionReturn(PETSC_SUCCESS);
1033:   PetscCall(PetscFree((*ctx)->filenametemplate));
1034:   PetscCall(PetscFree(*ctx));
1035:   PetscFunctionReturn(PETSC_SUCCESS);
1036: }

1038: /*@C
1039:   TSMonitorSolutionVTKCtxCreate - Create the monitor context to be used in `TSMonitorSolutionVTK()`

1041:   Not collective

1043:   Input Parameter:
1044: . filenametemplate - the template file name, e.g. foo-%03d.vts

1046:   Output Parameter:
1047: . ctx - the monitor context

1049:   Level: developer

1051:   Note:
1052:   This function is normally used inside `TSSetFromOptions()` to pass the context created to `TSMonitorSet()` along with `TSMonitorSolutionVTK()`.

1054: .seealso: [](ch_ts), `TSMonitorSet()`, `TSMonitorSolutionVTK()`, `TSMonitorSolutionVTKDestroy()`
1055: @*/
1056: PetscErrorCode TSMonitorSolutionVTKCtxCreate(const char *filenametemplate, TSMonitorVTKCtx *ctx)
1057: {
1058:   const char     *ptr = NULL, *ptr2 = NULL;
1059:   TSMonitorVTKCtx ictx;

1061:   PetscFunctionBegin;
1062:   PetscAssertPointer(filenametemplate, 1);
1063:   PetscAssertPointer(ctx, 2);
1064:   /* Do some cursory validation of the input. */
1065:   PetscCall(PetscStrstr(filenametemplate, "%", (char **)&ptr));
1066:   PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_USER, "-ts_monitor_solution_vtk requires a file template, e.g. filename-%%03" PetscInt_FMT ".vts");
1067:   for (ptr++; ptr && *ptr; ptr++) {
1068:     PetscCall(PetscStrchr("DdiouxX", *ptr, (char **)&ptr2));
1069:     PetscCheck(ptr2 || (*ptr >= '0' && *ptr <= '9'), PETSC_COMM_SELF, PETSC_ERR_USER, "Invalid file template argument to -ts_monitor_solution_vtk, should look like filename-%%03" PetscInt_FMT ".vts");
1070:     if (ptr2) break;
1071:   }
1072:   PetscCall(PetscNew(&ictx));
1073:   PetscCall(PetscStrallocpy(filenametemplate, &ictx->filenametemplate));
1074:   ictx->interval = 1;

1076:   *ctx = ictx;
1077:   PetscFunctionReturn(PETSC_SUCCESS);
1078: }

1080: /*@C
1081:   TSMonitorLGSolution - Monitors progress of the `TS` solvers by plotting each component of the solution vector
1082:   in a time based line graph

1084:   Collective

1086:   Input Parameters:
1087: + ts    - the `TS` context
1088: . step  - current time-step
1089: . ptime - current time
1090: . u     - current solution
1091: - dctx  - the `TSMonitorLGCtx` object that contains all the options for the monitoring, this is created with `TSMonitorLGCtxCreate()`

1093:   Options Database Key:
1094: . -ts_monitor_lg_solution_variables - enable monitor of lg solution variables

1096:   Level: intermediate

1098:   Notes:
1099:   Each process in a parallel run displays its component solutions in a separate window

1101:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1102:   to be used during the `TS` integration.

1104: .seealso: [](ch_ts), `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGCtxCreate()`, `TSMonitorLGCtxSetVariableNames()`, `TSMonitorLGCtxGetVariableNames()`,
1105:           `TSMonitorLGSetVariableNames()`, `TSMonitorLGGetVariableNames()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGCtxSetDisplayVariables()`,
1106:           `TSMonitorLGCtxSetTransform()`, `TSMonitorLGSetTransform()`, `TSMonitorLGError()`, `TSMonitorLGSNESIterations()`, `TSMonitorLGKSPIterations()`,
1107:           `TSMonitorEnvelopeCtxCreate()`, `TSMonitorEnvelopeGetBounds()`, `TSMonitorEnvelopeCtxDestroy()`, `TSMonitorEnvelop()`
1108: @*/
1109: PetscErrorCode TSMonitorLGSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, void *dctx)
1110: {
1111:   TSMonitorLGCtx     ctx = (TSMonitorLGCtx)dctx;
1112:   const PetscScalar *yy;
1113:   Vec                v;

1115:   PetscFunctionBegin;
1116:   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
1117:   if (!step) {
1118:     PetscDrawAxis axis;
1119:     PetscInt      dim;
1120:     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
1121:     PetscCall(PetscDrawAxisSetLabels(axis, "Solution as function of time", "Time", "Solution"));
1122:     if (!ctx->names) {
1123:       PetscBool flg;
1124:       /* user provides names of variables to plot but no names has been set so assume names are integer values */
1125:       PetscCall(PetscOptionsHasName(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_monitor_lg_solution_variables", &flg));
1126:       if (flg) {
1127:         PetscInt i, n;
1128:         char   **names;
1129:         PetscCall(VecGetSize(u, &n));
1130:         PetscCall(PetscMalloc1(n + 1, &names));
1131:         for (i = 0; i < n; i++) {
1132:           PetscCall(PetscMalloc1(5, &names[i]));
1133:           PetscCall(PetscSNPrintf(names[i], 5, "%" PetscInt_FMT, i));
1134:         }
1135:         names[n]   = NULL;
1136:         ctx->names = names;
1137:       }
1138:     }
1139:     if (ctx->names && !ctx->displaynames) {
1140:       char    **displaynames;
1141:       PetscBool flg;
1142:       PetscCall(VecGetLocalSize(u, &dim));
1143:       PetscCall(PetscCalloc1(dim + 1, &displaynames));
1144:       PetscCall(PetscOptionsGetStringArray(((PetscObject)ts)->options, ((PetscObject)ts)->prefix, "-ts_monitor_lg_solution_variables", displaynames, &dim, &flg));
1145:       if (flg) PetscCall(TSMonitorLGCtxSetDisplayVariables(ctx, (const char *const *)displaynames));
1146:       PetscCall(PetscStrArrayDestroy(&displaynames));
1147:     }
1148:     if (ctx->displaynames) {
1149:       PetscCall(PetscDrawLGSetDimension(ctx->lg, ctx->ndisplayvariables));
1150:       PetscCall(PetscDrawLGSetLegend(ctx->lg, (const char *const *)ctx->displaynames));
1151:     } else if (ctx->names) {
1152:       PetscCall(VecGetLocalSize(u, &dim));
1153:       PetscCall(PetscDrawLGSetDimension(ctx->lg, dim));
1154:       PetscCall(PetscDrawLGSetLegend(ctx->lg, (const char *const *)ctx->names));
1155:     } else {
1156:       PetscCall(VecGetLocalSize(u, &dim));
1157:       PetscCall(PetscDrawLGSetDimension(ctx->lg, dim));
1158:     }
1159:     PetscCall(PetscDrawLGReset(ctx->lg));
1160:   }

1162:   if (!ctx->transform) v = u;
1163:   else PetscCall((*ctx->transform)(ctx->transformctx, u, &v));
1164:   PetscCall(VecGetArrayRead(v, &yy));
1165:   if (ctx->displaynames) {
1166:     PetscInt i;
1167:     for (i = 0; i < ctx->ndisplayvariables; i++) ctx->displayvalues[i] = PetscRealPart(yy[ctx->displayvariables[i]]);
1168:     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, ctx->displayvalues));
1169:   } else {
1170: #if defined(PETSC_USE_COMPLEX)
1171:     PetscInt   i, n;
1172:     PetscReal *yreal;
1173:     PetscCall(VecGetLocalSize(v, &n));
1174:     PetscCall(PetscMalloc1(n, &yreal));
1175:     for (i = 0; i < n; i++) yreal[i] = PetscRealPart(yy[i]);
1176:     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yreal));
1177:     PetscCall(PetscFree(yreal));
1178: #else
1179:     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yy));
1180: #endif
1181:   }
1182:   PetscCall(VecRestoreArrayRead(v, &yy));
1183:   if (ctx->transform) PetscCall(VecDestroy(&v));

1185:   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
1186:     PetscCall(PetscDrawLGDraw(ctx->lg));
1187:     PetscCall(PetscDrawLGSave(ctx->lg));
1188:   }
1189:   PetscFunctionReturn(PETSC_SUCCESS);
1190: }

1192: /*@C
1193:   TSMonitorLGSetVariableNames - Sets the name of each component in the solution vector so that it may be displayed in the plot

1195:   Collective

1197:   Input Parameters:
1198: + ts    - the `TS` context
1199: - names - the names of the components, final string must be `NULL`

1201:   Level: intermediate

1203:   Notes:
1204:   If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored

1206: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGCtxSetVariableNames()`
1207: @*/
1208: PetscErrorCode TSMonitorLGSetVariableNames(TS ts, const char *const *names)
1209: {
1210:   PetscInt i;

1212:   PetscFunctionBegin;
1213:   for (i = 0; i < ts->numbermonitors; i++) {
1214:     if (ts->monitor[i] == TSMonitorLGSolution) {
1215:       PetscCall(TSMonitorLGCtxSetVariableNames((TSMonitorLGCtx)ts->monitorcontext[i], names));
1216:       break;
1217:     }
1218:   }
1219:   PetscFunctionReturn(PETSC_SUCCESS);
1220: }

1222: /*@C
1223:   TSMonitorLGCtxSetVariableNames - Sets the name of each component in the solution vector so that it may be displayed in the plot

1225:   Collective

1227:   Input Parameters:
1228: + ctx   - the `TS` context
1229: - names - the names of the components, final string must be `NULL`

1231:   Level: intermediate

1233: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`, `TSMonitorLGSetVariableNames()`
1234: @*/
1235: PetscErrorCode TSMonitorLGCtxSetVariableNames(TSMonitorLGCtx ctx, const char *const *names)
1236: {
1237:   PetscFunctionBegin;
1238:   PetscCall(PetscStrArrayDestroy(&ctx->names));
1239:   PetscCall(PetscStrArrayallocpy(names, &ctx->names));
1240:   PetscFunctionReturn(PETSC_SUCCESS);
1241: }

1243: /*@C
1244:   TSMonitorLGGetVariableNames - Gets the name of each component in the solution vector so that it may be displayed in the plot

1246:   Collective

1248:   Input Parameter:
1249: . ts - the `TS` context

1251:   Output Parameter:
1252: . names - the names of the components, final string must be `NULL`

1254:   Level: intermediate

1256:   Note:
1257:   If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored

1259: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`
1260: @*/
1261: PetscErrorCode TSMonitorLGGetVariableNames(TS ts, const char *const **names)
1262: {
1263:   PetscInt i;

1265:   PetscFunctionBegin;
1266:   *names = NULL;
1267:   for (i = 0; i < ts->numbermonitors; i++) {
1268:     if (ts->monitor[i] == TSMonitorLGSolution) {
1269:       TSMonitorLGCtx ctx = (TSMonitorLGCtx)ts->monitorcontext[i];
1270:       *names             = (const char *const *)ctx->names;
1271:       break;
1272:     }
1273:   }
1274:   PetscFunctionReturn(PETSC_SUCCESS);
1275: }

1277: /*@C
1278:   TSMonitorLGCtxSetDisplayVariables - Sets the variables that are to be display in the monitor

1280:   Collective

1282:   Input Parameters:
1283: + ctx          - the `TSMonitorLG` context
1284: - displaynames - the names of the components, final string must be `NULL`

1286:   Level: intermediate

1288: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`
1289: @*/
1290: PetscErrorCode TSMonitorLGCtxSetDisplayVariables(TSMonitorLGCtx ctx, const char *const *displaynames)
1291: {
1292:   PetscInt j = 0, k;

1294:   PetscFunctionBegin;
1295:   if (!ctx->names) PetscFunctionReturn(PETSC_SUCCESS);
1296:   PetscCall(PetscStrArrayDestroy(&ctx->displaynames));
1297:   PetscCall(PetscStrArrayallocpy(displaynames, &ctx->displaynames));
1298:   while (displaynames[j]) j++;
1299:   ctx->ndisplayvariables = j;
1300:   PetscCall(PetscMalloc1(ctx->ndisplayvariables, &ctx->displayvariables));
1301:   PetscCall(PetscMalloc1(ctx->ndisplayvariables, &ctx->displayvalues));
1302:   j = 0;
1303:   while (displaynames[j]) {
1304:     k = 0;
1305:     while (ctx->names[k]) {
1306:       PetscBool flg;
1307:       PetscCall(PetscStrcmp(displaynames[j], ctx->names[k], &flg));
1308:       if (flg) {
1309:         ctx->displayvariables[j] = k;
1310:         break;
1311:       }
1312:       k++;
1313:     }
1314:     j++;
1315:   }
1316:   PetscFunctionReturn(PETSC_SUCCESS);
1317: }

1319: /*@C
1320:   TSMonitorLGSetDisplayVariables - Sets the variables that are to be display in the monitor

1322:   Collective

1324:   Input Parameters:
1325: + ts           - the `TS` context
1326: - displaynames - the names of the components, final string must be `NULL`

1328:   Level: intermediate

1330:   Note:
1331:   If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored

1333: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`
1334: @*/
1335: PetscErrorCode TSMonitorLGSetDisplayVariables(TS ts, const char *const *displaynames)
1336: {
1337:   PetscInt i;

1339:   PetscFunctionBegin;
1340:   for (i = 0; i < ts->numbermonitors; i++) {
1341:     if (ts->monitor[i] == TSMonitorLGSolution) {
1342:       PetscCall(TSMonitorLGCtxSetDisplayVariables((TSMonitorLGCtx)ts->monitorcontext[i], displaynames));
1343:       break;
1344:     }
1345:   }
1346:   PetscFunctionReturn(PETSC_SUCCESS);
1347: }

1349: /*@C
1350:   TSMonitorLGSetTransform - Solution vector will be transformed by provided function before being displayed

1352:   Collective

1354:   Input Parameters:
1355: + ts        - the `TS` context
1356: . transform - the transform function
1357: . destroy   - function to destroy the optional context, see `PetscCtxDestroyFn` for its calling sequence
1358: - tctx      - optional context used by transform function

1360:   Calling sequence of `transform`:
1361: + tctx - context used by the transform function
1362: . u    - the input solution vector
1363: - w    - the output transformed vector

1365:   Level: intermediate

1367:   Note:
1368:   If the `TS` object does not have a `TSMonitorLGCtx` associated with it then this function is ignored

1370: .seealso: [](ch_ts), `TSMonitorSet()`, `TSMonitorLGCtxSetTransform()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`, `PetscCtxDestroyFn`
1371: @*/
1372: PetscErrorCode TSMonitorLGSetTransform(TS ts, PetscErrorCode (*transform)(PetscCtx tctx, Vec u, Vec *w), PetscCtxDestroyFn *destroy, PetscCtx tctx)
1373: {
1374:   PetscInt i;

1376:   PetscFunctionBegin;
1377:   for (i = 0; i < ts->numbermonitors; i++) {
1378:     if (ts->monitor[i] == TSMonitorLGSolution) PetscCall(TSMonitorLGCtxSetTransform((TSMonitorLGCtx)ts->monitorcontext[i], transform, destroy, tctx));
1379:   }
1380:   PetscFunctionReturn(PETSC_SUCCESS);
1381: }

1383: /*@C
1384:   TSMonitorLGCtxSetTransform - Solution vector will be transformed by provided function before being displayed

1386:   Collective

1388:   Input Parameters:
1389: + tctx      - the `TS` context
1390: . transform - the transform function
1391: . destroy   - function to destroy the optional context, see `PetscCtxDestroyFn` for its calling sequence
1392: - ctx       - optional context used by transform function

1394:   Calling sequence of `transform`:
1395: + tctx - context used by the transform function
1396: . u    - the input solution vector
1397: - w    - the output transformed vector

1399:   Level: intermediate

1401: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetVariableNames()`, `TSMonitorLGSetTransform()`, `PetscCtxDestroyFn`
1402: @*/
1403: PetscErrorCode TSMonitorLGCtxSetTransform(TSMonitorLGCtx ctx, PetscErrorCode (*transform)(PetscCtx tctx, Vec u, Vec *w), PetscCtxDestroyFn *destroy, PetscCtx tctx)
1404: {
1405:   PetscFunctionBegin;
1406:   ctx->transform        = transform;
1407:   ctx->transformdestroy = destroy;
1408:   ctx->transformctx     = tctx;
1409:   PetscFunctionReturn(PETSC_SUCCESS);
1410: }

1412: /*@C
1413:   TSMonitorLGError - Monitors progress of the `TS` solvers by plotting each component of the error
1414:   in a time based line graph

1416:   Collective

1418:   Input Parameters:
1419: + ts    - the `TS` context
1420: . step  - current time-step
1421: . ptime - current time
1422: . u     - current solution
1423: - Ctx   - `TSMonitorLGCtx` object created with `TSMonitorLGCtxCreate()`

1425:   Options Database Key:
1426: . -ts_monitor_lg_error - create a graphical monitor of error history

1428:   Level: intermediate

1430:   Notes:
1431:   Each process in a parallel run displays its component errors in a separate window

1433:   The user must provide the solution using `TSSetSolutionFunction()` to use this monitor.

1435:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1436:   to be used during the TS integration.

1438: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
1439: @*/
1440: PetscErrorCode TSMonitorLGError(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx Ctx)
1441: {
1442:   TSMonitorLGCtx     ctx = (TSMonitorLGCtx)Ctx;
1443:   const PetscScalar *yy;
1444:   Vec                y;

1446:   PetscFunctionBegin;
1447:   if (!step) {
1448:     PetscDrawAxis axis;
1449:     PetscInt      dim;
1450:     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
1451:     PetscCall(PetscDrawAxisSetLabels(axis, "Error in solution as function of time", "Time", "Error"));
1452:     PetscCall(VecGetLocalSize(u, &dim));
1453:     PetscCall(PetscDrawLGSetDimension(ctx->lg, dim));
1454:     PetscCall(PetscDrawLGReset(ctx->lg));
1455:   }
1456:   PetscCall(VecDuplicate(u, &y));
1457:   PetscCall(TSComputeSolutionFunction(ts, ptime, y));
1458:   PetscCall(VecAXPY(y, -1.0, u));
1459:   PetscCall(VecGetArrayRead(y, &yy));
1460: #if defined(PETSC_USE_COMPLEX)
1461:   {
1462:     PetscReal *yreal;
1463:     PetscInt   i, n;
1464:     PetscCall(VecGetLocalSize(y, &n));
1465:     PetscCall(PetscMalloc1(n, &yreal));
1466:     for (i = 0; i < n; i++) yreal[i] = PetscRealPart(yy[i]);
1467:     PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yreal));
1468:     PetscCall(PetscFree(yreal));
1469:   }
1470: #else
1471:   PetscCall(PetscDrawLGAddCommonPoint(ctx->lg, ptime, yy));
1472: #endif
1473:   PetscCall(VecRestoreArrayRead(y, &yy));
1474:   PetscCall(VecDestroy(&y));
1475:   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
1476:     PetscCall(PetscDrawLGDraw(ctx->lg));
1477:     PetscCall(PetscDrawLGSave(ctx->lg));
1478:   }
1479:   PetscFunctionReturn(PETSC_SUCCESS);
1480: }

1482: /*@C
1483:   TSMonitorSPSwarmSolution - Graphically displays phase plots of `DMSWARM` particles on a scatter plot

1485:   Input Parameters:
1486: + ts    - the `TS` context
1487: . step  - current time-step
1488: . ptime - current time
1489: . u     - current solution
1490: - dctx  - the `TSMonitorSPCtx` object that contains all the options for the monitoring, this is created with `TSMonitorSPCtxCreate()`

1492:   Options Database Keys:
1493: + -ts_monitor_sp_swarm n                          - Monitor the solution every n steps, or -1 for plotting only the final solution
1494: . -ts_monitor_sp_swarm_retain n                   - Retain n old points so we can see the history, or -1 for all points
1495: . -ts_monitor_sp_swarm_multi_species (true|false) - Color each species differently
1496: - -ts_monitor_sp_swarm_phase (true|false)         - Plot in phase space, as opposed to coordinate space

1498:   Level: intermediate

1500:   Notes:
1501:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1502:   to be used during the `TS` integration.

1504: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `DMSWARM`, `TSMonitorSPCtxCreate()`
1505: @*/
1506: PetscErrorCode TSMonitorSPSwarmSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx dctx)
1507: {
1508:   TSMonitorSPCtx     ctx = (TSMonitorSPCtx)dctx;
1509:   PetscDraw          draw;
1510:   DM                 dm, cdm;
1511:   const PetscScalar *yy;
1512:   PetscInt           Np, p, dim = 2, *species;
1513:   PetscReal          species_color;

1515:   PetscFunctionBegin;
1516:   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
1517:   PetscCall(TSGetDM(ts, &dm));
1518:   if (!step) {
1519:     PetscDrawAxis axis;
1520:     PetscReal     dmboxlower[2], dmboxupper[2];

1522:     PetscCall(TSGetDM(ts, &dm));
1523:     PetscCall(DMGetDimension(dm, &dim));
1524:     PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Monitor only supports two dimensional fields");
1525:     PetscCall(DMSwarmGetCellDM(dm, &cdm));
1526:     PetscCall(DMGetBoundingBox(cdm, dmboxlower, dmboxupper));
1527:     PetscCall(VecGetLocalSize(u, &Np));
1528:     Np /= dim * 2;
1529:     PetscCall(PetscDrawSPGetAxis(ctx->sp, &axis));
1530:     if (ctx->phase) {
1531:       PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "X", "V"));
1532:       PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], -10, 10));
1533:     } else {
1534:       PetscCall(PetscDrawAxisSetLabels(axis, "Particles", "X", "Y"));
1535:       PetscCall(PetscDrawAxisSetLimits(axis, dmboxlower[0], dmboxupper[0], dmboxlower[1], dmboxupper[1]));
1536:     }
1537:     PetscCall(PetscDrawAxisSetHoldLimits(axis, PETSC_TRUE));
1538:     PetscCall(PetscDrawSPReset(ctx->sp));
1539:   }
1540:   if (ctx->multispecies) PetscCall(DMSwarmGetField(dm, "species", NULL, NULL, (void **)&species));
1541:   PetscCall(VecGetLocalSize(u, &Np));
1542:   Np /= dim * 2;
1543:   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
1544:     PetscCall(PetscDrawSPGetDraw(ctx->sp, &draw));
1545:     if ((ctx->retain == 0) || (ctx->retain > 0 && !(step % ctx->retain))) PetscCall(PetscDrawClear(draw));
1546:     PetscCall(PetscDrawFlush(draw));
1547:     PetscCall(PetscDrawSPReset(ctx->sp));
1548:     PetscCall(VecGetArrayRead(u, &yy));
1549:     for (p = 0; p < Np; ++p) {
1550:       PetscReal x, y;

1552:       if (ctx->phase) {
1553:         x = PetscRealPart(yy[p * dim * 2]);
1554:         y = PetscRealPart(yy[p * dim * 2 + dim]);
1555:       } else {
1556:         x = PetscRealPart(yy[p * dim * 2]);
1557:         y = PetscRealPart(yy[p * dim * 2 + 1]);
1558:       }
1559:       if (ctx->multispecies) {
1560:         species_color = species[p] + 2;
1561:         PetscCall(PetscDrawSPAddPointColorized(ctx->sp, &x, &y, &species_color));
1562:       } else {
1563:         PetscCall(PetscDrawSPAddPoint(ctx->sp, &x, &y));
1564:       }
1565:       PetscCall(PetscDrawSPAddPoint(ctx->sp, &x, &y));
1566:     }
1567:     PetscCall(VecRestoreArrayRead(u, &yy));
1568:     PetscCall(PetscDrawSPDraw(ctx->sp, PETSC_FALSE));
1569:     PetscCall(PetscDrawSPSave(ctx->sp));
1570:     if (ctx->multispecies) PetscCall(DMSwarmRestoreField(dm, "species", NULL, NULL, (void **)&species));
1571:   }
1572:   PetscFunctionReturn(PETSC_SUCCESS);
1573: }

1575: /*@C
1576:   TSMonitorHGSwarmSolution - Graphically displays histograms of `DMSWARM` particles

1578:   Input Parameters:
1579: + ts    - the `TS` context
1580: . step  - current time-step
1581: . ptime - current time
1582: . u     - current solution
1583: - dctx  - the `TSMonitorSPCtx` object that contains all the options for the monitoring, this is created with `TSMonitorHGCtxCreate()`

1585:   Options Database Keys:
1586: + -ts_monitor_hg_swarm n                     - Monitor the solution every n steps, or -1 for plotting only the final solution
1587: . -ts_monitor_hg_swarm_species num           - Number of species to histogram
1588: . -ts_monitor_hg_swarm_bins num              - Number of histogram bins
1589: - -ts_monitor_hg_swarm_velocity (true|false) - Plot in velocity space, as opposed to coordinate space

1591:   Level: intermediate

1593:   Note:
1594:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1595:   to be used during the `TS` integration.

1597: .seealso: `TSMonitorSet()`
1598: @*/
1599: PetscErrorCode TSMonitorHGSwarmSolution(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx dctx)
1600: {
1601:   TSMonitorHGCtx     ctx = (TSMonitorHGCtx)dctx;
1602:   PetscDraw          draw;
1603:   DM                 sw;
1604:   const PetscScalar *yy;
1605:   PetscInt          *species;
1606:   PetscInt           dim, d = 0, Np, p, Ns, s;

1608:   PetscFunctionBegin;
1609:   if (step < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
1610:   PetscCall(TSGetDM(ts, &sw));
1611:   PetscCall(DMGetDimension(sw, &dim));
1612:   PetscCall(DMSwarmGetNumSpecies(sw, &Ns));
1613:   Ns = PetscMin(Ns, ctx->Ns);
1614:   PetscCall(VecGetLocalSize(u, &Np));
1615:   Np /= dim * 2;
1616:   if (!step) {
1617:     PetscDrawAxis axis;
1618:     char          title[PETSC_MAX_PATH_LEN];

1620:     for (s = 0; s < Ns; ++s) {
1621:       PetscCall(PetscDrawHGGetAxis(ctx->hg[s], &axis));
1622:       PetscCall(PetscSNPrintf(title, PETSC_MAX_PATH_LEN, "Species %" PetscInt_FMT, s));
1623:       if (ctx->velocity) PetscCall(PetscDrawAxisSetLabels(axis, title, "V", "N"));
1624:       else PetscCall(PetscDrawAxisSetLabels(axis, title, "X", "N"));
1625:     }
1626:   }
1627:   if (((ctx->howoften > 0) && (!(step % ctx->howoften))) || ((ctx->howoften == -1) && ts->reason)) {
1628:     PetscCall(DMSwarmGetField(sw, "species", NULL, NULL, (void **)&species));
1629:     for (s = 0; s < Ns; ++s) {
1630:       PetscCall(PetscDrawHGReset(ctx->hg[s]));
1631:       PetscCall(PetscDrawHGGetDraw(ctx->hg[s], &draw));
1632:       PetscCall(PetscDrawClear(draw));
1633:       PetscCall(PetscDrawFlush(draw));
1634:     }
1635:     PetscCall(VecGetArrayRead(u, &yy));
1636:     for (p = 0; p < Np; ++p) {
1637:       const PetscInt s = species[p] < Ns ? species[p] : 0;
1638:       PetscReal      v;

1640:       if (ctx->velocity) v = PetscRealPart(yy[p * dim * 2 + d + dim]);
1641:       else v = PetscRealPart(yy[p * dim * 2 + d]);
1642:       PetscCall(PetscDrawHGAddValue(ctx->hg[s], v));
1643:     }
1644:     PetscCall(VecRestoreArrayRead(u, &yy));
1645:     for (s = 0; s < Ns; ++s) {
1646:       PetscCall(PetscDrawHGDraw(ctx->hg[s]));
1647:       PetscCall(PetscDrawHGSave(ctx->hg[s]));
1648:     }
1649:     PetscCall(DMSwarmRestoreField(sw, "species", NULL, NULL, (void **)&species));
1650:   }
1651:   PetscFunctionReturn(PETSC_SUCCESS);
1652: }

1654: /*@C
1655:   TSMonitorError - Monitors progress of the `TS` solvers by printing the 2 norm of the error at each timestep

1657:   Collective

1659:   Input Parameters:
1660: + ts    - the `TS` context
1661: . step  - current time-step
1662: . ptime - current time
1663: . u     - current solution
1664: - vf    - unused context

1666:   Options Database Key:
1667: . -ts_monitor_error - create a graphical monitor of error history

1669:   Level: intermediate

1671:   Notes:
1672:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1673:   to be used during the `TS` integration.

1675:   The user must provide the solution using `TSSetSolutionFunction()` to use this monitor.

1677: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSSetSolutionFunction()`
1678: @*/
1679: PetscErrorCode TSMonitorError(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscViewerAndFormat *vf)
1680: {
1681:   DM        dm;
1682:   PetscDS   ds = NULL;
1683:   PetscInt  Nf = -1, f;
1684:   PetscBool flg;

1686:   PetscFunctionBegin;
1687:   PetscCall(TSGetDM(ts, &dm));
1688:   if (dm) PetscCall(DMGetDS(dm, &ds));
1689:   if (ds) PetscCall(PetscDSGetNumFields(ds, &Nf));
1690:   if (Nf <= 0) {
1691:     Vec       y;
1692:     PetscReal nrm;

1694:     PetscCall(VecDuplicate(u, &y));
1695:     PetscCall(TSComputeSolutionFunction(ts, ptime, y));
1696:     PetscCall(VecAXPY(y, -1.0, u));
1697:     PetscCall(PetscObjectTypeCompare((PetscObject)vf->viewer, PETSCVIEWERASCII, &flg));
1698:     if (flg) {
1699:       PetscCall(VecNorm(y, NORM_2, &nrm));
1700:       PetscCall(PetscViewerASCIIPrintf(vf->viewer, "2-norm of error %g\n", (double)nrm));
1701:     }
1702:     PetscCall(PetscObjectTypeCompare((PetscObject)vf->viewer, PETSCVIEWERDRAW, &flg));
1703:     if (flg) PetscCall(VecView(y, vf->viewer));
1704:     PetscCall(VecDestroy(&y));
1705:   } else {
1706:     PetscErrorCode (**exactFuncs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx);
1707:     void    **ctxs;
1708:     Vec       v;
1709:     PetscReal ferrors[1];

1711:     PetscCall(PetscMalloc2(Nf, &exactFuncs, Nf, &ctxs));
1712:     for (f = 0; f < Nf; ++f) PetscCall(PetscDSGetExactSolution(ds, f, &exactFuncs[f], &ctxs[f]));
1713:     PetscCall(DMComputeL2FieldDiff(dm, ptime, exactFuncs, ctxs, u, ferrors));
1714:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Timestep: %04" PetscInt_FMT " time = %-8.4g \t L_2 Error: [", step, (double)ptime));
1715:     for (f = 0; f < Nf; ++f) {
1716:       if (f > 0) PetscCall(PetscPrintf(PETSC_COMM_WORLD, ", "));
1717:       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%2.3g", (double)ferrors[f]));
1718:     }
1719:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "]\n"));

1721:     PetscCall(VecViewFromOptions(u, NULL, "-sol_vec_view"));

1723:     PetscCall(PetscOptionsHasName(NULL, NULL, "-exact_vec_view", &flg));
1724:     if (flg) {
1725:       PetscCall(DMGetGlobalVector(dm, &v));
1726:       PetscCall(DMProjectFunction(dm, ptime, exactFuncs, ctxs, INSERT_ALL_VALUES, v));
1727:       PetscCall(PetscObjectSetName((PetscObject)v, "Exact Solution"));
1728:       PetscCall(VecViewFromOptions(v, NULL, "-exact_vec_view"));
1729:       PetscCall(DMRestoreGlobalVector(dm, &v));
1730:     }
1731:     PetscCall(PetscFree2(exactFuncs, ctxs));
1732:   }
1733:   PetscFunctionReturn(PETSC_SUCCESS);
1734: }

1736: /*@C
1737:   TSMonitorLGSNESIterations - Monitors the number of nonlinear (`SNES`) iterations used per time step in a line-graph plot

1739:   Collective

1741:   Input Parameters:
1742: + ts     - the `TS` context
1743: . n      - iteration number (a negative value indicates an interpolated solution and is ignored)
1744: . ptime  - current time
1745: . v      - current solution
1746: - monctx - the `TSMonitorLGCtx` object that contains all the options for the monitoring, created with `TSMonitorLGCtxCreate()`

1748:   Level: intermediate

1750:   Note:
1751:   This is not called directly by users; pass this function to `TSMonitorSet()` along with the context created by `TSMonitorLGCtxCreate()` and `TSMonitorLGCtxDestroy()`.

1753: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorLGCtxCreate()`, `TSMonitorLGKSPIterations()`
1754: @*/
1755: PetscErrorCode TSMonitorLGSNESIterations(TS ts, PetscInt n, PetscReal ptime, Vec v, PetscCtx monctx)
1756: {
1757:   TSMonitorLGCtx ctx = (TSMonitorLGCtx)monctx;
1758:   PetscReal      x   = ptime, y;
1759:   PetscInt       its;

1761:   PetscFunctionBegin;
1762:   if (n < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
1763:   if (!n) {
1764:     PetscDrawAxis axis;
1765:     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
1766:     PetscCall(PetscDrawAxisSetLabels(axis, "Nonlinear iterations as function of time", "Time", "SNES Iterations"));
1767:     PetscCall(PetscDrawLGReset(ctx->lg));
1768:     ctx->snes_its = 0;
1769:   }
1770:   PetscCall(TSGetSNESIterations(ts, &its));
1771:   y = its - ctx->snes_its;
1772:   PetscCall(PetscDrawLGAddPoint(ctx->lg, &x, &y));
1773:   if (((ctx->howoften > 0) && (!(n % ctx->howoften)) && (n > -1)) || ((ctx->howoften == -1) && (n == -1))) {
1774:     PetscCall(PetscDrawLGDraw(ctx->lg));
1775:     PetscCall(PetscDrawLGSave(ctx->lg));
1776:   }
1777:   ctx->snes_its = its;
1778:   PetscFunctionReturn(PETSC_SUCCESS);
1779: }

1781: /*@C
1782:   TSMonitorLGKSPIterations - Monitors the number of linear (`KSP`) iterations used per time step in a line-graph plot

1784:   Collective

1786:   Input Parameters:
1787: + ts     - the `TS` context
1788: . n      - iteration number (a negative value indicates an interpolated solution and is ignored)
1789: . ptime  - current time
1790: . v      - current solution
1791: - monctx - the `TSMonitorLGCtx` object that contains all the options for the monitoring, created with `TSMonitorLGCtxCreate()`

1793:   Level: intermediate

1795:   Note:
1796:   This is not called directly by users; pass this function to `TSMonitorSet()` along with the context created by `TSMonitorLGCtxCreate()` and `TSMonitorLGCtxDestroy()`.

1798: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorLGCtxCreate()`, `TSMonitorLGSNESIterations()`
1799: @*/
1800: PetscErrorCode TSMonitorLGKSPIterations(TS ts, PetscInt n, PetscReal ptime, Vec v, PetscCtx monctx)
1801: {
1802:   TSMonitorLGCtx ctx = (TSMonitorLGCtx)monctx;
1803:   PetscReal      x   = ptime, y;
1804:   PetscInt       its;

1806:   PetscFunctionBegin;
1807:   if (n < 0) PetscFunctionReturn(PETSC_SUCCESS); /* -1 indicates interpolated solution */
1808:   if (!n) {
1809:     PetscDrawAxis axis;
1810:     PetscCall(PetscDrawLGGetAxis(ctx->lg, &axis));
1811:     PetscCall(PetscDrawAxisSetLabels(axis, "Linear iterations as function of time", "Time", "KSP Iterations"));
1812:     PetscCall(PetscDrawLGReset(ctx->lg));
1813:     ctx->ksp_its = 0;
1814:   }
1815:   PetscCall(TSGetKSPIterations(ts, &its));
1816:   y = its - ctx->ksp_its;
1817:   PetscCall(PetscDrawLGAddPoint(ctx->lg, &x, &y));
1818:   if (((ctx->howoften > 0) && (!(n % ctx->howoften)) && (n > -1)) || ((ctx->howoften == -1) && (n == -1))) {
1819:     PetscCall(PetscDrawLGDraw(ctx->lg));
1820:     PetscCall(PetscDrawLGSave(ctx->lg));
1821:   }
1822:   ctx->ksp_its = its;
1823:   PetscFunctionReturn(PETSC_SUCCESS);
1824: }

1826: /*@C
1827:   TSMonitorEnvelopeCtxCreate - Creates a context for use with `TSMonitorEnvelope()`

1829:   Collective

1831:   Input Parameter:
1832: . ts - the `TS` solver object

1834:   Output Parameter:
1835: . ctx - the context

1837:   Level: intermediate

1839: .seealso: [](ch_ts), `TS`, `TSMonitorLGTimeStep()`, `TSMonitorSet()`, `TSMonitorLGSolution()`, `TSMonitorLGError()`
1840: @*/
1841: PetscErrorCode TSMonitorEnvelopeCtxCreate(TS ts, TSMonitorEnvelopeCtx *ctx)
1842: {
1843:   PetscFunctionBegin;
1844:   PetscCall(PetscNew(ctx));
1845:   PetscFunctionReturn(PETSC_SUCCESS);
1846: }

1848: /*@C
1849:   TSMonitorEnvelope - Monitors the maximum and minimum value of each component of the solution

1851:   Collective

1853:   Input Parameters:
1854: + ts    - the `TS` context
1855: . step  - current time-step
1856: . ptime - current time
1857: . u     - current solution
1858: - dctx  - the envelope context

1860:   Options Database Key:
1861: . -ts_monitor_envelope - determine maximum and minimum value of each component of the solution over the solution time

1863:   Level: intermediate

1865:   Notes:
1866:   After a solve you can use `TSMonitorEnvelopeGetBounds()` to access the envelope

1868:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1869:   to be used during the `TS` integration.

1871: .seealso: [](ch_ts), `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorEnvelopeGetBounds()`, `TSMonitorEnvelopeCtxCreate()`
1872: @*/
1873: PetscErrorCode TSMonitorEnvelope(TS ts, PetscInt step, PetscReal ptime, Vec u, PetscCtx dctx)
1874: {
1875:   TSMonitorEnvelopeCtx ctx = (TSMonitorEnvelopeCtx)dctx;

1877:   PetscFunctionBegin;
1878:   if (!ctx->max) {
1879:     PetscCall(VecDuplicate(u, &ctx->max));
1880:     PetscCall(VecDuplicate(u, &ctx->min));
1881:     PetscCall(VecCopy(u, ctx->max));
1882:     PetscCall(VecCopy(u, ctx->min));
1883:   } else {
1884:     PetscCall(VecPointwiseMax(ctx->max, u, ctx->max));
1885:     PetscCall(VecPointwiseMin(ctx->min, u, ctx->min));
1886:   }
1887:   PetscFunctionReturn(PETSC_SUCCESS);
1888: }

1890: /*@C
1891:   TSMonitorEnvelopeGetBounds - Gets the bounds for the components of the solution

1893:   Collective

1895:   Input Parameter:
1896: . ts - the `TS` context

1898:   Output Parameters:
1899: + max - the maximum values
1900: - min - the minimum values

1902:   Level: intermediate

1904:   Notes:
1905:   If the `TS` does not have a `TSMonitorEnvelopeCtx` associated with it then this function is ignored

1907: .seealso: [](ch_ts), `TSMonitorEnvelopeCtx`, `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `VecView()`, `TSMonitorLGSetDisplayVariables()`
1908: @*/
1909: PetscErrorCode TSMonitorEnvelopeGetBounds(TS ts, Vec *max, Vec *min)
1910: {
1911:   PetscInt i;

1913:   PetscFunctionBegin;
1914:   if (max) *max = NULL;
1915:   if (min) *min = NULL;
1916:   for (i = 0; i < ts->numbermonitors; i++) {
1917:     if (ts->monitor[i] == TSMonitorEnvelope) {
1918:       TSMonitorEnvelopeCtx ctx = (TSMonitorEnvelopeCtx)ts->monitorcontext[i];
1919:       if (max) *max = ctx->max;
1920:       if (min) *min = ctx->min;
1921:       break;
1922:     }
1923:   }
1924:   PetscFunctionReturn(PETSC_SUCCESS);
1925: }

1927: /*@C
1928:   TSMonitorEnvelopeCtxDestroy - Destroys a context that was created  with `TSMonitorEnvelopeCtxCreate()`.

1930:   Collective

1932:   Input Parameter:
1933: . ctx - the monitor context

1935:   Level: intermediate

1937: .seealso: [](ch_ts), `TS`, `TSMonitorLGCtxCreate()`, `TSMonitorSet()`, `TSMonitorLGTimeStep()`
1938: @*/
1939: PetscErrorCode TSMonitorEnvelopeCtxDestroy(TSMonitorEnvelopeCtx *ctx)
1940: {
1941:   PetscFunctionBegin;
1942:   PetscCall(VecDestroy(&(*ctx)->min));
1943:   PetscCall(VecDestroy(&(*ctx)->max));
1944:   PetscCall(PetscFree(*ctx));
1945:   PetscFunctionReturn(PETSC_SUCCESS);
1946: }

1948: /*@C
1949:   TSDMSwarmMonitorMoments - Monitors the first three moments of a `DMSWARM` being evolved by the `TS`

1951:   Not Collective

1953:   Input Parameters:
1954: + ts   - the `TS` context
1955: . step - current timestep
1956: . t    - current time
1957: . U    - current solution
1958: - vf   - not used

1960:   Options Database Key:
1961: + -ts_dmswarm_monitor_moments          - Monitor moments of particle distribution
1962: - -ts_dmswarm_monitor_moments_interval - Interval of timesteps between monitor outputs

1964:   Level: intermediate

1966:   Notes:
1967:   This requires a `DMSWARM` be attached to the `TS`.

1969:   This is not called directly by users, rather one calls `TSMonitorSet()`, with this function as an argument, to cause the monitor
1970:   to be used during the TS integration.

1972: .seealso: [](ch_ts), `TS`, `TSMonitorSet()`, `TSMonitorDefault()`, `DMSWARM`
1973: @*/
1974: PetscErrorCode TSDMSwarmMonitorMoments(TS ts, PetscInt step, PetscReal t, Vec U, PetscViewerAndFormat *vf)
1975: {
1976:   DM                 sw;
1977:   const PetscScalar *u;
1978:   PetscReal          m = 1.0, totE = 0., totMom[3] = {0., 0., 0.};
1979:   PetscInt           dim, d, Np, p;
1980:   MPI_Comm           comm;

1982:   PetscFunctionBeginUser;
1983:   (void)t;
1984:   (void)vf;
1985:   PetscCall(TSGetDM(ts, &sw));
1986:   if (!sw || step % vf->view_interval != 0) PetscFunctionReturn(PETSC_SUCCESS);
1987:   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
1988:   PetscCall(DMGetDimension(sw, &dim));
1989:   PetscCall(VecGetLocalSize(U, &Np));
1990:   Np /= dim;
1991:   PetscCall(VecGetArrayRead(U, &u));
1992:   for (p = 0; p < Np; ++p) {
1993:     for (d = 0; d < dim; ++d) {
1994:       totE += PetscRealPart(u[p * dim + d] * u[p * dim + d]);
1995:       totMom[d] += PetscRealPart(u[p * dim + d]);
1996:     }
1997:   }
1998:   PetscCall(VecRestoreArrayRead(U, &u));
1999:   for (d = 0; d < dim; ++d) totMom[d] *= m;
2000:   totE *= 0.5 * m;
2001:   PetscCall(PetscPrintf(comm, "Step %4" PetscInt_FMT " Total Energy: %10.8lf", step, (double)totE));
2002:   for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(comm, "    Total Momentum %c: %10.8lf", (char)('x' + d), (double)totMom[d]));
2003:   PetscCall(PetscPrintf(comm, "\n"));
2004:   PetscFunctionReturn(PETSC_SUCCESS);
2005: }