xref: /petsc/src/ts/trajectory/impls/memory/trajmemory.c (revision bfe80ac4a46d58cb7760074b25f5e81b2f541d8a)
1 #include <petsc/private/tsimpl.h> /*I "petscts.h"  I*/
2 #include <petscsys.h>
3 #if defined(PETSC_HAVE_REVOLVE)
4   #include <revolve_c.h>
5 
6   /* Limit Revolve to 32-bits */
7   #define PETSC_REVOLVE_INT_MAX 2147483647
8 
9 typedef int PetscRevolveInt;
10 
11 static inline PetscErrorCode PetscRevolveIntCast(PetscInt a, PetscRevolveInt *b)
12 {
13   PetscFunctionBegin;
14   #if defined(PETSC_USE_64BIT_INDICES)
15   *b = 0;
16   PetscCheck(a <= PETSC_REVOLVE_INT_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parameter is too large for Revolve, which is restricted to 32-bit integers");
17   #endif
18   *b = (PetscRevolveInt)a;
19   PetscFunctionReturn(PETSC_SUCCESS);
20 }
21 #endif
22 #if defined(PETSC_HAVE_CAMS)
23   #include <offline_schedule.h>
24 #endif
25 
26 PetscLogEvent         TSTrajectory_DiskWrite, TSTrajectory_DiskRead;
27 static PetscErrorCode TSTrajectorySet_Memory(TSTrajectory, TS, PetscInt, PetscReal, Vec);
28 
29 typedef enum {
30   NONE,
31   TWO_LEVEL_NOREVOLVE,
32   TWO_LEVEL_REVOLVE,
33   TWO_LEVEL_TWO_REVOLVE,
34   REVOLVE_OFFLINE,
35   REVOLVE_ONLINE,
36   REVOLVE_MULTISTAGE,
37   CAMS_OFFLINE
38 } SchedulerType;
39 
40 typedef enum {
41   UNSET           = -1,
42   SOLUTIONONLY    = 0,
43   STAGESONLY      = 1,
44   SOLUTION_STAGES = 2
45 } CheckpointType;
46 
47 const char *const TSTrajectoryMemoryTypes[] = {"REVOLVE", "CAMS", "PETSC", "TSTrajectoryMemoryType", "TJ_", NULL};
48 
49 #define HaveSolution(m) ((m) == SOLUTIONONLY || (m) == SOLUTION_STAGES)
50 #define HaveStages(m)   ((m) == STAGESONLY || (m) == SOLUTION_STAGES)
51 
52 typedef struct _StackElement {
53   PetscInt       stepnum;
54   Vec            X;
55   Vec           *Y;
56   PetscReal      time;
57   PetscReal      timeprev; /* for no solution_only mode */
58   PetscReal      timenext; /* for solution_only mode */
59   CheckpointType cptype;
60 } *StackElement;
61 
62 #if defined(PETSC_HAVE_REVOLVE)
63 typedef struct _RevolveCTX {
64   PetscBool       reverseonestep;
65   PetscRevolveInt where;
66   PetscRevolveInt snaps_in;
67   PetscRevolveInt stepsleft;
68   PetscRevolveInt check;
69   PetscRevolveInt oldcapo;
70   PetscRevolveInt capo;
71   PetscRevolveInt fine;
72   PetscRevolveInt info;
73 } RevolveCTX;
74 #endif
75 
76 #if defined(PETSC_HAVE_CAMS)
77 typedef struct _CAMSCTX {
78   PetscInt lastcheckpointstep;
79   PetscInt lastcheckpointtype;
80   PetscInt num_units_avail;
81   PetscInt endstep;
82   PetscInt num_stages;
83   PetscInt nextcheckpointstep;
84   PetscInt nextcheckpointtype; /* (0) solution only (1) stages (2) solution+stages */
85   PetscInt info;
86 } CAMSCTX;
87 #endif
88 
89 typedef struct _Stack {
90   PetscInt      stacksize;
91   PetscInt      top;
92   StackElement *container;
93   PetscInt      nallocated;
94   PetscInt      numY;
95   PetscBool     solution_only;
96   PetscBool     use_dram;
97 } Stack;
98 
99 typedef struct _DiskStack {
100   PetscInt  stacksize;
101   PetscInt  top;
102   PetscInt *container;
103 } DiskStack;
104 
105 typedef struct _TJScheduler {
106   SchedulerType          stype;
107   TSTrajectoryMemoryType tj_memory_type;
108 #if defined(PETSC_HAVE_REVOLVE)
109   RevolveCTX *rctx, *rctx2;
110   PetscBool   use_online;
111   PetscInt    store_stride;
112 #endif
113 #if defined(PETSC_HAVE_CAMS)
114   CAMSCTX *actx;
115 #endif
116   PetscBool   recompute;
117   PetscBool   skip_trajectory;
118   PetscBool   save_stack;
119   PetscInt    max_units_ram;  /* maximum checkpointing units in RAM */
120   PetscInt    max_units_disk; /* maximum checkpointing units on disk */
121   PetscInt    max_cps_ram;    /* maximum checkpoints in RAM */
122   PetscInt    max_cps_disk;   /* maximum checkpoints on disk */
123   PetscInt    stride;
124   PetscInt    total_steps; /* total number of steps */
125   Stack       stack;
126   DiskStack   diskstack;
127   PetscViewer viewer;
128 } TJScheduler;
129 
130 static PetscErrorCode TurnForwardWithStepsize(TS ts, PetscReal nextstepsize)
131 {
132   PetscFunctionBegin;
133   /* reverse the direction */
134   PetscCall(TSSetTimeStep(ts, nextstepsize));
135   PetscFunctionReturn(PETSC_SUCCESS);
136 }
137 
138 static PetscErrorCode TurnForward(TS ts)
139 {
140   PetscReal stepsize;
141 
142   PetscFunctionBegin;
143   /* reverse the direction */
144   PetscCall(TSGetTimeStep(ts, &stepsize));
145   PetscCall(TSSetTimeStep(ts, -stepsize));
146   PetscFunctionReturn(PETSC_SUCCESS);
147 }
148 
149 static PetscErrorCode TurnBackward(TS ts)
150 {
151   PetscReal stepsize;
152 
153   PetscFunctionBegin;
154   if (!ts->trajectory->adjoint_solve_mode) PetscFunctionReturn(PETSC_SUCCESS);
155   /* reverse the direction */
156   stepsize = ts->ptime_prev - ts->ptime;
157   PetscCall(TSSetTimeStep(ts, stepsize));
158   PetscFunctionReturn(PETSC_SUCCESS);
159 }
160 
161 static PetscErrorCode ElementCreate(TS ts, CheckpointType cptype, Stack *stack, StackElement *e)
162 {
163   Vec  X;
164   Vec *Y;
165 
166   PetscFunctionBegin;
167   if (stack->top < stack->stacksize - 1 && stack->container[stack->top + 1]) {
168     *e = stack->container[stack->top + 1];
169     if (HaveSolution(cptype) && !(*e)->X) {
170       PetscCall(TSGetSolution(ts, &X));
171       PetscCall(VecDuplicate(X, &(*e)->X));
172     }
173     if (cptype == 1 && (*e)->X) PetscCall(VecDestroy(&(*e)->X));
174     if (HaveStages(cptype) && !(*e)->Y) {
175       PetscCall(TSGetStages(ts, &stack->numY, &Y));
176       if (stack->numY) PetscCall(VecDuplicateVecs(Y[0], stack->numY, &(*e)->Y));
177     }
178     if (cptype == 0 && (*e)->Y) PetscCall(VecDestroyVecs(stack->numY, &(*e)->Y));
179     (*e)->cptype = cptype;
180     PetscFunctionReturn(PETSC_SUCCESS);
181   }
182   if (stack->use_dram) PetscCall(PetscMallocSetDRAM());
183   PetscCall(PetscNew(e));
184   if (HaveSolution(cptype)) {
185     PetscCall(TSGetSolution(ts, &X));
186     PetscCall(VecDuplicate(X, &(*e)->X));
187   }
188   if (HaveStages(cptype)) {
189     PetscCall(TSGetStages(ts, &stack->numY, &Y));
190     if (stack->numY) PetscCall(VecDuplicateVecs(Y[0], stack->numY, &(*e)->Y));
191   }
192   if (stack->use_dram) PetscCall(PetscMallocResetDRAM());
193   stack->nallocated++;
194   (*e)->cptype = cptype;
195   PetscFunctionReturn(PETSC_SUCCESS);
196 }
197 
198 static PetscErrorCode ElementSet(TS ts, Stack *stack, StackElement *e, PetscInt stepnum, PetscReal time, Vec X)
199 {
200   Vec      *Y;
201   PetscInt  i;
202   PetscReal timeprev;
203 
204   PetscFunctionBegin;
205   if (HaveSolution((*e)->cptype)) PetscCall(VecCopy(X, (*e)->X));
206   if (HaveStages((*e)->cptype)) {
207     PetscCall(TSGetStages(ts, &stack->numY, &Y));
208     for (i = 0; i < stack->numY; i++) PetscCall(VecCopy(Y[i], (*e)->Y[i]));
209   }
210   (*e)->stepnum = stepnum;
211   (*e)->time    = time;
212   /* for consistency */
213   if (stepnum == 0) {
214     (*e)->timeprev = (*e)->time - ts->time_step;
215   } else {
216     PetscCall(TSGetPrevTime(ts, &timeprev));
217     (*e)->timeprev = timeprev;
218   }
219   PetscFunctionReturn(PETSC_SUCCESS);
220 }
221 
222 static PetscErrorCode ElementDestroy(Stack *stack, StackElement e)
223 {
224   PetscFunctionBegin;
225   if (stack->use_dram) PetscCall(PetscMallocSetDRAM());
226   PetscCall(VecDestroy(&e->X));
227   if (e->Y) PetscCall(VecDestroyVecs(stack->numY, &e->Y));
228   PetscCall(PetscFree(e));
229   if (stack->use_dram) PetscCall(PetscMallocResetDRAM());
230   stack->nallocated--;
231   PetscFunctionReturn(PETSC_SUCCESS);
232 }
233 
234 static PetscErrorCode StackResize(Stack *stack, PetscInt newsize)
235 {
236   StackElement *newcontainer;
237   PetscInt      i;
238 
239   PetscFunctionBegin;
240   PetscCall(PetscCalloc1(newsize * sizeof(StackElement), &newcontainer));
241   for (i = 0; i < stack->stacksize; i++) newcontainer[i] = stack->container[i];
242   PetscCall(PetscFree(stack->container));
243   stack->container = newcontainer;
244   stack->stacksize = newsize;
245   PetscFunctionReturn(PETSC_SUCCESS);
246 }
247 
248 static PetscErrorCode StackPush(Stack *stack, StackElement e)
249 {
250   PetscFunctionBegin;
251   PetscCheck(stack->top + 1 < stack->stacksize, PETSC_COMM_SELF, PETSC_ERR_MEMC, "Maximum stack size (%" PetscInt_FMT ") exceeded", stack->stacksize);
252   stack->container[++stack->top] = e;
253   PetscFunctionReturn(PETSC_SUCCESS);
254 }
255 
256 static PetscErrorCode StackPop(Stack *stack, StackElement *e)
257 {
258   PetscFunctionBegin;
259   *e = NULL;
260   PetscCheck(stack->top != -1, PETSC_COMM_SELF, PETSC_ERR_MEMC, "Empty stack");
261   *e = stack->container[stack->top--];
262   PetscFunctionReturn(PETSC_SUCCESS);
263 }
264 
265 static PetscErrorCode StackTop(Stack *stack, StackElement *e)
266 {
267   PetscFunctionBegin;
268   *e = stack->container[stack->top];
269   PetscFunctionReturn(PETSC_SUCCESS);
270 }
271 
272 static PetscErrorCode StackInit(Stack *stack, PetscInt size, PetscInt ny)
273 {
274   PetscFunctionBegin;
275   stack->top  = -1;
276   stack->numY = ny;
277 
278   if (!stack->container) PetscCall(PetscCalloc1(size, &stack->container));
279   PetscFunctionReturn(PETSC_SUCCESS);
280 }
281 
282 static PetscErrorCode StackDestroy(Stack *stack)
283 {
284   const PetscInt n = stack->nallocated;
285 
286   PetscFunctionBegin;
287   if (!stack->container) PetscFunctionReturn(PETSC_SUCCESS);
288   PetscCheck(stack->top + 1 <= n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Stack size does not match element counter %" PetscInt_FMT, n);
289   for (PetscInt i = 0; i < n; i++) PetscCall(ElementDestroy(stack, stack->container[i]));
290   PetscCall(PetscFree(stack->container));
291   PetscFunctionReturn(PETSC_SUCCESS);
292 }
293 
294 static PetscErrorCode StackFind(Stack *stack, StackElement *e, PetscInt index)
295 {
296   PetscFunctionBegin;
297   *e = NULL;
298   PetscCheck(index >= 0 && index <= stack->top, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid index %" PetscInt_FMT, index);
299   *e = stack->container[index];
300   PetscFunctionReturn(PETSC_SUCCESS);
301 }
302 
303 static PetscErrorCode WriteToDisk(PetscBool stifflyaccurate, PetscInt stepnum, PetscReal time, PetscReal timeprev, Vec X, Vec *Y, PetscInt numY, CheckpointType cptype, PetscViewer viewer)
304 {
305   PetscFunctionBegin;
306   PetscCall(PetscViewerBinaryWrite(viewer, &stepnum, 1, PETSC_INT));
307   if (HaveSolution(cptype)) PetscCall(VecView(X, viewer));
308   if (HaveStages(cptype)) {
309     for (PetscInt i = 0; i < numY; i++) {
310       /* For stiffly accurate TS methods, the last stage Y[ns-1] is the same as the solution X, thus does not need to be saved again. */
311       if (stifflyaccurate && i == numY - 1 && HaveSolution(cptype)) continue;
312       PetscCall(VecView(Y[i], viewer));
313     }
314   }
315   PetscCall(PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL));
316   PetscCall(PetscViewerBinaryWrite(viewer, &timeprev, 1, PETSC_REAL));
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 static PetscErrorCode ReadFromDisk(PetscBool stifflyaccurate, PetscInt *stepnum, PetscReal *time, PetscReal *timeprev, Vec X, Vec *Y, PetscInt numY, CheckpointType cptype, PetscViewer viewer)
321 {
322   PetscFunctionBegin;
323   PetscCall(PetscViewerBinaryRead(viewer, stepnum, 1, NULL, PETSC_INT));
324   if (HaveSolution(cptype)) PetscCall(VecLoad(X, viewer));
325   if (HaveStages(cptype)) {
326     for (PetscInt i = 0; i < numY; i++) {
327       /* For stiffly accurate TS methods, the last stage Y[ns-1] is the same as the solution X, thus does not need to be loaded again. */
328       if (stifflyaccurate && i == numY - 1 && HaveSolution(cptype)) continue;
329       PetscCall(VecLoad(Y[i], viewer));
330     }
331   }
332   PetscCall(PetscViewerBinaryRead(viewer, time, 1, NULL, PETSC_REAL));
333   PetscCall(PetscViewerBinaryRead(viewer, timeprev, 1, NULL, PETSC_REAL));
334   PetscFunctionReturn(PETSC_SUCCESS);
335 }
336 
337 static PetscErrorCode StackDumpAll(TSTrajectory tj, TS ts, Stack *stack, PetscInt id)
338 {
339   Vec         *Y;
340   PetscInt     ndumped, cptype_int;
341   StackElement e     = NULL;
342   TJScheduler *tjsch = (TJScheduler *)tj->data;
343   char         filename[PETSC_MAX_PATH_LEN];
344   MPI_Comm     comm;
345 
346   PetscFunctionBegin;
347   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
348   if (tj->monitor) {
349     PetscCall(PetscViewerASCIIPushTab(tj->monitor));
350     PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Dump stack id %" PetscInt_FMT " to file\n", id));
351     PetscCall(PetscViewerASCIIPopTab(tj->monitor));
352   }
353   PetscCall(PetscSNPrintf(filename, sizeof(filename), "%s/TS-STACK%06" PetscInt_FMT ".bin", tj->dirname, id));
354   PetscCall(PetscViewerFileSetName(tjsch->viewer, filename));
355   PetscCall(PetscViewerSetUp(tjsch->viewer));
356   ndumped = stack->top + 1;
357   PetscCall(PetscViewerBinaryWrite(tjsch->viewer, &ndumped, 1, PETSC_INT));
358   for (PetscInt i = 0; i < ndumped; i++) {
359     e          = stack->container[i];
360     cptype_int = (PetscInt)e->cptype;
361     PetscCall(PetscViewerBinaryWrite(tjsch->viewer, &cptype_int, 1, PETSC_INT));
362     PetscCall(PetscLogEventBegin(TSTrajectory_DiskWrite, tj, ts, 0, 0));
363     PetscCall(WriteToDisk(ts->stifflyaccurate, e->stepnum, e->time, e->timeprev, e->X, e->Y, stack->numY, e->cptype, tjsch->viewer));
364     PetscCall(PetscLogEventEnd(TSTrajectory_DiskWrite, tj, ts, 0, 0));
365     ts->trajectory->diskwrites++;
366     PetscCall(StackPop(stack, &e));
367   }
368   /* save the last step for restart, the last step is in memory when using single level schemes, but not necessarily the case for multi level schemes */
369   PetscCall(TSGetStages(ts, &stack->numY, &Y));
370   PetscCall(PetscLogEventBegin(TSTrajectory_DiskWrite, tj, ts, 0, 0));
371   PetscCall(WriteToDisk(ts->stifflyaccurate, ts->steps, ts->ptime, ts->ptime_prev, ts->vec_sol, Y, stack->numY, SOLUTION_STAGES, tjsch->viewer));
372   PetscCall(PetscLogEventEnd(TSTrajectory_DiskWrite, tj, ts, 0, 0));
373   ts->trajectory->diskwrites++;
374   PetscFunctionReturn(PETSC_SUCCESS);
375 }
376 
377 static PetscErrorCode StackLoadAll(TSTrajectory tj, TS ts, Stack *stack, PetscInt id)
378 {
379   Vec         *Y;
380   PetscInt     i, nloaded, cptype_int;
381   StackElement e;
382   PetscViewer  viewer;
383   char         filename[PETSC_MAX_PATH_LEN];
384 
385   PetscFunctionBegin;
386   if (tj->monitor) {
387     PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
388     PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Load stack from file\n"));
389     PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
390   }
391   PetscCall(PetscSNPrintf(filename, sizeof filename, "%s/TS-STACK%06" PetscInt_FMT ".bin", tj->dirname, id));
392   PetscCall(PetscViewerBinaryOpen(PetscObjectComm((PetscObject)tj), filename, FILE_MODE_READ, &viewer));
393   PetscCall(PetscViewerBinarySetSkipInfo(viewer, PETSC_TRUE));
394   PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE));
395   PetscCall(PetscViewerBinaryRead(viewer, &nloaded, 1, NULL, PETSC_INT));
396   for (i = 0; i < nloaded; i++) {
397     PetscCall(PetscViewerBinaryRead(viewer, &cptype_int, 1, NULL, PETSC_INT));
398     PetscCall(ElementCreate(ts, (CheckpointType)cptype_int, stack, &e));
399     PetscCall(StackPush(stack, e));
400     PetscCall(PetscLogEventBegin(TSTrajectory_DiskRead, tj, ts, 0, 0));
401     PetscCall(ReadFromDisk(ts->stifflyaccurate, &e->stepnum, &e->time, &e->timeprev, e->X, e->Y, stack->numY, e->cptype, viewer));
402     PetscCall(PetscLogEventEnd(TSTrajectory_DiskRead, tj, ts, 0, 0));
403     ts->trajectory->diskreads++;
404   }
405   /* load the last step into TS */
406   PetscCall(TSGetStages(ts, &stack->numY, &Y));
407   PetscCall(PetscLogEventBegin(TSTrajectory_DiskRead, tj, ts, 0, 0));
408   PetscCall(ReadFromDisk(ts->stifflyaccurate, &ts->steps, &ts->ptime, &ts->ptime_prev, ts->vec_sol, Y, stack->numY, SOLUTION_STAGES, viewer));
409   PetscCall(PetscLogEventEnd(TSTrajectory_DiskRead, tj, ts, 0, 0));
410   ts->trajectory->diskreads++;
411   PetscCall(TurnBackward(ts));
412   PetscCall(PetscViewerDestroy(&viewer));
413   PetscFunctionReturn(PETSC_SUCCESS);
414 }
415 
416 #if defined(PETSC_HAVE_REVOLVE)
417 static PetscErrorCode StackLoadLast(TSTrajectory tj, TS ts, Stack *stack, PetscInt id)
418 {
419   Vec        *Y;
420   PetscInt    size;
421   PetscViewer viewer;
422   char        filename[PETSC_MAX_PATH_LEN];
423   #if defined(PETSC_HAVE_MPIIO)
424   PetscBool usempiio;
425   #endif
426   int   fd;
427   off_t off, offset;
428 
429   PetscFunctionBegin;
430   if (tj->monitor) {
431     PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
432     PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Load last stack element from file\n"));
433     PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
434   }
435   PetscCall(TSGetStages(ts, &stack->numY, &Y));
436   PetscCall(VecGetSize(Y[0], &size));
437   /* VecView writes to file two extra int's for class id and number of rows */
438   off = -((stack->solution_only ? 0 : stack->numY) + 1) * (size * PETSC_BINARY_SCALAR_SIZE + 2 * PETSC_BINARY_INT_SIZE) - PETSC_BINARY_INT_SIZE - 2 * PETSC_BINARY_SCALAR_SIZE;
439 
440   PetscCall(PetscSNPrintf(filename, sizeof filename, "%s/TS-STACK%06" PetscInt_FMT ".bin", tj->dirname, id));
441   PetscCall(PetscViewerBinaryOpen(PetscObjectComm((PetscObject)tj), filename, FILE_MODE_READ, &viewer));
442   PetscCall(PetscViewerBinarySetSkipInfo(viewer, PETSC_TRUE));
443   PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE));
444   #if defined(PETSC_HAVE_MPIIO)
445   PetscCall(PetscViewerBinaryGetUseMPIIO(viewer, &usempiio));
446   if (usempiio) {
447     PetscCall(PetscViewerBinaryGetMPIIODescriptor(viewer, (MPI_File *)&fd));
448     PetscCall(PetscBinarySynchronizedSeek(PetscObjectComm((PetscObject)tj), fd, off, PETSC_BINARY_SEEK_END, &offset));
449   } else {
450   #endif
451     PetscCall(PetscViewerBinaryGetDescriptor(viewer, &fd));
452     PetscCall(PetscBinarySeek(fd, off, PETSC_BINARY_SEEK_END, &offset));
453   #if defined(PETSC_HAVE_MPIIO)
454   }
455   #endif
456   /* load the last step into TS */
457   PetscCall(PetscLogEventBegin(TSTrajectory_DiskRead, tj, ts, 0, 0));
458   PetscCall(ReadFromDisk(ts->stifflyaccurate, &ts->steps, &ts->ptime, &ts->ptime_prev, ts->vec_sol, Y, stack->numY, SOLUTION_STAGES, viewer));
459   PetscCall(PetscLogEventEnd(TSTrajectory_DiskRead, tj, ts, 0, 0));
460   ts->trajectory->diskreads++;
461   PetscCall(PetscViewerDestroy(&viewer));
462   PetscCall(TurnBackward(ts));
463   PetscFunctionReturn(PETSC_SUCCESS);
464 }
465 #endif
466 
467 static PetscErrorCode DumpSingle(TSTrajectory tj, TS ts, Stack *stack, PetscInt id)
468 {
469   Vec         *Y;
470   PetscInt     stepnum;
471   TJScheduler *tjsch = (TJScheduler *)tj->data;
472   char         filename[PETSC_MAX_PATH_LEN];
473   MPI_Comm     comm;
474 
475   PetscFunctionBegin;
476   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
477   if (tj->monitor) {
478     PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
479     PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Dump a single point from file\n"));
480     PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
481   }
482   PetscCall(TSGetStepNumber(ts, &stepnum));
483   PetscCall(PetscSNPrintf(filename, sizeof(filename), "%s/TS-CPS%06" PetscInt_FMT ".bin", tj->dirname, id));
484   PetscCall(PetscViewerFileSetName(tjsch->viewer, filename));
485   PetscCall(PetscViewerSetUp(tjsch->viewer));
486 
487   PetscCall(TSGetStages(ts, &stack->numY, &Y));
488   PetscCall(PetscLogEventBegin(TSTrajectory_DiskWrite, tj, ts, 0, 0));
489   PetscCall(WriteToDisk(ts->stifflyaccurate, stepnum, ts->ptime, ts->ptime_prev, ts->vec_sol, Y, stack->numY, SOLUTION_STAGES, tjsch->viewer));
490   PetscCall(PetscLogEventEnd(TSTrajectory_DiskWrite, tj, ts, 0, 0));
491   ts->trajectory->diskwrites++;
492   PetscFunctionReturn(PETSC_SUCCESS);
493 }
494 
495 static PetscErrorCode LoadSingle(TSTrajectory tj, TS ts, Stack *stack, PetscInt id)
496 {
497   Vec        *Y;
498   PetscViewer viewer;
499   char        filename[PETSC_MAX_PATH_LEN];
500 
501   PetscFunctionBegin;
502   if (tj->monitor) {
503     PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
504     PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Load a single point from file\n"));
505     PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
506   }
507   PetscCall(PetscSNPrintf(filename, sizeof filename, "%s/TS-CPS%06" PetscInt_FMT ".bin", tj->dirname, id));
508   PetscCall(PetscViewerBinaryOpen(PetscObjectComm((PetscObject)tj), filename, FILE_MODE_READ, &viewer));
509   PetscCall(PetscViewerBinarySetSkipInfo(viewer, PETSC_TRUE));
510   PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE));
511   PetscCall(TSGetStages(ts, &stack->numY, &Y));
512   PetscCall(PetscLogEventBegin(TSTrajectory_DiskRead, tj, ts, 0, 0));
513   PetscCall(ReadFromDisk(ts->stifflyaccurate, &ts->steps, &ts->ptime, &ts->ptime_prev, ts->vec_sol, Y, stack->numY, SOLUTION_STAGES, viewer));
514   PetscCall(PetscLogEventEnd(TSTrajectory_DiskRead, tj, ts, 0, 0));
515   ts->trajectory->diskreads++;
516   PetscCall(PetscViewerDestroy(&viewer));
517   PetscFunctionReturn(PETSC_SUCCESS);
518 }
519 
520 static PetscErrorCode UpdateTS(TS ts, Stack *stack, StackElement e, PetscInt stepnum, PetscBool adjoint_mode)
521 {
522   Vec     *Y;
523   PetscInt i;
524 
525   PetscFunctionBegin;
526   /* In adjoint mode we do not need to copy solution if the stepnum is the same */
527   if (!adjoint_mode || (HaveSolution(e->cptype) && e->stepnum != stepnum)) PetscCall(VecCopy(e->X, ts->vec_sol));
528   if (HaveStages(e->cptype)) {
529     PetscCall(TSGetStages(ts, &stack->numY, &Y));
530     if (e->stepnum && e->stepnum == stepnum) {
531       for (i = 0; i < stack->numY; i++) PetscCall(VecCopy(e->Y[i], Y[i]));
532     } else if (ts->stifflyaccurate) {
533       PetscCall(VecCopy(e->Y[stack->numY - 1], ts->vec_sol));
534     }
535   }
536   if (adjoint_mode) {
537     PetscCall(TSSetTimeStep(ts, e->timeprev - e->time)); /* stepsize will be negative */
538   } else {
539     PetscCall(TSSetTimeStep(ts, e->time - e->timeprev)); /* stepsize will be positive */
540   }
541   ts->ptime       = e->time;
542   ts->ptime_prev  = e->timeprev;
543   ts->steprestart = PETSC_TRUE; /* prevent methods with FSAL using information from the previous time step which is not available when current checkpoint is restored */
544   PetscFunctionReturn(PETSC_SUCCESS);
545 }
546 
547 static PetscErrorCode ReCompute(TS ts, TJScheduler *tjsch, PetscInt stepnumbegin, PetscInt stepnumend)
548 {
549   Stack   *stack = &tjsch->stack;
550   PetscInt i;
551 
552   PetscFunctionBegin;
553   tjsch->recompute = PETSC_TRUE;                           /* hints TSTrajectorySet() that it is in recompute mode */
554   PetscCall(TSSetStepNumber(ts, stepnumbegin));            /* global step number */
555   for (i = stepnumbegin; i < stepnumend; i++) {            /* assume fixed step size */
556     if (stack->solution_only && !tjsch->skip_trajectory) { /* revolve online need this */
557       /* don't use the public interface as it will update the TSHistory: this need a better fix */
558       PetscCall(TSTrajectorySet_Memory(ts->trajectory, ts, ts->steps, ts->ptime, ts->vec_sol));
559     }
560     PetscCall(TSMonitor(ts, ts->steps, ts->ptime, ts->vec_sol));
561     PetscCall(TSStep(ts));
562     if (!stack->solution_only && !tjsch->skip_trajectory) {
563       /* don't use the public interface as it will update the TSHistory: this need a better fix */
564       PetscCall(TSTrajectorySet_Memory(ts->trajectory, ts, ts->steps, ts->ptime, ts->vec_sol));
565     }
566     PetscCall(TSEventHandler(ts));
567     if (!ts->steprollback) PetscCall(TSPostStep(ts));
568   }
569   PetscCall(TurnBackward(ts));
570   ts->trajectory->recomps += stepnumend - stepnumbegin; /* recomputation counter */
571   PetscCall(TSSetStepNumber(ts, stepnumend));
572   tjsch->recompute = PETSC_FALSE; /* reset the flag for recompute mode */
573   PetscFunctionReturn(PETSC_SUCCESS);
574 }
575 
576 static PetscErrorCode TopLevelStore(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscInt localstepnum, PetscInt laststridesize, PetscBool *done)
577 {
578   Stack     *stack     = &tjsch->stack;
579   DiskStack *diskstack = &tjsch->diskstack;
580   PetscInt   stridenum;
581 
582   PetscFunctionBegin;
583   *done     = PETSC_FALSE;
584   stridenum = stepnum / tjsch->stride;
585   /* make sure saved checkpoint id starts from 1
586      skip last stride when using stridenum+1
587      skip first stride when using stridenum */
588   if (stack->solution_only) {
589     if (tjsch->save_stack) {
590       if (localstepnum == tjsch->stride - 1 && stepnum < tjsch->total_steps - laststridesize) { /* current step will be saved without going through stack */
591         PetscCall(StackDumpAll(tj, ts, stack, stridenum + 1));
592         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum + 1;
593         *done = PETSC_TRUE;
594       }
595     } else {
596       if (localstepnum == 0 && stepnum < tjsch->total_steps - laststridesize) {
597         PetscCall(DumpSingle(tj, ts, stack, stridenum + 1));
598         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum + 1;
599         *done = PETSC_TRUE;
600       }
601     }
602   } else {
603     if (tjsch->save_stack) {
604       if (localstepnum == 0 && stepnum < tjsch->total_steps && stepnum != 0) { /* skip the first stride */
605         PetscCall(StackDumpAll(tj, ts, stack, stridenum));
606         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum;
607         *done = PETSC_TRUE;
608       }
609     } else {
610       if (localstepnum == 1 && stepnum < tjsch->total_steps - laststridesize) {
611         PetscCall(DumpSingle(tj, ts, stack, stridenum + 1));
612         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum + 1;
613         *done = PETSC_TRUE;
614       }
615     }
616   }
617   PetscFunctionReturn(PETSC_SUCCESS);
618 }
619 
620 static PetscErrorCode TSTrajectoryMemorySet_N(TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
621 {
622   Stack         *stack = &tjsch->stack;
623   StackElement   e;
624   CheckpointType cptype;
625 
626   PetscFunctionBegin;
627   /* skip the last step */
628   if (ts->reason) { /* only affect the forward run */
629     /* update total_steps in the end of forward run */
630     if (stepnum != tjsch->total_steps) tjsch->total_steps = stepnum;
631     if (stack->solution_only) {
632       /* get rid of the solution at second last step */
633       PetscCall(StackPop(stack, &e));
634     }
635     PetscFunctionReturn(PETSC_SUCCESS);
636   }
637   /*  do not save trajectory at the recompute stage for solution_only mode */
638   if (stack->solution_only && tjsch->recompute) PetscFunctionReturn(PETSC_SUCCESS);
639   /* skip the first step for no_solution_only mode */
640   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);
641 
642   /* resize the stack */
643   if (stack->top + 1 == stack->stacksize) PetscCall(StackResize(stack, 2 * stack->stacksize));
644   /* update timenext for the previous step; necessary for step adaptivity */
645   if (stack->top > -1) {
646     PetscCall(StackTop(stack, &e));
647     e->timenext = ts->ptime;
648   }
649   PetscCheck(stepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
650   cptype = stack->solution_only ? SOLUTIONONLY : STAGESONLY;
651   PetscCall(ElementCreate(ts, cptype, stack, &e));
652   PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
653   PetscCall(StackPush(stack, e));
654   PetscFunctionReturn(PETSC_SUCCESS);
655 }
656 
657 static PetscErrorCode TSTrajectoryMemorySet_N_2(TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
658 {
659   Stack         *stack = &tjsch->stack;
660   StackElement   e;
661   CheckpointType cptype;
662 
663   PetscFunctionBegin;
664   if (stack->top + 1 == stack->stacksize) PetscCall(StackResize(stack, 2 * stack->stacksize));
665   /* update timenext for the previous step; necessary for step adaptivity */
666   if (stack->top > -1) {
667     PetscCall(StackTop(stack, &e));
668     e->timenext = ts->ptime;
669   }
670   PetscCheck(stepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
671   cptype = stack->solution_only ? SOLUTIONONLY : SOLUTION_STAGES; /* Always include solution in a checkpoint in non-adjoint mode */
672   PetscCall(ElementCreate(ts, cptype, stack, &e));
673   PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
674   PetscCall(StackPush(stack, e));
675   PetscFunctionReturn(PETSC_SUCCESS);
676 }
677 
678 static PetscErrorCode TSTrajectoryMemoryGet_N(TS ts, TJScheduler *tjsch, PetscInt stepnum)
679 {
680   Stack       *stack = &tjsch->stack;
681   StackElement e;
682   PetscInt     ns;
683 
684   PetscFunctionBegin;
685   /* If TSTrajectoryGet() is called after TSAdjointSolve() converges (e.g. outside the while loop in TSAdjointSolve()), skip getting the checkpoint. */
686   if (ts->reason) PetscFunctionReturn(PETSC_SUCCESS);
687   if (stepnum == tjsch->total_steps) {
688     PetscCall(TurnBackward(ts));
689     PetscFunctionReturn(PETSC_SUCCESS);
690   }
691   /* restore a checkpoint */
692   PetscCall(StackTop(stack, &e));
693   PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
694   PetscCall(TSGetStages(ts, &ns, PETSC_IGNORE));
695   if (stack->solution_only && ns) { /* recompute one step */
696     PetscCall(TurnForwardWithStepsize(ts, e->timenext - e->time));
697     PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
698   }
699   PetscCall(StackPop(stack, &e));
700   PetscFunctionReturn(PETSC_SUCCESS);
701 }
702 
703 static PetscErrorCode TSTrajectoryMemoryGet_N_2(TS ts, TJScheduler *tjsch, PetscInt stepnum)
704 {
705   Stack       *stack = &tjsch->stack;
706   StackElement e     = NULL;
707 
708   PetscFunctionBegin;
709   PetscCall(StackFind(stack, &e, stepnum));
710   PetscCheck(stepnum == e->stepnum, PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Inconsistent steps! %" PetscInt_FMT " != %" PetscInt_FMT, stepnum, e->stepnum);
711   PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_FALSE));
712   PetscFunctionReturn(PETSC_SUCCESS);
713 }
714 
715 static PetscErrorCode TSTrajectoryMemorySet_TLNR(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
716 {
717   Stack         *stack = &tjsch->stack;
718   PetscInt       localstepnum, laststridesize;
719   StackElement   e;
720   PetscBool      done;
721   CheckpointType cptype;
722 
723   PetscFunctionBegin;
724   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);
725   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(PETSC_SUCCESS);
726   if (tjsch->save_stack && tjsch->recompute) PetscFunctionReturn(PETSC_SUCCESS);
727 
728   localstepnum = stepnum % tjsch->stride;
729   /* (stridesize-1) checkpoints are saved in each stride; an extra point is added by StackDumpAll() */
730   laststridesize = tjsch->total_steps % tjsch->stride;
731   if (!laststridesize) laststridesize = tjsch->stride;
732 
733   if (!tjsch->recompute) {
734     PetscCall(TopLevelStore(tj, ts, tjsch, stepnum, localstepnum, laststridesize, &done));
735     if (!tjsch->save_stack && stepnum < tjsch->total_steps - laststridesize) PetscFunctionReturn(PETSC_SUCCESS);
736   }
737   if (!stack->solution_only && localstepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);                /* skip last point in each stride at recompute stage or last stride */
738   if (stack->solution_only && localstepnum == tjsch->stride - 1) PetscFunctionReturn(PETSC_SUCCESS); /* skip last step in each stride at recompute stage or last stride */
739 
740   cptype = stack->solution_only ? SOLUTIONONLY : STAGESONLY;
741   PetscCall(ElementCreate(ts, cptype, stack, &e));
742   PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
743   PetscCall(StackPush(stack, e));
744   PetscFunctionReturn(PETSC_SUCCESS);
745 }
746 
747 static PetscErrorCode TSTrajectoryMemoryGet_TLNR(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum)
748 {
749   Stack       *stack = &tjsch->stack;
750   PetscInt     id, localstepnum, laststridesize;
751   StackElement e;
752 
753   PetscFunctionBegin;
754   if (stepnum == tjsch->total_steps) {
755     PetscCall(TurnBackward(ts));
756     PetscFunctionReturn(PETSC_SUCCESS);
757   }
758 
759   localstepnum   = stepnum % tjsch->stride;
760   laststridesize = tjsch->total_steps % tjsch->stride;
761   if (!laststridesize) laststridesize = tjsch->stride;
762   if (stack->solution_only) {
763     /* fill stack with info */
764     if (localstepnum == 0 && tjsch->total_steps - stepnum >= laststridesize) {
765       id = stepnum / tjsch->stride;
766       if (tjsch->save_stack) {
767         PetscCall(StackLoadAll(tj, ts, stack, id));
768         tjsch->skip_trajectory = PETSC_TRUE;
769         PetscCall(TurnForward(ts));
770         PetscCall(ReCompute(ts, tjsch, id * tjsch->stride - 1, id * tjsch->stride));
771         tjsch->skip_trajectory = PETSC_FALSE;
772       } else {
773         PetscCall(LoadSingle(tj, ts, stack, id));
774         PetscCall(TurnForward(ts));
775         PetscCall(ReCompute(ts, tjsch, (id - 1) * tjsch->stride, id * tjsch->stride));
776       }
777       PetscFunctionReturn(PETSC_SUCCESS);
778     }
779     /* restore a checkpoint */
780     PetscCall(StackPop(stack, &e));
781     PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
782     tjsch->skip_trajectory = PETSC_TRUE;
783     PetscCall(TurnForward(ts));
784     PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
785     tjsch->skip_trajectory = PETSC_FALSE;
786   } else {
787     CheckpointType cptype = STAGESONLY;
788     /* fill stack with info */
789     if (localstepnum == 0 && tjsch->total_steps - stepnum >= laststridesize) {
790       id = stepnum / tjsch->stride;
791       if (tjsch->save_stack) {
792         PetscCall(StackLoadAll(tj, ts, stack, id));
793       } else {
794         PetscCall(LoadSingle(tj, ts, stack, id));
795         PetscCall(ElementCreate(ts, cptype, stack, &e));
796         PetscCall(ElementSet(ts, stack, &e, (id - 1) * tjsch->stride + 1, ts->ptime, ts->vec_sol));
797         PetscCall(StackPush(stack, e));
798         PetscCall(TurnForward(ts));
799         PetscCall(ReCompute(ts, tjsch, e->stepnum, id * tjsch->stride));
800       }
801       PetscFunctionReturn(PETSC_SUCCESS);
802     }
803     /* restore a checkpoint */
804     PetscCall(StackPop(stack, &e));
805     PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
806   }
807   PetscFunctionReturn(PETSC_SUCCESS);
808 }
809 
810 #if defined(PETSC_HAVE_REVOLVE)
811 static PetscErrorCode printwhattodo(PetscViewer viewer, PetscRevolveInt whattodo, RevolveCTX *rctx, PetscRevolveInt shift)
812 {
813   PetscFunctionBegin;
814   if (!viewer) PetscFunctionReturn(PETSC_SUCCESS);
815 
816   switch (whattodo) {
817   case 1:
818     PetscCall(PetscViewerASCIIPrintf(viewer, "Advance from %d to %d\n", rctx->oldcapo + shift, rctx->capo + shift));
819     break;
820   case 2:
821     PetscCall(PetscViewerASCIIPrintf(viewer, "Store in checkpoint number %d (located in RAM)\n", rctx->check));
822     break;
823   case 3:
824     PetscCall(PetscViewerASCIIPrintf(viewer, "First turn: Initialize adjoints and reverse first step\n"));
825     break;
826   case 4:
827     PetscCall(PetscViewerASCIIPrintf(viewer, "Forward and reverse one step\n"));
828     break;
829   case 5:
830     PetscCall(PetscViewerASCIIPrintf(viewer, "Restore in checkpoint number %d (located in RAM)\n", rctx->check));
831     break;
832   case 7:
833     PetscCall(PetscViewerASCIIPrintf(viewer, "Store in checkpoint number %d (located on disk)\n", rctx->check));
834     break;
835   case 8:
836     PetscCall(PetscViewerASCIIPrintf(viewer, "Restore in checkpoint number %d (located on disk)\n", rctx->check));
837     break;
838   case -1:
839     PetscCall(PetscViewerASCIIPrintf(viewer, "Error!"));
840     break;
841   }
842   PetscFunctionReturn(PETSC_SUCCESS);
843 }
844 
845 static PetscErrorCode printwhattodo2(PetscViewer viewer, PetscRevolveInt whattodo, RevolveCTX *rctx, PetscRevolveInt shift)
846 {
847   PetscFunctionBegin;
848   if (!viewer) PetscFunctionReturn(PETSC_SUCCESS);
849 
850   switch (whattodo) {
851   case 1:
852     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] Advance from stride %d to stride %d\n", rctx->oldcapo + shift, rctx->capo + shift));
853     break;
854   case 2:
855     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] Store in checkpoint number %d\n", rctx->check));
856     break;
857   case 3:
858     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] First turn: Initialize adjoints and reverse first stride\n"));
859     break;
860   case 4:
861     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] Forward and reverse one stride\n"));
862     break;
863   case 5:
864     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] Restore in checkpoint number %d\n", rctx->check));
865     break;
866   case 7:
867     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] Store in top-level checkpoint number %d\n", rctx->check));
868     break;
869   case 8:
870     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] Restore in top-level checkpoint number %d\n", rctx->check));
871     break;
872   case -1:
873     PetscCall(PetscViewerASCIIPrintf(viewer, "[Top Level] Error!"));
874     break;
875   }
876   PetscFunctionReturn(PETSC_SUCCESS);
877 }
878 
879 static PetscErrorCode InitRevolve(PetscInt fine, PetscInt snaps, RevolveCTX *rctx)
880 {
881   PetscRevolveInt rsnaps, rfine;
882 
883   PetscFunctionBegin;
884   PetscCall(PetscRevolveIntCast(snaps, &rsnaps));
885   PetscCall(PetscRevolveIntCast(fine, &rfine));
886   revolve_reset();
887   revolve_create_offline(rfine, rsnaps);
888   rctx->snaps_in       = rsnaps;
889   rctx->fine           = rfine;
890   rctx->check          = 0;
891   rctx->capo           = 0;
892   rctx->reverseonestep = PETSC_FALSE;
893   /* check stepsleft? */
894   PetscFunctionReturn(PETSC_SUCCESS);
895 }
896 
897 static PetscErrorCode FastForwardRevolve(RevolveCTX *rctx)
898 {
899   PetscRevolveInt whattodo;
900 
901   PetscFunctionBegin;
902   whattodo = 0;
903   while (whattodo != 3) { /* we have to fast forward revolve to the beginning of the backward sweep due to unfriendly revolve interface */
904     whattodo = revolve_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where);
905   }
906   PetscFunctionReturn(PETSC_SUCCESS);
907 }
908 
909 static PetscErrorCode ApplyRevolve(PetscViewer viewer, SchedulerType stype, RevolveCTX *rctx, PetscRevolveInt total_steps, PetscRevolveInt stepnum, PetscRevolveInt localstepnum, PetscBool toplevel, PetscInt *store)
910 {
911   PetscRevolveInt shift, whattodo;
912 
913   PetscFunctionBegin;
914   *store = 0;
915   if (rctx->stepsleft > 0) { /* advance the solution without checkpointing anything as Revolve requires */
916     rctx->stepsleft--;
917     PetscFunctionReturn(PETSC_SUCCESS);
918   }
919   /* let Revolve determine what to do next */
920   shift         = stepnum - localstepnum;
921   rctx->oldcapo = rctx->capo;
922   rctx->capo    = localstepnum;
923 
924   if (!toplevel) whattodo = revolve_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where);
925   else whattodo = revolve2_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where);
926   if (stype == REVOLVE_ONLINE && whattodo == 8) whattodo = 5;
927   if (stype == REVOLVE_ONLINE && whattodo == 7) whattodo = 2;
928   if (!toplevel) PetscCall(printwhattodo(viewer, whattodo, rctx, shift));
929   else PetscCall(printwhattodo2(viewer, whattodo, rctx, shift));
930   PetscCheck(whattodo != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in the Revolve library");
931   if (whattodo == 1) { /* advance some time steps */
932     if (stype == REVOLVE_ONLINE && rctx->capo >= total_steps - 1) {
933       revolve_turn(total_steps, &rctx->capo, &rctx->fine);
934       if (!toplevel) PetscCall(printwhattodo(viewer, whattodo, rctx, shift));
935       else PetscCall(printwhattodo2(viewer, whattodo, rctx, shift));
936     }
937     rctx->stepsleft = rctx->capo - rctx->oldcapo - 1;
938   }
939   if (whattodo == 3 || whattodo == 4) { /* ready for a reverse step */
940     rctx->reverseonestep = PETSC_TRUE;
941   }
942   if (whattodo == 5) { /* restore a checkpoint and ask Revolve what to do next */
943     rctx->oldcapo = rctx->capo;
944     if (!toplevel) whattodo = revolve_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where); /* must return 1 or 3 or 4*/
945     else whattodo = revolve2_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where);
946     if (!toplevel) PetscCall(printwhattodo(viewer, whattodo, rctx, shift));
947     else PetscCall(printwhattodo2(viewer, whattodo, rctx, shift));
948     if (whattodo == 3 || whattodo == 4) rctx->reverseonestep = PETSC_TRUE;
949     if (whattodo == 1) rctx->stepsleft = rctx->capo - rctx->oldcapo;
950   }
951   if (whattodo == 7) { /* save the checkpoint to disk */
952     *store        = 2;
953     rctx->oldcapo = rctx->capo;
954     whattodo      = revolve_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where); /* must return 1 */
955     PetscCall(printwhattodo(viewer, whattodo, rctx, shift));
956     rctx->stepsleft = rctx->capo - rctx->oldcapo - 1;
957   }
958   if (whattodo == 2) { /* store a checkpoint to RAM and ask Revolve how many time steps to advance next */
959     *store        = 1;
960     rctx->oldcapo = rctx->capo;
961     if (!toplevel) whattodo = revolve_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where); /* must return 1 */
962     else whattodo = revolve2_action(&rctx->check, &rctx->capo, &rctx->fine, rctx->snaps_in, &rctx->info, &rctx->where);
963     if (!toplevel) PetscCall(printwhattodo(viewer, whattodo, rctx, shift));
964     else PetscCall(printwhattodo2(viewer, whattodo, rctx, shift));
965     if (stype == REVOLVE_ONLINE && rctx->capo >= total_steps - 1) {
966       revolve_turn(total_steps, &rctx->capo, &rctx->fine);
967       PetscCall(printwhattodo(viewer, whattodo, rctx, shift));
968     }
969     rctx->stepsleft = rctx->capo - rctx->oldcapo - 1;
970   }
971   PetscFunctionReturn(PETSC_SUCCESS);
972 }
973 
974 static PetscErrorCode TSTrajectoryMemorySet_ROF(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
975 {
976   Stack          *stack = &tjsch->stack;
977   PetscInt        store;
978   StackElement    e;
979   PetscRevolveInt rtotal_steps, rstepnum;
980   CheckpointType  cptype;
981 
982   PetscFunctionBegin;
983   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);
984   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(PETSC_SUCCESS);
985   PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
986   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
987   PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, rstepnum, PETSC_FALSE, &store));
988   if (store == 1) {
989     PetscCheck(stepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
990     cptype = stack->solution_only ? SOLUTIONONLY : SOLUTION_STAGES;
991     PetscCall(ElementCreate(ts, cptype, stack, &e));
992     PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
993     PetscCall(StackPush(stack, e));
994   }
995   PetscFunctionReturn(PETSC_SUCCESS);
996 }
997 
998 static PetscErrorCode TSTrajectoryMemoryGet_ROF(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum)
999 {
1000   Stack          *stack = &tjsch->stack;
1001   PetscInt        store;
1002   PetscRevolveInt whattodo, shift, rtotal_steps, rstepnum;
1003   StackElement    e;
1004 
1005   PetscFunctionBegin;
1006   if (stepnum == 0 || stepnum == tjsch->total_steps) {
1007     PetscCall(TurnBackward(ts));
1008     tjsch->rctx->reverseonestep = PETSC_FALSE;
1009     PetscFunctionReturn(PETSC_SUCCESS);
1010   }
1011   /* restore a checkpoint */
1012   PetscCall(StackTop(stack, &e));
1013   PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1014   PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1015   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1016   if (stack->solution_only) { /* start with restoring a checkpoint */
1017     tjsch->rctx->capo    = rstepnum;
1018     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1019     shift                = 0;
1020     whattodo             = revolve_action(&tjsch->rctx->check, &tjsch->rctx->capo, &tjsch->rctx->fine, tjsch->rctx->snaps_in, &tjsch->rctx->info, &tjsch->rctx->where);
1021     PetscCall(printwhattodo(tj->monitor, whattodo, tjsch->rctx, shift));
1022   } else { /* 2 revolve actions: restore a checkpoint and then advance */
1023     PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, rstepnum, PETSC_FALSE, &store));
1024     if (tj->monitor) {
1025       PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1026       PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Skip the step from %d to %d (stage values already checkpointed)\n", tjsch->rctx->oldcapo, tjsch->rctx->oldcapo + 1));
1027       PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1028     }
1029     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1030   }
1031   if (stack->solution_only || (!stack->solution_only && e->stepnum < stepnum)) {
1032     PetscCall(TurnForward(ts));
1033     PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
1034   }
1035   if ((stack->solution_only && e->stepnum + 1 == stepnum) || (!stack->solution_only && e->stepnum == stepnum)) PetscCall(StackPop(stack, &e));
1036   tjsch->rctx->reverseonestep = PETSC_FALSE;
1037   PetscFunctionReturn(PETSC_SUCCESS);
1038 }
1039 
1040 static PetscErrorCode TSTrajectoryMemorySet_RON(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
1041 {
1042   Stack          *stack = &tjsch->stack;
1043   Vec            *Y;
1044   PetscInt        i, store;
1045   PetscReal       timeprev;
1046   StackElement    e;
1047   RevolveCTX     *rctx = tjsch->rctx;
1048   PetscRevolveInt rtotal_steps, rstepnum;
1049   CheckpointType  cptype;
1050 
1051   PetscFunctionBegin;
1052   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);
1053   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(PETSC_SUCCESS);
1054   PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1055   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1056   PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, rctx, rtotal_steps, rstepnum, rstepnum, PETSC_FALSE, &store));
1057   if (store == 1) {
1058     if (rctx->check != stack->top + 1) { /* overwrite some non-top checkpoint in the stack */
1059       PetscCall(StackFind(stack, &e, rctx->check));
1060       if (HaveSolution(e->cptype)) PetscCall(VecCopy(X, e->X));
1061       if (HaveStages(e->cptype)) {
1062         PetscCall(TSGetStages(ts, &stack->numY, &Y));
1063         for (i = 0; i < stack->numY; i++) PetscCall(VecCopy(Y[i], e->Y[i]));
1064       }
1065       e->stepnum = stepnum;
1066       e->time    = time;
1067       PetscCall(TSGetPrevTime(ts, &timeprev));
1068       e->timeprev = timeprev;
1069     } else {
1070       PetscCheck(stepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
1071       cptype = stack->solution_only ? SOLUTIONONLY : SOLUTION_STAGES;
1072       PetscCall(ElementCreate(ts, cptype, stack, &e));
1073       PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
1074       PetscCall(StackPush(stack, e));
1075     }
1076   }
1077   PetscFunctionReturn(PETSC_SUCCESS);
1078 }
1079 
1080 static PetscErrorCode TSTrajectoryMemoryGet_RON(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum)
1081 {
1082   Stack          *stack = &tjsch->stack;
1083   PetscRevolveInt whattodo, shift, rstepnum;
1084   StackElement    e;
1085 
1086   PetscFunctionBegin;
1087   if (stepnum == 0 || stepnum == tjsch->total_steps) {
1088     PetscCall(TurnBackward(ts));
1089     tjsch->rctx->reverseonestep = PETSC_FALSE;
1090     PetscFunctionReturn(PETSC_SUCCESS);
1091   }
1092   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1093   tjsch->rctx->capo    = rstepnum;
1094   tjsch->rctx->oldcapo = tjsch->rctx->capo;
1095   shift                = 0;
1096   whattodo             = revolve_action(&tjsch->rctx->check, &tjsch->rctx->capo, &tjsch->rctx->fine, tjsch->rctx->snaps_in, &tjsch->rctx->info, &tjsch->rctx->where); /* whattodo=restore */
1097   if (whattodo == 8) whattodo = 5;
1098   PetscCall(printwhattodo(tj->monitor, whattodo, tjsch->rctx, shift));
1099   /* restore a checkpoint */
1100   PetscCall(StackFind(stack, &e, tjsch->rctx->check));
1101   PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1102   if (!stack->solution_only) { /* whattodo must be 5 */
1103     /* ask Revolve what to do next */
1104     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1105     whattodo             = revolve_action(&tjsch->rctx->check, &tjsch->rctx->capo, &tjsch->rctx->fine, tjsch->rctx->snaps_in, &tjsch->rctx->info, &tjsch->rctx->where); /* must return 1 or 3 or 4*/
1106     PetscCall(printwhattodo(tj->monitor, whattodo, tjsch->rctx, shift));
1107     if (whattodo == 3 || whattodo == 4) tjsch->rctx->reverseonestep = PETSC_TRUE;
1108     if (whattodo == 1) tjsch->rctx->stepsleft = tjsch->rctx->capo - tjsch->rctx->oldcapo;
1109     if (tj->monitor) {
1110       PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1111       PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Skip the step from %d to %d (stage values already checkpointed)\n", tjsch->rctx->oldcapo, tjsch->rctx->oldcapo + 1));
1112       PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1113     }
1114     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1115   }
1116   if (stack->solution_only || (!stack->solution_only && e->stepnum < stepnum)) {
1117     PetscCall(TurnForward(ts));
1118     PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
1119   }
1120   tjsch->rctx->reverseonestep = PETSC_FALSE;
1121   PetscFunctionReturn(PETSC_SUCCESS);
1122 }
1123 
1124 static PetscErrorCode TSTrajectoryMemorySet_TLR(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
1125 {
1126   Stack          *stack = &tjsch->stack;
1127   PetscInt        store, localstepnum, laststridesize;
1128   StackElement    e;
1129   PetscBool       done = PETSC_FALSE;
1130   PetscRevolveInt rtotal_steps, rstepnum, rlocalstepnum;
1131   CheckpointType  cptype;
1132 
1133   PetscFunctionBegin;
1134   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);
1135   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(PETSC_SUCCESS);
1136 
1137   localstepnum   = stepnum % tjsch->stride;
1138   laststridesize = tjsch->total_steps % tjsch->stride;
1139   if (!laststridesize) laststridesize = tjsch->stride;
1140 
1141   if (!tjsch->recompute) {
1142     PetscCall(TopLevelStore(tj, ts, tjsch, stepnum, localstepnum, laststridesize, &done));
1143     /* revolve is needed for the last stride; different starting points for last stride between solutin_only and !solutin_only */
1144     if (!stack->solution_only && !tjsch->save_stack && stepnum <= tjsch->total_steps - laststridesize) PetscFunctionReturn(PETSC_SUCCESS);
1145     if (stack->solution_only && !tjsch->save_stack && stepnum < tjsch->total_steps - laststridesize) PetscFunctionReturn(PETSC_SUCCESS);
1146   }
1147   if (tjsch->save_stack && done) {
1148     PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1149     PetscFunctionReturn(PETSC_SUCCESS);
1150   }
1151   if (laststridesize < tjsch->stride) {
1152     if (stack->solution_only && stepnum == tjsch->total_steps - laststridesize && !tjsch->recompute) { /* step tjsch->total_steps-laststridesize-1 is skipped, but the next step is not */
1153       PetscCall(InitRevolve(laststridesize, tjsch->max_cps_ram, tjsch->rctx));
1154     }
1155     if (!stack->solution_only && stepnum == tjsch->total_steps - laststridesize + 1 && !tjsch->recompute) { /* step tjsch->total_steps-laststridesize is skipped, but the next step is not */
1156       PetscCall(InitRevolve(laststridesize, tjsch->max_cps_ram, tjsch->rctx));
1157     }
1158   }
1159   PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1160   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1161   PetscCall(PetscRevolveIntCast(localstepnum, &rlocalstepnum));
1162   PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, rlocalstepnum, PETSC_FALSE, &store));
1163   if (store == 1) {
1164     PetscCheck(localstepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
1165     cptype = stack->solution_only ? SOLUTIONONLY : SOLUTION_STAGES;
1166     PetscCall(ElementCreate(ts, cptype, stack, &e));
1167     PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
1168     PetscCall(StackPush(stack, e));
1169   }
1170   PetscFunctionReturn(PETSC_SUCCESS);
1171 }
1172 
1173 static PetscErrorCode TSTrajectoryMemoryGet_TLR(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum)
1174 {
1175   Stack          *stack = &tjsch->stack;
1176   PetscRevolveInt whattodo, shift, rstepnum, rlocalstepnum, rtotal_steps;
1177   PetscInt        localstepnum, stridenum, laststridesize, store;
1178   StackElement    e;
1179   CheckpointType  cptype;
1180 
1181   PetscFunctionBegin;
1182   localstepnum = stepnum % tjsch->stride;
1183   stridenum    = stepnum / tjsch->stride;
1184   if (stepnum == tjsch->total_steps) {
1185     PetscCall(TurnBackward(ts));
1186     tjsch->rctx->reverseonestep = PETSC_FALSE;
1187     PetscFunctionReturn(PETSC_SUCCESS);
1188   }
1189   laststridesize = tjsch->total_steps % tjsch->stride;
1190   if (!laststridesize) laststridesize = tjsch->stride;
1191   PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1192   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1193   PetscCall(PetscRevolveIntCast(localstepnum, &rlocalstepnum));
1194   if (stack->solution_only) {
1195     /* fill stack */
1196     if (localstepnum == 0 && stepnum <= tjsch->total_steps - laststridesize) {
1197       if (tjsch->save_stack) {
1198         PetscCall(StackLoadAll(tj, ts, stack, stridenum));
1199         PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1200         PetscCall(FastForwardRevolve(tjsch->rctx));
1201         tjsch->skip_trajectory = PETSC_TRUE;
1202         PetscCall(TurnForward(ts));
1203         PetscCall(ReCompute(ts, tjsch, stridenum * tjsch->stride - 1, stridenum * tjsch->stride));
1204         tjsch->skip_trajectory = PETSC_FALSE;
1205       } else {
1206         PetscCall(LoadSingle(tj, ts, stack, stridenum));
1207         PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1208         PetscCall(TurnForward(ts));
1209         PetscCall(ReCompute(ts, tjsch, (stridenum - 1) * tjsch->stride, stridenum * tjsch->stride));
1210       }
1211       PetscFunctionReturn(PETSC_SUCCESS);
1212     }
1213     /* restore a checkpoint */
1214     PetscCall(StackTop(stack, &e));
1215     PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1216     /* start with restoring a checkpoint */
1217     tjsch->rctx->capo    = rstepnum;
1218     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1219     shift                = rstepnum - rlocalstepnum;
1220     whattodo             = revolve_action(&tjsch->rctx->check, &tjsch->rctx->capo, &tjsch->rctx->fine, tjsch->rctx->snaps_in, &tjsch->rctx->info, &tjsch->rctx->where);
1221     PetscCall(printwhattodo(tj->monitor, whattodo, tjsch->rctx, shift));
1222     PetscCall(TurnForward(ts));
1223     PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
1224     if (e->stepnum + 1 == stepnum) PetscCall(StackPop(stack, &e));
1225   } else {
1226     /* fill stack with info */
1227     if (localstepnum == 0 && tjsch->total_steps - stepnum >= laststridesize) {
1228       if (tjsch->save_stack) {
1229         PetscCall(StackLoadAll(tj, ts, stack, stridenum));
1230         PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1231         PetscCall(FastForwardRevolve(tjsch->rctx));
1232       } else {
1233         PetscRevolveInt rnum;
1234         PetscCall(LoadSingle(tj, ts, stack, stridenum));
1235         PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1236         PetscCall(PetscRevolveIntCast((stridenum - 1) * tjsch->stride + 1, &rnum));
1237         PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rnum, 1, PETSC_FALSE, &store));
1238         if (tj->monitor) {
1239           PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1240           PetscCall(
1241             PetscViewerASCIIPrintf(tj->monitor, "Skip the step from %" PetscInt_FMT " to %" PetscInt_FMT " (stage values already checkpointed)\n", (stridenum - 1) * tjsch->stride + tjsch->rctx->oldcapo, (stridenum - 1) * tjsch->stride + tjsch->rctx->oldcapo + 1));
1242           PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1243         }
1244         cptype = SOLUTION_STAGES;
1245         PetscCall(ElementCreate(ts, cptype, stack, &e));
1246         PetscCall(ElementSet(ts, stack, &e, (stridenum - 1) * tjsch->stride + 1, ts->ptime, ts->vec_sol));
1247         PetscCall(StackPush(stack, e));
1248         PetscCall(TurnForward(ts));
1249         PetscCall(ReCompute(ts, tjsch, e->stepnum, stridenum * tjsch->stride));
1250       }
1251       PetscFunctionReturn(PETSC_SUCCESS);
1252     }
1253     /* restore a checkpoint */
1254     PetscCall(StackTop(stack, &e));
1255     PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1256     /* 2 revolve actions: restore a checkpoint and then advance */
1257     PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, rlocalstepnum, PETSC_FALSE, &store));
1258     if (tj->monitor) {
1259       PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1260       PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Skip the step from %" PetscInt_FMT " to %" PetscInt_FMT " (stage values already checkpointed)\n", stepnum - localstepnum + tjsch->rctx->oldcapo, stepnum - localstepnum + tjsch->rctx->oldcapo + 1));
1261       PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1262     }
1263     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1264     if (e->stepnum < stepnum) {
1265       PetscCall(TurnForward(ts));
1266       PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
1267     }
1268     if (e->stepnum == stepnum) PetscCall(StackPop(stack, &e));
1269   }
1270   tjsch->rctx->reverseonestep = PETSC_FALSE;
1271   PetscFunctionReturn(PETSC_SUCCESS);
1272 }
1273 
1274 static PetscErrorCode TSTrajectoryMemorySet_TLTR(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
1275 {
1276   Stack          *stack = &tjsch->stack;
1277   PetscInt        store, localstepnum, stridenum, laststridesize;
1278   StackElement    e;
1279   PetscBool       done = PETSC_FALSE;
1280   PetscRevolveInt rlocalstepnum, rstepnum, rtotal_steps;
1281 
1282   PetscFunctionBegin;
1283   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);
1284   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(PETSC_SUCCESS);
1285 
1286   localstepnum   = stepnum % tjsch->stride; /* index at the bottom level (inside a stride) */
1287   stridenum      = stepnum / tjsch->stride; /* index at the top level */
1288   laststridesize = tjsch->total_steps % tjsch->stride;
1289   if (!laststridesize) laststridesize = tjsch->stride;
1290   if (stack->solution_only && localstepnum == 0 && !tjsch->rctx2->reverseonestep) {
1291     PetscCall(PetscRevolveIntCast((tjsch->total_steps + tjsch->stride - 1) / tjsch->stride, &rtotal_steps));
1292     PetscCall(PetscRevolveIntCast(stridenum, &rstepnum));
1293     PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx2, rtotal_steps, rstepnum, rstepnum, PETSC_TRUE, &tjsch->store_stride));
1294     if (laststridesize < tjsch->stride && stepnum == tjsch->total_steps - laststridesize) PetscCall(InitRevolve(laststridesize, tjsch->max_cps_ram, tjsch->rctx));
1295   }
1296   if (!stack->solution_only && localstepnum == 1 && !tjsch->rctx2->reverseonestep) {
1297     PetscCall(PetscRevolveIntCast((tjsch->total_steps + tjsch->stride - 1) / tjsch->stride, &rtotal_steps));
1298     PetscCall(PetscRevolveIntCast(stridenum, &rstepnum));
1299     PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx2, rtotal_steps, rstepnum, rstepnum, PETSC_TRUE, &tjsch->store_stride));
1300     if (laststridesize < tjsch->stride && stepnum == tjsch->total_steps - laststridesize + 1) PetscCall(InitRevolve(laststridesize, tjsch->max_cps_ram, tjsch->rctx));
1301   }
1302   if (tjsch->store_stride) {
1303     PetscCall(TopLevelStore(tj, ts, tjsch, stepnum, localstepnum, laststridesize, &done));
1304     if (done) {
1305       PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1306       PetscFunctionReturn(PETSC_SUCCESS);
1307     }
1308   }
1309   if (stepnum < tjsch->total_steps - laststridesize) {
1310     if (tjsch->save_stack && !tjsch->store_stride && !tjsch->rctx2->reverseonestep) PetscFunctionReturn(PETSC_SUCCESS); /* store or forward-and-reverse at top level trigger revolve at bottom level */
1311     if (!tjsch->save_stack && !tjsch->rctx2->reverseonestep) PetscFunctionReturn(PETSC_SUCCESS);                        /* store operation does not require revolve be called at bottom level */
1312   }
1313   /* Skipping stepnum=0 for !stack->only is enough for TLR, but not for TLTR. Here we skip the first step for each stride so that the top-level revolve is applied (always at localstepnum=1) ahead of the bottom-level revolve */
1314   if (!stack->solution_only && localstepnum == 0 && stepnum != tjsch->total_steps && !tjsch->recompute) PetscFunctionReturn(PETSC_SUCCESS);
1315   PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1316   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1317   PetscCall(PetscRevolveIntCast(localstepnum, &rlocalstepnum));
1318   PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, rlocalstepnum, PETSC_FALSE, &store));
1319   if (store == 1) {
1320     CheckpointType cptype;
1321     PetscCheck(localstepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
1322     cptype = stack->solution_only ? SOLUTIONONLY : SOLUTION_STAGES;
1323     PetscCall(ElementCreate(ts, cptype, stack, &e));
1324     PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
1325     PetscCall(StackPush(stack, e));
1326   }
1327   PetscFunctionReturn(PETSC_SUCCESS);
1328 }
1329 
1330 static PetscErrorCode TSTrajectoryMemoryGet_TLTR(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum)
1331 {
1332   Stack          *stack     = &tjsch->stack;
1333   DiskStack      *diskstack = &tjsch->diskstack;
1334   PetscInt        localstepnum, stridenum, restoredstridenum, laststridesize, store;
1335   StackElement    e;
1336   PetscRevolveInt whattodo, shift;
1337   PetscRevolveInt rtotal_steps, rstepnum, rlocalstepnum;
1338 
1339   PetscFunctionBegin;
1340   localstepnum = stepnum % tjsch->stride;
1341   stridenum    = stepnum / tjsch->stride;
1342   if (stepnum == tjsch->total_steps) {
1343     PetscCall(TurnBackward(ts));
1344     tjsch->rctx->reverseonestep = PETSC_FALSE;
1345     PetscFunctionReturn(PETSC_SUCCESS);
1346   }
1347   laststridesize = tjsch->total_steps % tjsch->stride;
1348   if (!laststridesize) laststridesize = tjsch->stride;
1349   /*
1350    Last stride can be adjoined directly. All the other strides require that the stack in memory be ready before an adjoint step is taken (at the end of each stride). The following two cases need to be addressed differently:
1351      Case 1 (save_stack)
1352        Restore a disk checkpoint; update TS with the last element in the restored data; recompute to the current point.
1353      Case 2 (!save_stack)
1354        Restore a disk checkpoint; update TS with the restored point; recompute to the current point.
1355   */
1356   if (localstepnum == 0 && stepnum <= tjsch->total_steps - laststridesize) {
1357     /* restore the top element in the stack for disk checkpoints */
1358     restoredstridenum            = diskstack->container[diskstack->top];
1359     tjsch->rctx2->reverseonestep = PETSC_FALSE;
1360     /* top-level revolve must be applied before current step, just like the solution_only mode for single-level revolve */
1361     if (!tjsch->save_stack && stack->solution_only) { /* start with restoring a checkpoint */
1362       PetscCall(PetscRevolveIntCast(stridenum, &rstepnum));
1363       tjsch->rctx2->capo    = rstepnum;
1364       tjsch->rctx2->oldcapo = tjsch->rctx2->capo;
1365       shift                 = 0;
1366       whattodo              = revolve2_action(&tjsch->rctx2->check, &tjsch->rctx2->capo, &tjsch->rctx2->fine, tjsch->rctx2->snaps_in, &tjsch->rctx2->info, &tjsch->rctx2->where);
1367       PetscCall(printwhattodo2(tj->monitor, whattodo, tjsch->rctx2, shift));
1368     } else { /* 2 revolve actions: restore a checkpoint and then advance */
1369       PetscCall(PetscRevolveIntCast((tjsch->total_steps + tjsch->stride - 1) / tjsch->stride, &rtotal_steps));
1370       PetscCall(PetscRevolveIntCast(stridenum, &rstepnum));
1371       PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx2, rtotal_steps, rstepnum, rstepnum, PETSC_TRUE, &tjsch->store_stride));
1372       if (tj->monitor) {
1373         PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1374         PetscCall(PetscViewerASCIIPrintf(tj->monitor, "[Top Level] Skip the stride from %d to %d (stage values already checkpointed)\n", tjsch->rctx2->oldcapo, tjsch->rctx2->oldcapo + 1));
1375         PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1376       }
1377       if (!tjsch->rctx2->reverseonestep && tjsch->rctx2->stepsleft > 0) tjsch->rctx2->stepsleft--;
1378     }
1379     /* fill stack */
1380     if (stack->solution_only) {
1381       if (tjsch->save_stack) {
1382         if (restoredstridenum < stridenum) {
1383           PetscCall(StackLoadLast(tj, ts, stack, restoredstridenum));
1384         } else {
1385           PetscCall(StackLoadAll(tj, ts, stack, restoredstridenum));
1386         }
1387         /* recompute one step ahead */
1388         tjsch->skip_trajectory = PETSC_TRUE;
1389         PetscCall(TurnForward(ts));
1390         PetscCall(ReCompute(ts, tjsch, stridenum * tjsch->stride - 1, stridenum * tjsch->stride));
1391         tjsch->skip_trajectory = PETSC_FALSE;
1392         if (restoredstridenum < stridenum) {
1393           PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1394           PetscCall(TurnForward(ts));
1395           PetscCall(ReCompute(ts, tjsch, restoredstridenum * tjsch->stride, stepnum));
1396         } else { /* stack ready, fast forward revolve status */
1397           PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1398           PetscCall(FastForwardRevolve(tjsch->rctx));
1399         }
1400       } else {
1401         PetscCall(LoadSingle(tj, ts, stack, restoredstridenum));
1402         PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1403         PetscCall(TurnForward(ts));
1404         PetscCall(ReCompute(ts, tjsch, (restoredstridenum - 1) * tjsch->stride, stepnum));
1405       }
1406     } else {
1407       if (tjsch->save_stack) {
1408         if (restoredstridenum < stridenum) {
1409           PetscCall(StackLoadLast(tj, ts, stack, restoredstridenum));
1410           /* reset revolve */
1411           PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1412           PetscCall(TurnForward(ts));
1413           PetscCall(ReCompute(ts, tjsch, restoredstridenum * tjsch->stride, stepnum));
1414         } else { /* stack ready, fast forward revolve status */
1415           PetscCall(StackLoadAll(tj, ts, stack, restoredstridenum));
1416           PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1417           PetscCall(FastForwardRevolve(tjsch->rctx));
1418         }
1419       } else {
1420         PetscCall(LoadSingle(tj, ts, stack, restoredstridenum));
1421         PetscCall(InitRevolve(tjsch->stride, tjsch->max_cps_ram, tjsch->rctx));
1422         /* push first element to stack */
1423         if (tjsch->store_stride || tjsch->rctx2->reverseonestep) {
1424           CheckpointType cptype = SOLUTION_STAGES;
1425           shift                 = (restoredstridenum - 1) * tjsch->stride - localstepnum;
1426           PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1427           PetscCall(PetscRevolveIntCast((restoredstridenum - 1) * tjsch->stride + 1, &rstepnum));
1428           PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, 1, PETSC_FALSE, &store));
1429           if (tj->monitor) {
1430             PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1431             PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Skip the step from %" PetscInt_FMT " to %" PetscInt_FMT " (stage values already checkpointed)\n", (restoredstridenum - 1) * tjsch->stride, (restoredstridenum - 1) * tjsch->stride + 1));
1432             PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1433           }
1434           PetscCall(ElementCreate(ts, cptype, stack, &e));
1435           PetscCall(ElementSet(ts, stack, &e, (restoredstridenum - 1) * tjsch->stride + 1, ts->ptime, ts->vec_sol));
1436           PetscCall(StackPush(stack, e));
1437         }
1438         PetscCall(TurnForward(ts));
1439         PetscCall(ReCompute(ts, tjsch, (restoredstridenum - 1) * tjsch->stride + 1, stepnum));
1440       }
1441     }
1442     if (restoredstridenum == stridenum) diskstack->top--;
1443     tjsch->rctx->reverseonestep = PETSC_FALSE;
1444     PetscFunctionReturn(PETSC_SUCCESS);
1445   }
1446 
1447   if (stack->solution_only) {
1448     /* restore a checkpoint */
1449     PetscCall(StackTop(stack, &e));
1450     PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1451     /* start with restoring a checkpoint */
1452     PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1453     PetscCall(PetscRevolveIntCast(localstepnum, &rlocalstepnum));
1454     tjsch->rctx->capo    = rstepnum;
1455     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1456     shift                = rstepnum - rlocalstepnum;
1457     whattodo             = revolve_action(&tjsch->rctx->check, &tjsch->rctx->capo, &tjsch->rctx->fine, tjsch->rctx->snaps_in, &tjsch->rctx->info, &tjsch->rctx->where);
1458     PetscCall(printwhattodo(tj->monitor, whattodo, tjsch->rctx, shift));
1459     PetscCall(TurnForward(ts));
1460     PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
1461     if (e->stepnum + 1 == stepnum) PetscCall(StackPop(stack, &e));
1462   } else {
1463     PetscRevolveInt rlocalstepnum;
1464     /* restore a checkpoint */
1465     PetscCall(StackTop(stack, &e));
1466     PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1467     /* 2 revolve actions: restore a checkpoint and then advance */
1468     PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1469     PetscCall(PetscRevolveIntCast(stridenum, &rstepnum));
1470     PetscCall(PetscRevolveIntCast(localstepnum, &rlocalstepnum));
1471     PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, rlocalstepnum, PETSC_FALSE, &store));
1472     if (tj->monitor) {
1473       PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1474       PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Skip the step from %" PetscInt_FMT " to %" PetscInt_FMT " (stage values already checkpointed)\n", stepnum - localstepnum + tjsch->rctx->oldcapo, stepnum - localstepnum + tjsch->rctx->oldcapo + 1));
1475       PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1476     }
1477     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1478     if (e->stepnum < stepnum) {
1479       PetscCall(TurnForward(ts));
1480       PetscCall(ReCompute(ts, tjsch, e->stepnum, stepnum));
1481     }
1482     if (e->stepnum == stepnum) PetscCall(StackPop(stack, &e));
1483   }
1484   tjsch->rctx->reverseonestep = PETSC_FALSE;
1485   PetscFunctionReturn(PETSC_SUCCESS);
1486 }
1487 
1488 static PetscErrorCode TSTrajectoryMemorySet_RMS(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
1489 {
1490   Stack          *stack = &tjsch->stack;
1491   PetscInt        store;
1492   StackElement    e;
1493   PetscRevolveInt rtotal_steps, rstepnum;
1494 
1495   PetscFunctionBegin;
1496   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(PETSC_SUCCESS);
1497   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(PETSC_SUCCESS);
1498   PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rtotal_steps));
1499   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1500   PetscCall(ApplyRevolve(tj->monitor, tjsch->stype, tjsch->rctx, rtotal_steps, rstepnum, rstepnum, PETSC_FALSE, &store));
1501   if (store == 1) {
1502     CheckpointType cptype;
1503     PetscCheck(stepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
1504     cptype = stack->solution_only ? SOLUTIONONLY : SOLUTION_STAGES;
1505     PetscCall(ElementCreate(ts, cptype, stack, &e));
1506     PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
1507     PetscCall(StackPush(stack, e));
1508   } else if (store == 2) {
1509     PetscCall(DumpSingle(tj, ts, stack, tjsch->rctx->check + 1));
1510   }
1511   PetscFunctionReturn(PETSC_SUCCESS);
1512 }
1513 
1514 static PetscErrorCode TSTrajectoryMemoryGet_RMS(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum)
1515 {
1516   Stack          *stack = &tjsch->stack;
1517   PetscRevolveInt whattodo, shift, rstepnum;
1518   PetscInt        restart;
1519   PetscBool       ondisk;
1520   StackElement    e;
1521 
1522   PetscFunctionBegin;
1523   if (stepnum == 0 || stepnum == tjsch->total_steps) {
1524     PetscCall(TurnBackward(ts));
1525     tjsch->rctx->reverseonestep = PETSC_FALSE;
1526     PetscFunctionReturn(PETSC_SUCCESS);
1527   }
1528   PetscCall(PetscRevolveIntCast(stepnum, &rstepnum));
1529   tjsch->rctx->capo    = rstepnum;
1530   tjsch->rctx->oldcapo = tjsch->rctx->capo;
1531   shift                = 0;
1532   whattodo             = revolve_action(&tjsch->rctx->check, &tjsch->rctx->capo, &tjsch->rctx->fine, tjsch->rctx->snaps_in, &tjsch->rctx->info, &tjsch->rctx->where); /* whattodo=restore */
1533   PetscCall(printwhattodo(tj->monitor, whattodo, tjsch->rctx, shift));
1534   /* restore a checkpoint */
1535   restart = tjsch->rctx->capo;
1536   if (!tjsch->rctx->where) {
1537     ondisk = PETSC_TRUE;
1538     PetscCall(LoadSingle(tj, ts, stack, tjsch->rctx->check + 1));
1539     PetscCall(TurnBackward(ts));
1540   } else {
1541     ondisk = PETSC_FALSE;
1542     PetscCall(StackTop(stack, &e));
1543     PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1544   }
1545   if (!stack->solution_only) { /* whattodo must be 5 or 8 */
1546     /* ask Revolve what to do next */
1547     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1548     whattodo             = revolve_action(&tjsch->rctx->check, &tjsch->rctx->capo, &tjsch->rctx->fine, tjsch->rctx->snaps_in, &tjsch->rctx->info, &tjsch->rctx->where); /* must return 1 or 3 or 4*/
1549     PetscCall(printwhattodo(tj->monitor, whattodo, tjsch->rctx, shift));
1550     if (whattodo == 3 || whattodo == 4) tjsch->rctx->reverseonestep = PETSC_TRUE;
1551     if (whattodo == 1) tjsch->rctx->stepsleft = tjsch->rctx->capo - tjsch->rctx->oldcapo;
1552     if (tj->monitor) {
1553       PetscCall(PetscViewerASCIIAddTab(tj->monitor, ((PetscObject)tj)->tablevel));
1554       PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Skip the step from %d to %d (stage values already checkpointed)\n", tjsch->rctx->oldcapo, tjsch->rctx->oldcapo + 1));
1555       PetscCall(PetscViewerASCIISubtractTab(tj->monitor, ((PetscObject)tj)->tablevel));
1556     }
1557     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1558     restart++; /* skip one step */
1559   }
1560   if (stack->solution_only || (!stack->solution_only && restart < stepnum)) {
1561     PetscCall(TurnForward(ts));
1562     PetscCall(ReCompute(ts, tjsch, restart, stepnum));
1563   }
1564   if (!ondisk && ((stack->solution_only && e->stepnum + 1 == stepnum) || (!stack->solution_only && e->stepnum == stepnum))) PetscCall(StackPop(stack, &e));
1565   tjsch->rctx->reverseonestep = PETSC_FALSE;
1566   PetscFunctionReturn(PETSC_SUCCESS);
1567 }
1568 #endif
1569 
1570 #if defined(PETSC_HAVE_CAMS)
1571 /* Optimal offline adjoint checkpointing for multistage time integration methods */
1572 static PetscErrorCode TSTrajectoryMemorySet_AOF(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum, PetscReal time, Vec X)
1573 {
1574   Stack       *stack = &tjsch->stack;
1575   StackElement e;
1576 
1577   PetscFunctionBegin;
1578   /* skip if no checkpoint to use. This also avoids an error when num_units_avail=0  */
1579   if (tjsch->actx->nextcheckpointstep == -1) PetscFunctionReturn(PETSC_SUCCESS);
1580   if (stepnum == 0) { /* When placing the first checkpoint, no need to change the units available */
1581     if (stack->solution_only) {
1582       PetscCallExternal(offline_ca, tjsch->actx->lastcheckpointstep, tjsch->actx->num_units_avail, tjsch->actx->endstep, &tjsch->actx->nextcheckpointstep);
1583     } else {
1584       /* First two arguments must be -1 when first time calling cams */
1585       PetscCallExternal(offline_cams, tjsch->actx->lastcheckpointstep, tjsch->actx->lastcheckpointtype, tjsch->actx->num_units_avail, tjsch->actx->endstep, tjsch->actx->num_stages, &tjsch->actx->nextcheckpointstep, &tjsch->actx->nextcheckpointtype);
1586     }
1587   }
1588 
1589   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(PETSC_SUCCESS);
1590 
1591   if (tjsch->actx->nextcheckpointstep == stepnum) {
1592     PetscCheck(stepnum >= stack->top, PetscObjectComm((PetscObject)ts), PETSC_ERR_MEMC, "Illegal modification of a non-top stack element");
1593 
1594     if (tjsch->actx->nextcheckpointtype == 2) { /* solution + stage values */
1595       if (tj->monitor) PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Store in checkpoint number %" PetscInt_FMT " with stage values and solution (located in RAM)\n", stepnum));
1596       PetscCall(ElementCreate(ts, SOLUTION_STAGES, stack, &e));
1597       PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
1598     }
1599     if (tjsch->actx->nextcheckpointtype == 1) {
1600       if (tj->monitor) PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Store in checkpoint number %" PetscInt_FMT " with stage values (located in RAM)\n", stepnum));
1601       PetscCall(ElementCreate(ts, STAGESONLY, stack, &e));
1602       PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
1603     }
1604     if (tjsch->actx->nextcheckpointtype == 0) { /* solution only */
1605       if (tj->monitor) PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Store in checkpoint number %" PetscInt_FMT " (located in RAM)\n", stepnum));
1606       PetscCall(ElementCreate(ts, SOLUTIONONLY, stack, &e));
1607       PetscCall(ElementSet(ts, stack, &e, stepnum, time, X));
1608     }
1609     PetscCall(StackPush(stack, e));
1610 
1611     tjsch->actx->lastcheckpointstep = stepnum;
1612     if (stack->solution_only) {
1613       PetscCallExternal(offline_ca, tjsch->actx->lastcheckpointstep, tjsch->actx->num_units_avail, tjsch->actx->endstep, &tjsch->actx->nextcheckpointstep);
1614       tjsch->actx->num_units_avail--;
1615     } else {
1616       tjsch->actx->lastcheckpointtype = tjsch->actx->nextcheckpointtype;
1617       PetscCallExternal(offline_cams, tjsch->actx->lastcheckpointstep, tjsch->actx->lastcheckpointtype, tjsch->actx->num_units_avail, tjsch->actx->endstep, tjsch->actx->num_stages, &tjsch->actx->nextcheckpointstep, &tjsch->actx->nextcheckpointtype);
1618       if (tjsch->actx->lastcheckpointtype == 2) tjsch->actx->num_units_avail -= tjsch->actx->num_stages + 1;
1619       if (tjsch->actx->lastcheckpointtype == 1) tjsch->actx->num_units_avail -= tjsch->actx->num_stages;
1620       if (tjsch->actx->lastcheckpointtype == 0) tjsch->actx->num_units_avail--;
1621     }
1622   }
1623   PetscFunctionReturn(PETSC_SUCCESS);
1624 }
1625 
1626 static PetscErrorCode TSTrajectoryMemoryGet_AOF(TSTrajectory tj, TS ts, TJScheduler *tjsch, PetscInt stepnum)
1627 {
1628   Stack       *stack = &tjsch->stack;
1629   StackElement e;
1630   PetscInt     estepnum;
1631 
1632   PetscFunctionBegin;
1633   if (stepnum == 0 || stepnum == tjsch->total_steps) {
1634     PetscCall(TurnBackward(ts));
1635     PetscFunctionReturn(PETSC_SUCCESS);
1636   }
1637   /* Restore a checkpoint */
1638   PetscCall(StackTop(stack, &e));
1639   estepnum = e->stepnum;
1640   if (estepnum == stepnum && e->cptype == SOLUTIONONLY) { /* discard the checkpoint if not useful (corner case) */
1641     PetscCall(StackPop(stack, &e));
1642     tjsch->actx->num_units_avail++;
1643     PetscCall(StackTop(stack, &e));
1644     estepnum = e->stepnum;
1645   }
1646   /* Update TS with stage values if an adjoint step can be taken immediately */
1647   if (HaveStages(e->cptype)) {
1648     if (tj->monitor) PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Restore in checkpoint number %" PetscInt_FMT " with stage values (located in RAM)\n", e->stepnum));
1649     if (e->cptype == STAGESONLY) tjsch->actx->num_units_avail += tjsch->actx->num_stages;
1650     if (e->cptype == SOLUTION_STAGES) tjsch->actx->num_units_avail += tjsch->actx->num_stages + 1;
1651   } else {
1652     if (tj->monitor) PetscCall(PetscViewerASCIIPrintf(tj->monitor, "Restore in checkpoint number %" PetscInt_FMT " (located in RAM)\n", e->stepnum));
1653     tjsch->actx->num_units_avail++;
1654   }
1655   PetscCall(UpdateTS(ts, stack, e, stepnum, PETSC_TRUE));
1656   /* Query the scheduler */
1657   tjsch->actx->lastcheckpointstep = estepnum;
1658   tjsch->actx->endstep            = stepnum;
1659   if (stack->solution_only) { /* start with restoring a checkpoint */
1660     PetscCallExternal(offline_ca, tjsch->actx->lastcheckpointstep, tjsch->actx->num_units_avail, tjsch->actx->endstep, &tjsch->actx->nextcheckpointstep);
1661   } else { /* 2 revolve actions: restore a checkpoint and then advance */
1662     tjsch->actx->lastcheckpointtype = e->cptype;
1663     PetscCallExternal(offline_cams, tjsch->actx->lastcheckpointstep, tjsch->actx->lastcheckpointtype, tjsch->actx->num_units_avail, tjsch->actx->endstep, tjsch->actx->num_stages, &tjsch->actx->nextcheckpointstep, &tjsch->actx->nextcheckpointtype);
1664   }
1665   /* Discard the checkpoint if not needed, decrease the number of available checkpoints if it still stays in stack */
1666   if (HaveStages(e->cptype)) {
1667     if (estepnum == stepnum) {
1668       PetscCall(StackPop(stack, &e));
1669     } else {
1670       if (e->cptype == STAGESONLY) tjsch->actx->num_units_avail -= tjsch->actx->num_stages;
1671       if (e->cptype == SOLUTION_STAGES) tjsch->actx->num_units_avail -= tjsch->actx->num_stages + 1;
1672     }
1673   } else {
1674     if (estepnum + 1 == stepnum) {
1675       PetscCall(StackPop(stack, &e));
1676     } else {
1677       tjsch->actx->num_units_avail--;
1678     }
1679   }
1680   /* Recompute from the restored checkpoint */
1681   if (stack->solution_only || (!stack->solution_only && estepnum < stepnum)) {
1682     PetscCall(TurnForward(ts));
1683     PetscCall(ReCompute(ts, tjsch, estepnum, stepnum));
1684   }
1685   PetscFunctionReturn(PETSC_SUCCESS);
1686 }
1687 #endif
1688 
1689 static PetscErrorCode TSTrajectorySet_Memory(TSTrajectory tj, TS ts, PetscInt stepnum, PetscReal time, Vec X)
1690 {
1691   TJScheduler *tjsch = (TJScheduler *)tj->data;
1692 
1693   PetscFunctionBegin;
1694   if (!tjsch->recompute) { /* use global stepnum in the forward sweep */
1695     PetscCall(TSGetStepNumber(ts, &stepnum));
1696   }
1697   /* for consistency */
1698   if (!tjsch->recompute && stepnum == 0) ts->ptime_prev = ts->ptime - ts->time_step;
1699   switch (tjsch->stype) {
1700   case NONE:
1701     if (tj->adjoint_solve_mode) {
1702       PetscCall(TSTrajectoryMemorySet_N(ts, tjsch, stepnum, time, X));
1703     } else {
1704       PetscCall(TSTrajectoryMemorySet_N_2(ts, tjsch, stepnum, time, X));
1705     }
1706     break;
1707   case TWO_LEVEL_NOREVOLVE:
1708     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1709     PetscCall(TSTrajectoryMemorySet_TLNR(tj, ts, tjsch, stepnum, time, X));
1710     break;
1711 #if defined(PETSC_HAVE_REVOLVE)
1712   case TWO_LEVEL_REVOLVE:
1713     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1714     PetscCall(TSTrajectoryMemorySet_TLR(tj, ts, tjsch, stepnum, time, X));
1715     break;
1716   case TWO_LEVEL_TWO_REVOLVE:
1717     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1718     PetscCall(TSTrajectoryMemorySet_TLTR(tj, ts, tjsch, stepnum, time, X));
1719     break;
1720   case REVOLVE_OFFLINE:
1721     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1722     PetscCall(TSTrajectoryMemorySet_ROF(tj, ts, tjsch, stepnum, time, X));
1723     break;
1724   case REVOLVE_ONLINE:
1725     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1726     PetscCall(TSTrajectoryMemorySet_RON(tj, ts, tjsch, stepnum, time, X));
1727     break;
1728   case REVOLVE_MULTISTAGE:
1729     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1730     PetscCall(TSTrajectoryMemorySet_RMS(tj, ts, tjsch, stepnum, time, X));
1731     break;
1732 #endif
1733 #if defined(PETSC_HAVE_CAMS)
1734   case CAMS_OFFLINE:
1735     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1736     PetscCall(TSTrajectoryMemorySet_AOF(tj, ts, tjsch, stepnum, time, X));
1737     break;
1738 #endif
1739   default:
1740     break;
1741   }
1742   PetscFunctionReturn(PETSC_SUCCESS);
1743 }
1744 
1745 static PetscErrorCode TSTrajectoryGet_Memory(TSTrajectory tj, TS ts, PetscInt stepnum, PetscReal *t)
1746 {
1747   TJScheduler *tjsch = (TJScheduler *)tj->data;
1748 
1749   PetscFunctionBegin;
1750   if (tj->adjoint_solve_mode && stepnum == 0) {
1751     PetscCall(TSTrajectoryReset(tj)); /* reset TSTrajectory so users do not need to reset TSTrajectory */
1752     PetscFunctionReturn(PETSC_SUCCESS);
1753   }
1754   switch (tjsch->stype) {
1755   case NONE:
1756     if (tj->adjoint_solve_mode) {
1757       PetscCall(TSTrajectoryMemoryGet_N(ts, tjsch, stepnum));
1758     } else {
1759       PetscCall(TSTrajectoryMemoryGet_N_2(ts, tjsch, stepnum));
1760     }
1761     break;
1762   case TWO_LEVEL_NOREVOLVE:
1763     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1764     PetscCall(TSTrajectoryMemoryGet_TLNR(tj, ts, tjsch, stepnum));
1765     break;
1766 #if defined(PETSC_HAVE_REVOLVE)
1767   case TWO_LEVEL_REVOLVE:
1768     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1769     PetscCall(TSTrajectoryMemoryGet_TLR(tj, ts, tjsch, stepnum));
1770     break;
1771   case TWO_LEVEL_TWO_REVOLVE:
1772     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1773     PetscCall(TSTrajectoryMemoryGet_TLTR(tj, ts, tjsch, stepnum));
1774     break;
1775   case REVOLVE_OFFLINE:
1776     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1777     PetscCall(TSTrajectoryMemoryGet_ROF(tj, ts, tjsch, stepnum));
1778     break;
1779   case REVOLVE_ONLINE:
1780     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1781     PetscCall(TSTrajectoryMemoryGet_RON(tj, ts, tjsch, stepnum));
1782     break;
1783   case REVOLVE_MULTISTAGE:
1784     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1785     PetscCall(TSTrajectoryMemoryGet_RMS(tj, ts, tjsch, stepnum));
1786     break;
1787 #endif
1788 #if defined(PETSC_HAVE_CAMS)
1789   case CAMS_OFFLINE:
1790     PetscCheck(tj->adjoint_solve_mode, PetscObjectComm((PetscObject)tj), PETSC_ERR_SUP, "Not implemented");
1791     PetscCall(TSTrajectoryMemoryGet_AOF(tj, ts, tjsch, stepnum));
1792     break;
1793 #endif
1794   default:
1795     break;
1796   }
1797   PetscFunctionReturn(PETSC_SUCCESS);
1798 }
1799 
1800 PETSC_UNUSED static PetscErrorCode TSTrajectorySetStride_Memory(TSTrajectory tj, PetscInt stride)
1801 {
1802   TJScheduler *tjsch = (TJScheduler *)tj->data;
1803 
1804   PetscFunctionBegin;
1805   tjsch->stride = stride;
1806   PetscFunctionReturn(PETSC_SUCCESS);
1807 }
1808 
1809 static PetscErrorCode TSTrajectorySetMaxCpsRAM_Memory(TSTrajectory tj, PetscInt max_cps_ram)
1810 {
1811   TJScheduler *tjsch = (TJScheduler *)tj->data;
1812 
1813   PetscFunctionBegin;
1814   tjsch->max_cps_ram = max_cps_ram;
1815   PetscFunctionReturn(PETSC_SUCCESS);
1816 }
1817 
1818 static PetscErrorCode TSTrajectorySetMaxCpsDisk_Memory(TSTrajectory tj, PetscInt max_cps_disk)
1819 {
1820   TJScheduler *tjsch = (TJScheduler *)tj->data;
1821 
1822   PetscFunctionBegin;
1823   tjsch->max_cps_disk = max_cps_disk;
1824   PetscFunctionReturn(PETSC_SUCCESS);
1825 }
1826 
1827 static PetscErrorCode TSTrajectorySetMaxUnitsRAM_Memory(TSTrajectory tj, PetscInt max_units_ram)
1828 {
1829   TJScheduler *tjsch = (TJScheduler *)tj->data;
1830 
1831   PetscFunctionBegin;
1832   PetscCheck(tjsch->max_cps_ram, PetscObjectComm((PetscObject)tj), PETSC_ERR_ARG_INCOMP, "Conflict with -ts_trjaectory_max_cps_ram or TSTrajectorySetMaxCpsRAM. You can set max_cps_ram or max_units_ram, but not both at the same time.");
1833   tjsch->max_units_ram = max_units_ram;
1834   PetscFunctionReturn(PETSC_SUCCESS);
1835 }
1836 
1837 static PetscErrorCode TSTrajectorySetMaxUnitsDisk_Memory(TSTrajectory tj, PetscInt max_units_disk)
1838 {
1839   TJScheduler *tjsch = (TJScheduler *)tj->data;
1840 
1841   PetscFunctionBegin;
1842   PetscCheck(tjsch->max_cps_disk, PetscObjectComm((PetscObject)tj), PETSC_ERR_ARG_INCOMP, "Conflict with -ts_trjaectory_max_cps_disk or TSTrajectorySetMaxCpsDisk. You can set max_cps_disk or max_units_disk, but not both at the same time.");
1843   tjsch->max_units_ram = max_units_disk;
1844   PetscFunctionReturn(PETSC_SUCCESS);
1845 }
1846 
1847 static PetscErrorCode TSTrajectoryMemorySetType_Memory(TSTrajectory tj, TSTrajectoryMemoryType tj_memory_type)
1848 {
1849   TJScheduler *tjsch = (TJScheduler *)tj->data;
1850 
1851   PetscFunctionBegin;
1852   PetscCheck(!tj->setupcalled, PetscObjectComm((PetscObject)tj), PETSC_ERR_ARG_WRONGSTATE, "Cannot change schedule software after TSTrajectory has been setup or used");
1853   tjsch->tj_memory_type = tj_memory_type;
1854   PetscFunctionReturn(PETSC_SUCCESS);
1855 }
1856 
1857 #if defined(PETSC_HAVE_REVOLVE)
1858 PETSC_UNUSED static PetscErrorCode TSTrajectorySetRevolveOnline(TSTrajectory tj, PetscBool use_online)
1859 {
1860   TJScheduler *tjsch = (TJScheduler *)tj->data;
1861 
1862   PetscFunctionBegin;
1863   tjsch->use_online = use_online;
1864   PetscFunctionReturn(PETSC_SUCCESS);
1865 }
1866 #endif
1867 
1868 PETSC_UNUSED static PetscErrorCode TSTrajectorySetSaveStack(TSTrajectory tj, PetscBool save_stack)
1869 {
1870   TJScheduler *tjsch = (TJScheduler *)tj->data;
1871 
1872   PetscFunctionBegin;
1873   tjsch->save_stack = save_stack;
1874   PetscFunctionReturn(PETSC_SUCCESS);
1875 }
1876 
1877 PETSC_UNUSED static PetscErrorCode TSTrajectorySetUseDRAM(TSTrajectory tj, PetscBool use_dram)
1878 {
1879   TJScheduler *tjsch = (TJScheduler *)tj->data;
1880 
1881   PetscFunctionBegin;
1882   tjsch->stack.use_dram = use_dram;
1883   PetscFunctionReturn(PETSC_SUCCESS);
1884 }
1885 
1886 /*@
1887   TSTrajectoryMemorySetType - sets the software that is used to generate the checkpointing schedule.
1888 
1889   Logically Collective
1890 
1891   Input Parameters:
1892 + tj             - the `TSTrajectory` context
1893 - tj_memory_type - Revolve or CAMS
1894 
1895   Options Database Key:
1896 . -ts_trajectory_memory_type <tj_memory_type> - petsc, revolve, cams
1897 
1898   Level: intermediate
1899 
1900 .seealso: [](ch_ts), `TSTrajectory`, `TSTrajectorySetMaxUnitsRAM()`, `TSTrajectoryMemoryType`
1901 @*/
1902 PetscErrorCode TSTrajectoryMemorySetType(TSTrajectory tj, TSTrajectoryMemoryType tj_memory_type)
1903 {
1904   PetscFunctionBegin;
1905   PetscTryMethod(tj, "TSTrajectoryMemorySetType_C", (TSTrajectory, TSTrajectoryMemoryType), (tj, tj_memory_type));
1906   PetscFunctionReturn(PETSC_SUCCESS);
1907 }
1908 
1909 /*@
1910   TSTrajectorySetMaxCpsRAM - Set maximum number of checkpoints in RAM
1911 
1912   Logically Collective
1913 
1914   Input Parameter:
1915 . tj - tstrajectory context
1916 
1917   Output Parameter:
1918 . max_cps_ram - maximum number of checkpoints in RAM
1919 
1920   Level: intermediate
1921 
1922 .seealso: [](ch_ts), `TSTrajectory`, `TSTrajectorySetMaxUnitsRAM()`
1923 @*/
1924 PetscErrorCode TSTrajectorySetMaxCpsRAM(TSTrajectory tj, PetscInt max_cps_ram)
1925 {
1926   PetscFunctionBegin;
1927   PetscUseMethod(tj, "TSTrajectorySetMaxCpsRAM_C", (TSTrajectory, PetscInt), (tj, max_cps_ram));
1928   PetscFunctionReturn(PETSC_SUCCESS);
1929 }
1930 
1931 /*@
1932   TSTrajectorySetMaxCpsDisk - Set maximum number of checkpoints on disk
1933 
1934   Logically Collective
1935 
1936   Input Parameter:
1937 . tj - tstrajectory context
1938 
1939   Output Parameter:
1940 . max_cps_disk - maximum number of checkpoints on disk
1941 
1942   Level: intermediate
1943 
1944 .seealso: [](ch_ts), `TSTrajectory`, `TSTrajectorySetMaxUnitsDisk()`, `TSTrajectorySetMaxUnitsRAM()`
1945 @*/
1946 PetscErrorCode TSTrajectorySetMaxCpsDisk(TSTrajectory tj, PetscInt max_cps_disk)
1947 {
1948   PetscFunctionBegin;
1949   PetscUseMethod(tj, "TSTrajectorySetMaxCpsDisk_C", (TSTrajectory, PetscInt), (tj, max_cps_disk));
1950   PetscFunctionReturn(PETSC_SUCCESS);
1951 }
1952 
1953 /*@
1954   TSTrajectorySetMaxUnitsRAM - Set maximum number of checkpointing units in RAM
1955 
1956   Logically Collective
1957 
1958   Input Parameter:
1959 . tj - tstrajectory context
1960 
1961   Output Parameter:
1962 . max_units_ram - maximum number of checkpointing units in RAM
1963 
1964   Level: intermediate
1965 
1966 .seealso: [](ch_ts), `TSTrajectory`, `TSTrajectorySetMaxCpsRAM()`
1967 @*/
1968 PetscErrorCode TSTrajectorySetMaxUnitsRAM(TSTrajectory tj, PetscInt max_units_ram)
1969 {
1970   PetscFunctionBegin;
1971   PetscUseMethod(tj, "TSTrajectorySetMaxUnitsRAM_C", (TSTrajectory, PetscInt), (tj, max_units_ram));
1972   PetscFunctionReturn(PETSC_SUCCESS);
1973 }
1974 
1975 /*@
1976   TSTrajectorySetMaxUnitsDisk - Set maximum number of checkpointing units on disk
1977 
1978   Logically Collective
1979 
1980   Input Parameter:
1981 . tj - tstrajectory context
1982 
1983   Output Parameter:
1984 . max_units_disk - maximum number of checkpointing units on disk
1985 
1986   Level: intermediate
1987 
1988 .seealso: [](ch_ts), `TSTrajectory`, `TSTrajectorySetMaxCpsDisk()`
1989 @*/
1990 PetscErrorCode TSTrajectorySetMaxUnitsDisk(TSTrajectory tj, PetscInt max_units_disk)
1991 {
1992   PetscFunctionBegin;
1993   PetscUseMethod(tj, "TSTrajectorySetMaxUnitsDisk_C", (TSTrajectory, PetscInt), (tj, max_units_disk));
1994   PetscFunctionReturn(PETSC_SUCCESS);
1995 }
1996 
1997 static PetscErrorCode TSTrajectorySetFromOptions_Memory(TSTrajectory tj, PetscOptionItems PetscOptionsObject)
1998 {
1999   TJScheduler *tjsch = (TJScheduler *)tj->data;
2000   PetscEnum    etmp;
2001   PetscInt     max_cps_ram, max_cps_disk, max_units_ram, max_units_disk;
2002   PetscBool    flg;
2003 
2004   PetscFunctionBegin;
2005   PetscOptionsHeadBegin(PetscOptionsObject, "Memory based TS trajectory options");
2006   {
2007     PetscCall(PetscOptionsInt("-ts_trajectory_max_cps_ram", "Maximum number of checkpoints in RAM", "TSTrajectorySetMaxCpsRAM", tjsch->max_cps_ram, &max_cps_ram, &flg));
2008     if (flg) PetscCall(TSTrajectorySetMaxCpsRAM(tj, max_cps_ram));
2009     PetscCall(PetscOptionsInt("-ts_trajectory_max_cps_disk", "Maximum number of checkpoints on disk", "TSTrajectorySetMaxCpsDisk", tjsch->max_cps_disk, &max_cps_disk, &flg));
2010     if (flg) PetscCall(TSTrajectorySetMaxCpsDisk(tj, max_cps_disk));
2011     PetscCall(PetscOptionsInt("-ts_trajectory_max_units_ram", "Maximum number of checkpointing units in RAM", "TSTrajectorySetMaxUnitsRAM", tjsch->max_units_ram, &max_units_ram, &flg));
2012     if (flg) PetscCall(TSTrajectorySetMaxUnitsRAM(tj, max_units_ram));
2013     PetscCall(PetscOptionsInt("-ts_trajectory_max_units_disk", "Maximum number of checkpointing units on disk", "TSTrajectorySetMaxUnitsDisk", tjsch->max_units_disk, &max_units_disk, &flg));
2014     if (flg) PetscCall(TSTrajectorySetMaxUnitsDisk(tj, max_units_disk));
2015     PetscCall(PetscOptionsInt("-ts_trajectory_stride", "Stride to save checkpoints to file", "TSTrajectorySetStride", tjsch->stride, &tjsch->stride, NULL));
2016 #if defined(PETSC_HAVE_REVOLVE)
2017     PetscCall(PetscOptionsBool("-ts_trajectory_revolve_online", "Trick TS trajectory into using online mode of revolve", "TSTrajectorySetRevolveOnline", tjsch->use_online, &tjsch->use_online, NULL));
2018 #endif
2019     PetscCall(PetscOptionsBool("-ts_trajectory_save_stack", "Save all stack to disk", "TSTrajectorySetSaveStack", tjsch->save_stack, &tjsch->save_stack, NULL));
2020     PetscCall(PetscOptionsBool("-ts_trajectory_use_dram", "Use DRAM for checkpointing", "TSTrajectorySetUseDRAM", tjsch->stack.use_dram, &tjsch->stack.use_dram, NULL));
2021     PetscCall(PetscOptionsEnum("-ts_trajectory_memory_type", "Checkpointing schedule software to use", "TSTrajectoryMemorySetType", TSTrajectoryMemoryTypes, (PetscEnum)(int)tjsch->tj_memory_type, &etmp, &flg));
2022     if (flg) PetscCall(TSTrajectoryMemorySetType(tj, (TSTrajectoryMemoryType)etmp));
2023   }
2024   PetscOptionsHeadEnd();
2025   PetscFunctionReturn(PETSC_SUCCESS);
2026 }
2027 
2028 static PetscErrorCode TSTrajectorySetUp_Memory(TSTrajectory tj, TS ts)
2029 {
2030   TJScheduler *tjsch = (TJScheduler *)tj->data;
2031   Stack       *stack = &tjsch->stack;
2032 #if defined(PETSC_HAVE_REVOLVE)
2033   RevolveCTX *rctx, *rctx2;
2034   DiskStack  *diskstack = &tjsch->diskstack;
2035   PetscInt    diskblocks;
2036 #endif
2037   PetscInt  numY, total_steps;
2038   PetscBool fixedtimestep;
2039 
2040   PetscFunctionBegin;
2041   if (ts->adapt) {
2042     PetscCall(PetscObjectTypeCompare((PetscObject)ts->adapt, TSADAPTNONE, &fixedtimestep));
2043   } else {
2044     fixedtimestep = PETSC_TRUE;
2045   }
2046   total_steps = (PetscInt)(PetscCeilReal((ts->max_time - ts->ptime) / ts->time_step));
2047   total_steps = total_steps < 0 ? PETSC_INT_MAX : total_steps;
2048   if (fixedtimestep) tjsch->total_steps = PetscMin(ts->max_steps, total_steps);
2049 
2050   tjsch->stack.solution_only = tj->solution_only;
2051   PetscCall(TSGetStages(ts, &numY, PETSC_IGNORE));
2052   if (stack->solution_only) {
2053     if (tjsch->max_units_ram) tjsch->max_cps_ram = tjsch->max_units_ram;
2054     else tjsch->max_units_ram = tjsch->max_cps_ram;
2055     if (tjsch->max_units_disk) tjsch->max_cps_disk = tjsch->max_units_disk;
2056   } else {
2057     if (tjsch->max_units_ram) tjsch->max_cps_ram = (ts->stifflyaccurate) ? tjsch->max_units_ram / numY : tjsch->max_units_ram / (numY + 1);
2058     else tjsch->max_units_ram = (ts->stifflyaccurate) ? numY * tjsch->max_cps_ram : (numY + 1) * tjsch->max_cps_ram;
2059     if (tjsch->max_units_disk) tjsch->max_cps_disk = (ts->stifflyaccurate) ? tjsch->max_units_disk / numY : tjsch->max_units_disk / (numY + 1);
2060     else tjsch->max_units_disk = (ts->stifflyaccurate) ? numY * tjsch->max_cps_disk : (numY + 1) * tjsch->max_cps_disk;
2061   }
2062   if (tjsch->max_cps_ram > 0) stack->stacksize = tjsch->max_units_ram; /* maximum stack size. Could be overallocated. */
2063 
2064   /* Determine the scheduler type */
2065   if (tjsch->stride > 1) { /* two level mode */
2066     PetscCheck(!tjsch->save_stack || tjsch->max_cps_disk <= 1 || tjsch->max_cps_disk > tjsch->max_cps_ram, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_INCOMP, "The specified disk capacity is not enough to store a full stack of RAM checkpoints. You might want to change the disk capacity or use single level checkpointing instead.");
2067     if (tjsch->max_cps_disk <= 1 && tjsch->max_cps_ram > 1 && tjsch->max_cps_ram <= tjsch->stride - 1) tjsch->stype = TWO_LEVEL_REVOLVE;    /* use revolve_offline for each stride */
2068     if (tjsch->max_cps_disk > 1 && tjsch->max_cps_ram > 1 && tjsch->max_cps_ram <= tjsch->stride - 1) tjsch->stype = TWO_LEVEL_TWO_REVOLVE; /* use revolve_offline for each stride */
2069     if (tjsch->max_cps_disk <= 1 && (tjsch->max_cps_ram >= tjsch->stride || tjsch->max_cps_ram == -1)) tjsch->stype = TWO_LEVEL_NOREVOLVE;  /* can also be handled by TWO_LEVEL_REVOLVE */
2070   } else {                                                                                                                                  /* single level mode */
2071     if (fixedtimestep) {
2072       if (tjsch->max_cps_ram >= tjsch->total_steps - 1 || tjsch->max_cps_ram == -1) tjsch->stype = NONE; /* checkpoint all */
2073       else { /* choose the schedule software for offline checkpointing */ switch (tjsch->tj_memory_type) {
2074         case TJ_PETSC:
2075           tjsch->stype = NONE;
2076           break;
2077         case TJ_CAMS:
2078           tjsch->stype = CAMS_OFFLINE;
2079           break;
2080         case TJ_REVOLVE:
2081           tjsch->stype = (tjsch->max_cps_disk > 1) ? REVOLVE_MULTISTAGE : REVOLVE_OFFLINE;
2082           break;
2083         default:
2084           break;
2085         }
2086       }
2087     } else tjsch->stype = NONE; /* checkpoint all for adaptive time step */
2088 #if defined(PETSC_HAVE_REVOLVE)
2089     if (tjsch->use_online) tjsch->stype = REVOLVE_ONLINE; /* trick into online (for testing purpose only) */
2090 #endif
2091     PetscCheck(tjsch->stype == NONE || tjsch->max_cps_ram >= 1 || tjsch->max_cps_disk >= 1, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_INCOMP, "The specified storage capacity is insufficient for one checkpoint, which is the minimum");
2092   }
2093   if (tjsch->stype >= CAMS_OFFLINE) {
2094 #ifndef PETSC_HAVE_CAMS
2095     SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "CAMS is needed when there is not enough memory to checkpoint all time steps according to the user's settings, please reconfigure with the additional option --download-cams.");
2096 #else
2097     CAMSCTX *actx;
2098     PetscInt ns = 0;
2099     if (stack->solution_only) {
2100       offline_ca_create(tjsch->total_steps, tjsch->max_cps_ram);
2101     } else {
2102       PetscCall(TSGetStages(ts, &ns, PETSC_IGNORE));
2103       offline_cams_create(tjsch->total_steps, tjsch->max_units_ram, ns, ts->stifflyaccurate);
2104     }
2105     PetscCall(PetscNew(&actx));
2106     actx->lastcheckpointstep = -1; /* -1 can trigger the initialization of CAMS */
2107     actx->lastcheckpointtype = -1; /* -1 can trigger the initialization of CAMS */
2108     actx->endstep            = tjsch->total_steps;
2109     actx->num_units_avail    = tjsch->max_units_ram;
2110     actx->num_stages         = ns;
2111     tjsch->actx              = actx;
2112 #endif
2113   } else if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
2114 #ifndef PETSC_HAVE_REVOLVE
2115     SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "revolve is needed when there is not enough memory to checkpoint all time steps according to the user's settings, please reconfigure with the additional option --download-revolve.");
2116 #else
2117     PetscRevolveInt rfine, rsnaps, rsnaps2;
2118 
2119     switch (tjsch->stype) {
2120     case TWO_LEVEL_REVOLVE:
2121       PetscCall(PetscRevolveIntCast(tjsch->stride, &rfine));
2122       PetscCall(PetscRevolveIntCast(tjsch->max_cps_ram, &rsnaps));
2123       revolve_create_offline(rfine, rsnaps);
2124       break;
2125     case TWO_LEVEL_TWO_REVOLVE:
2126       diskblocks           = tjsch->save_stack ? tjsch->max_cps_disk / (tjsch->max_cps_ram + 1) : tjsch->max_cps_disk; /* The block size depends on whether the stack is saved. */
2127       diskstack->stacksize = diskblocks;
2128       PetscCall(PetscRevolveIntCast(tjsch->stride, &rfine));
2129       PetscCall(PetscRevolveIntCast(tjsch->max_cps_ram, &rsnaps));
2130       revolve_create_offline(rfine, rsnaps);
2131       PetscCall(PetscRevolveIntCast((tjsch->total_steps + tjsch->stride - 1) / tjsch->stride, &rfine));
2132       PetscCall(PetscRevolveIntCast(diskblocks, &rsnaps));
2133       revolve2_create_offline(rfine, rsnaps);
2134       PetscCall(PetscNew(&rctx2));
2135       rctx2->snaps_in       = rsnaps;
2136       rctx2->reverseonestep = PETSC_FALSE;
2137       rctx2->check          = 0;
2138       rctx2->oldcapo        = 0;
2139       rctx2->capo           = 0;
2140       rctx2->info           = 2;
2141       rctx2->fine           = rfine;
2142       tjsch->rctx2          = rctx2;
2143       diskstack->top        = -1;
2144       PetscCall(PetscMalloc1(diskstack->stacksize, &diskstack->container));
2145       break;
2146     case REVOLVE_OFFLINE:
2147       PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rfine));
2148       PetscCall(PetscRevolveIntCast(tjsch->max_cps_ram, &rsnaps));
2149       revolve_create_offline(rfine, rsnaps);
2150       break;
2151     case REVOLVE_ONLINE:
2152       stack->stacksize = tjsch->max_cps_ram;
2153       PetscCall(PetscRevolveIntCast(tjsch->max_cps_ram, &rsnaps));
2154       revolve_create_online(rsnaps);
2155       break;
2156     case REVOLVE_MULTISTAGE:
2157       PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rfine));
2158       PetscCall(PetscRevolveIntCast(tjsch->max_cps_ram, &rsnaps));
2159       PetscCall(PetscRevolveIntCast(tjsch->max_cps_ram + tjsch->max_cps_disk, &rsnaps2));
2160       revolve_create_multistage(rfine, rsnaps2, rsnaps);
2161       break;
2162     default:
2163       break;
2164     }
2165     PetscCall(PetscNew(&rctx));
2166     PetscCall(PetscRevolveIntCast(tjsch->max_cps_ram, &rsnaps));
2167     rctx->snaps_in       = rsnaps; /* for theta methods snaps_in=2*max_cps_ram */
2168     rctx->reverseonestep = PETSC_FALSE;
2169     rctx->check          = 0;
2170     rctx->oldcapo        = 0;
2171     rctx->capo           = 0;
2172     rctx->info           = 2;
2173     if (tjsch->stride > 1) {
2174       PetscCall(PetscRevolveIntCast(tjsch->stride, &rfine));
2175     } else {
2176       PetscCall(PetscRevolveIntCast(tjsch->total_steps, &rfine));
2177     }
2178     rctx->fine  = rfine;
2179     tjsch->rctx = rctx;
2180     if (tjsch->stype == REVOLVE_ONLINE) rctx->fine = -1;
2181 #endif
2182   } else {
2183     if (tjsch->stype == TWO_LEVEL_NOREVOLVE) stack->stacksize = tjsch->stride - 1; /* need tjsch->stride-1 at most */
2184     if (tjsch->stype == NONE) {
2185       if (fixedtimestep) stack->stacksize = stack->solution_only ? tjsch->total_steps : tjsch->total_steps - 1;
2186       else { /* adaptive time step */ /* if max_cps_ram is not specified, use maximal allowed number of steps for stack size */
2187         if (tjsch->max_cps_ram == -1) stack->stacksize = ts->max_steps < PETSC_INT_MAX ? ts->max_steps : 10000;
2188         tjsch->total_steps = stack->solution_only ? stack->stacksize : stack->stacksize + 1; /* will be updated as time integration advances */
2189       }
2190     }
2191   }
2192 
2193   if ((tjsch->stype >= TWO_LEVEL_NOREVOLVE && tjsch->stype < REVOLVE_OFFLINE) || tjsch->stype == REVOLVE_MULTISTAGE) { /* these types need to use disk */
2194     PetscCall(TSTrajectorySetUp_Basic(tj, ts));
2195   }
2196 
2197   stack->stacksize = PetscMax(stack->stacksize, 1);
2198   tjsch->recompute = PETSC_FALSE;
2199   PetscCall(StackInit(stack, stack->stacksize, numY));
2200   PetscFunctionReturn(PETSC_SUCCESS);
2201 }
2202 
2203 static PetscErrorCode TSTrajectoryReset_Memory(TSTrajectory tj)
2204 {
2205 #if defined(PETSC_HAVE_REVOLVE) || defined(PETSC_HAVE_CAMS)
2206   TJScheduler *tjsch = (TJScheduler *)tj->data;
2207 #endif
2208 
2209   PetscFunctionBegin;
2210 #if defined(PETSC_HAVE_REVOLVE)
2211   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
2212     revolve_reset();
2213     if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) {
2214       revolve2_reset();
2215       PetscCall(PetscFree(tjsch->diskstack.container));
2216     }
2217   }
2218   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
2219     PetscCall(PetscFree(tjsch->rctx));
2220     PetscCall(PetscFree(tjsch->rctx2));
2221   }
2222 #endif
2223 #if defined(PETSC_HAVE_CAMS)
2224   if (tjsch->stype == CAMS_OFFLINE) {
2225     if (tjsch->stack.solution_only) offline_ca_destroy();
2226     else offline_ca_destroy();
2227     PetscCall(PetscFree(tjsch->actx));
2228   }
2229 #endif
2230   PetscFunctionReturn(PETSC_SUCCESS);
2231 }
2232 
2233 static PetscErrorCode TSTrajectoryDestroy_Memory(TSTrajectory tj)
2234 {
2235   TJScheduler *tjsch = (TJScheduler *)tj->data;
2236 
2237   PetscFunctionBegin;
2238   PetscCall(StackDestroy(&tjsch->stack));
2239   PetscCall(PetscViewerDestroy(&tjsch->viewer));
2240   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxCpsRAM_C", NULL));
2241   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxCpsDisk_C", NULL));
2242   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxUnitsRAM_C", NULL));
2243   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxUnitsDisk_C", NULL));
2244   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectoryMemorySetType_C", NULL));
2245   PetscCall(PetscFree(tjsch));
2246   PetscFunctionReturn(PETSC_SUCCESS);
2247 }
2248 
2249 /*MC
2250       TSTRAJECTORYMEMORY - Stores each solution of the ODE/ADE in memory
2251 
2252   Level: intermediate
2253 
2254 .seealso: [](ch_ts), `TSTrajectoryCreate()`, `TS`, `TSTrajectorySetType()`, `TSTrajectoryType`, `TSTrajectory`
2255 M*/
2256 PETSC_EXTERN PetscErrorCode TSTrajectoryCreate_Memory(TSTrajectory tj, TS ts)
2257 {
2258   TJScheduler *tjsch;
2259 
2260   PetscFunctionBegin;
2261   tj->ops->set            = TSTrajectorySet_Memory;
2262   tj->ops->get            = TSTrajectoryGet_Memory;
2263   tj->ops->setup          = TSTrajectorySetUp_Memory;
2264   tj->ops->setfromoptions = TSTrajectorySetFromOptions_Memory;
2265   tj->ops->reset          = TSTrajectoryReset_Memory;
2266   tj->ops->destroy        = TSTrajectoryDestroy_Memory;
2267 
2268   PetscCall(PetscNew(&tjsch));
2269   tjsch->stype        = NONE;
2270   tjsch->max_cps_ram  = -1; /* -1 indicates that it is not set */
2271   tjsch->max_cps_disk = -1; /* -1 indicates that it is not set */
2272   tjsch->stride       = 0;  /* if not zero, two-level checkpointing will be used */
2273 #if defined(PETSC_HAVE_REVOLVE)
2274   tjsch->use_online = PETSC_FALSE;
2275 #endif
2276   tjsch->save_stack = PETSC_TRUE;
2277 
2278   tjsch->stack.solution_only = tj->solution_only;
2279   PetscCall(PetscViewerCreate(PetscObjectComm((PetscObject)tj), &tjsch->viewer));
2280   PetscCall(PetscViewerSetType(tjsch->viewer, PETSCVIEWERBINARY));
2281   PetscCall(PetscViewerPushFormat(tjsch->viewer, PETSC_VIEWER_NATIVE));
2282   PetscCall(PetscViewerFileSetMode(tjsch->viewer, FILE_MODE_WRITE));
2283 
2284   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxCpsRAM_C", TSTrajectorySetMaxCpsRAM_Memory));
2285   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxCpsDisk_C", TSTrajectorySetMaxCpsDisk_Memory));
2286   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxUnitsRAM_C", TSTrajectorySetMaxUnitsRAM_Memory));
2287   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectorySetMaxUnitsDisk_C", TSTrajectorySetMaxUnitsDisk_Memory));
2288   PetscCall(PetscObjectComposeFunction((PetscObject)tj, "TSTrajectoryMemorySetType_C", TSTrajectoryMemorySetType_Memory));
2289   tj->data = tjsch;
2290   PetscFunctionReturn(PETSC_SUCCESS);
2291 }
2292