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