xref: /petsc/src/ts/trajectory/impls/memory/trajmemory.c (revision feff33ee0b5b037fa8f9f294dede656a2f85cc47)
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 #endif
6 
7 PetscLogEvent TSTrajectory_DiskWrite, TSTrajectory_DiskRead;
8 
9 typedef enum {NONE,TWO_LEVEL_NOREVOLVE,TWO_LEVEL_REVOLVE,TWO_LEVEL_TWO_REVOLVE,REVOLVE_OFFLINE,REVOLVE_ONLINE,REVOLVE_MULTISTAGE} SchedulerType;
10 
11 typedef struct _StackElement {
12   PetscInt  stepnum;
13   Vec       X;
14   Vec       *Y;
15   PetscReal time;
16   PetscReal timeprev; /* for no solution_only mode */
17   PetscReal timenext; /* for solution_only mode */
18 } *StackElement;
19 
20 #if defined(PETSC_HAVE_REVOLVE)
21 typedef struct _RevolveCTX {
22   PetscBool reverseonestep;
23   PetscInt  where;
24   PetscInt  snaps_in;
25   PetscInt  stepsleft;
26   PetscInt  check;
27   PetscInt  oldcapo;
28   PetscInt  capo;
29   PetscInt  fine;
30   PetscInt  info;
31 } RevolveCTX;
32 #endif
33 
34 typedef struct _Stack {
35   PetscInt      stacksize;
36   PetscInt      top;
37   StackElement  *container;
38   PetscInt      numY;
39   PetscBool     solution_only;
40   PetscBool     use_dram;
41 } Stack;
42 
43 typedef struct _DiskStack {
44   PetscInt  stacksize;
45   PetscInt  top;
46   PetscInt  *container;
47 } DiskStack;
48 
49 typedef struct _TJScheduler {
50   SchedulerType stype;
51 #if defined(PETSC_HAVE_REVOLVE)
52   RevolveCTX    *rctx,*rctx2;
53   PetscBool     use_online;
54   PetscInt      store_stride;
55 #endif
56   PetscBool     recompute;
57   PetscBool     skip_trajectory;
58   PetscBool     save_stack;
59   PetscInt      max_cps_ram;  /* maximum checkpoints in RAM */
60   PetscInt      max_cps_disk; /* maximum checkpoints on disk */
61   PetscInt      stride;
62   PetscInt      total_steps;  /* total number of steps */
63   Stack         stack;
64   DiskStack     diskstack;
65 } TJScheduler;
66 
67 static PetscErrorCode TurnForwardWithStepsize(TS ts,PetscReal nextstepsize)
68 {
69     PetscReal      stepsize;
70     PetscErrorCode ierr;
71 
72     PetscFunctionBegin;
73     /* reverse the direction */
74     ierr = TSGetTimeStep(ts,&stepsize);CHKERRQ(ierr);
75     stepsize = nextstepsize;
76     ierr = TSSetTimeStep(ts,stepsize);CHKERRQ(ierr);
77     PetscFunctionReturn(0);
78 }
79 
80 static PetscErrorCode TurnForward(TS ts)
81 {
82   PetscReal      stepsize;
83   PetscErrorCode ierr;
84 
85   PetscFunctionBegin;
86   /* reverse the direction */
87   ierr = TSGetTimeStep(ts,&stepsize);CHKERRQ(ierr);
88   ierr = TSSetTimeStep(ts,-stepsize);CHKERRQ(ierr);
89   PetscFunctionReturn(0);
90 }
91 
92 static PetscErrorCode TurnBackward(TS ts)
93 {
94   PetscReal      stepsize;
95   PetscErrorCode ierr;
96 
97   PetscFunctionBegin;
98   /* reverse the direction */
99   stepsize = ts->ptime_prev-ts->ptime;
100   ierr = TSSetTimeStep(ts,stepsize);CHKERRQ(ierr);
101   PetscFunctionReturn(0);
102 }
103 
104 static PetscErrorCode ElementCreate(TS ts,Stack *stack,StackElement *e)
105 {
106   Vec            X;
107   Vec            *Y;
108   PetscErrorCode ierr;
109 
110   PetscFunctionBegin;
111   if (stack->use_dram) {
112     ierr = PetscMallocSetDRAM();CHKERRQ(ierr);
113   }
114   ierr = PetscCalloc1(1,e);CHKERRQ(ierr);
115   ierr = TSGetSolution(ts,&X);CHKERRQ(ierr);
116   ierr = VecDuplicate(X,&(*e)->X);CHKERRQ(ierr);
117   if (stack->numY > 0 && !stack->solution_only) {
118     ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
119     ierr = VecDuplicateVecs(Y[0],stack->numY,&(*e)->Y);CHKERRQ(ierr);
120   }
121   if (stack->use_dram) {
122     ierr = PetscMallocResetDRAM();CHKERRQ(ierr);
123   }
124   PetscFunctionReturn(0);
125 }
126 
127 static PetscErrorCode ElementSet(TS ts,Stack *stack,StackElement *e,PetscInt stepnum,PetscReal time,Vec X)
128 {
129   Vec            *Y;
130   PetscInt       i;
131   PetscReal      timeprev;
132   PetscErrorCode ierr;
133 
134   PetscFunctionBegin;
135   ierr = VecCopy(X,(*e)->X);CHKERRQ(ierr);
136   if (stack->numY > 0 && !stack->solution_only) {
137     ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
138     for (i=0;i<stack->numY;i++) {
139       ierr = VecCopy(Y[i],(*e)->Y[i]);CHKERRQ(ierr);
140     }
141   }
142   (*e)->stepnum = stepnum;
143   (*e)->time    = time;
144   /* for consistency */
145   if (stepnum == 0) {
146     (*e)->timeprev = (*e)->time - ts->time_step;
147   } else {
148     ierr = TSGetPrevTime(ts,&timeprev);CHKERRQ(ierr);
149     (*e)->timeprev = timeprev;
150   }
151   PetscFunctionReturn(0);
152 }
153 
154 static PetscErrorCode ElementDestroy(Stack *stack,StackElement e)
155 {
156   PetscErrorCode ierr;
157 
158   PetscFunctionBegin;
159   if (stack->use_dram) {
160     ierr = PetscMallocSetDRAM();CHKERRQ(ierr);
161   }
162   ierr = VecDestroy(&e->X);CHKERRQ(ierr);
163   if (stack->numY > 0 && !stack->solution_only) {
164     ierr = VecDestroyVecs(stack->numY,&e->Y);CHKERRQ(ierr);
165   }
166   ierr = PetscFree(e);CHKERRQ(ierr);
167   if (stack->use_dram) {
168     ierr = PetscMallocResetDRAM();CHKERRQ(ierr);
169   }
170   PetscFunctionReturn(0);
171 }
172 
173 static PetscErrorCode StackResize(Stack *stack,PetscInt newsize)
174 {
175   StackElement   *newcontainer;
176   PetscInt       i;
177   PetscErrorCode ierr;
178 
179   PetscFunctionBegin;
180   ierr = PetscMalloc1(newsize*sizeof(StackElement),&newcontainer);CHKERRQ(ierr);
181   for (i=0;i<stack->stacksize;i++) {
182     newcontainer[i] = stack->container[i];
183   }
184   ierr = PetscFree(stack->container);CHKERRQ(ierr);
185   stack->container = newcontainer;
186   stack->stacksize = newsize;
187   PetscFunctionReturn(0);
188 }
189 
190 static PetscErrorCode StackPush(Stack *stack,StackElement e)
191 {
192   PetscFunctionBegin;
193   if (stack->top+1 >= stack->stacksize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Maximum stack size (%D) exceeded",stack->stacksize);
194   stack->container[++stack->top] = e;
195   PetscFunctionReturn(0);
196 }
197 
198 static PetscErrorCode StackPop(Stack *stack,StackElement *e)
199 {
200   PetscFunctionBegin;
201   *e = NULL;
202   if (stack->top == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Empty stack");
203   *e = stack->container[stack->top--];
204   PetscFunctionReturn(0);
205 }
206 
207 static PetscErrorCode StackTop(Stack *stack,StackElement *e)
208 {
209   PetscFunctionBegin;
210   *e = stack->container[stack->top];
211   PetscFunctionReturn(0);
212 }
213 
214 static PetscErrorCode StackCreate(Stack *stack,PetscInt size,PetscInt ny)
215 {
216   PetscErrorCode ierr;
217 
218   PetscFunctionBegin;
219   stack->top  = -1;
220   stack->numY = ny;
221 
222   ierr = PetscMalloc1(size*sizeof(StackElement),&stack->container);CHKERRQ(ierr);
223   PetscFunctionReturn(0);
224 }
225 
226 static PetscErrorCode StackDestroy(Stack *stack)
227 {
228   PetscInt       i,n;
229   StackElement   e;
230   PetscErrorCode ierr;
231 
232   PetscFunctionBegin;
233   if (stack->top > -1) {
234     n = stack->top+1; /* number of elements in the stack */
235     for (i=0;i<n;i++) {
236       ierr = StackPop(stack,&e);CHKERRQ(ierr);
237       ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
238     }
239   }
240   ierr = PetscFree(stack->container);CHKERRQ(ierr);
241   PetscFunctionReturn(0);
242 }
243 
244 #if defined(PETSC_HAVE_REVOLVE)
245 static PetscErrorCode StackFind(Stack *stack,StackElement *e,PetscInt index)
246 {
247   PetscFunctionBegin;
248   *e = stack->container[index];
249   PetscFunctionReturn(0);
250 }
251 #endif
252 
253 static PetscErrorCode OutputBIN(MPI_Comm comm,const char *filename,PetscViewer *viewer)
254 {
255   PetscErrorCode ierr;
256 
257   PetscFunctionBegin;
258   ierr = PetscViewerCreate(comm,viewer);CHKERRQ(ierr);
259   ierr = PetscViewerSetType(*viewer,PETSCVIEWERBINARY);CHKERRQ(ierr);
260   ierr = PetscViewerFileSetMode(*viewer,FILE_MODE_WRITE);CHKERRQ(ierr);
261   ierr = PetscViewerFileSetName(*viewer,filename);CHKERRQ(ierr);
262   PetscFunctionReturn(0);
263 }
264 
265 static PetscErrorCode WriteToDisk(PetscInt stepnum,PetscReal time,PetscReal timeprev,Vec X,Vec *Y,PetscInt numY,PetscBool solution_only,PetscViewer viewer)
266 {
267   PetscInt       i;
268   PetscErrorCode ierr;
269 
270   PetscFunctionBegin;
271   ierr = PetscViewerBinaryWrite(viewer,&stepnum,1,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr);
272   ierr = VecView(X,viewer);CHKERRQ(ierr);
273   for (i=0;!solution_only && i<numY;i++) {
274     ierr = VecView(Y[i],viewer);CHKERRQ(ierr);
275   }
276   ierr = PetscViewerBinaryWrite(viewer,&time,1,PETSC_REAL,PETSC_FALSE);CHKERRQ(ierr);
277   ierr = PetscViewerBinaryWrite(viewer,&timeprev,1,PETSC_REAL,PETSC_FALSE);CHKERRQ(ierr);
278   PetscFunctionReturn(0);
279 }
280 
281 static PetscErrorCode ReadFromDisk(PetscInt *stepnum,PetscReal *time,PetscReal *timeprev,Vec X,Vec *Y,PetscInt numY,PetscBool solution_only,PetscViewer viewer)
282 {
283   PetscInt       i;
284   PetscErrorCode ierr;
285 
286   PetscFunctionBegin;
287   ierr = PetscViewerBinaryRead(viewer,stepnum,1,NULL,PETSC_INT);CHKERRQ(ierr);
288   ierr = VecLoad(X,viewer);CHKERRQ(ierr);
289   for (i=0;!solution_only && i<numY;i++) {
290     ierr = VecLoad(Y[i],viewer);CHKERRQ(ierr);
291   }
292   ierr = PetscViewerBinaryRead(viewer,time,1,NULL,PETSC_REAL);CHKERRQ(ierr);
293   ierr = PetscViewerBinaryRead(viewer,timeprev,1,NULL,PETSC_REAL);CHKERRQ(ierr);
294   PetscFunctionReturn(0);
295 }
296 
297 static PetscErrorCode StackDumpAll(TSTrajectory tj,TS ts,Stack *stack,PetscInt id)
298 {
299   Vec            *Y;
300   PetscInt       i;
301   StackElement   e = NULL;
302   PetscViewer    viewer;
303   char           filename[PETSC_MAX_PATH_LEN];
304   PetscErrorCode ierr;
305   MPI_Comm       comm;
306 
307   PetscFunctionBegin;
308   ierr = PetscObjectGetComm((PetscObject)ts,&comm);CHKERRQ(ierr);
309   if (tj->monitor) {
310     ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
311     ierr = PetscViewerASCIIPrintf(tj->monitor,"Dump stack to file\n");CHKERRQ(ierr);
312     ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
313   }
314   if (id == 1) {
315     PetscMPIInt rank;
316     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
317     if (!rank) {
318       ierr = PetscRMTree("SA-data");CHKERRQ(ierr);
319       ierr = PetscMkdir("SA-data");CHKERRQ(ierr);
320     }
321   }
322   ierr = PetscSNPrintf(filename,sizeof(filename),"SA-data/SA-STACK%06d.bin",id);CHKERRQ(ierr);
323   ierr = OutputBIN(comm,filename,&viewer);CHKERRQ(ierr);
324   for (i=0;i<stack->stacksize;i++) {
325     e = stack->container[i];
326     ierr = PetscLogEventBegin(TSTrajectory_DiskWrite,ts,0,0,0);CHKERRQ(ierr);
327     ierr = WriteToDisk(e->stepnum,e->time,e->timeprev,e->X,e->Y,stack->numY,stack->solution_only,viewer);CHKERRQ(ierr);
328     ierr = PetscLogEventEnd(TSTrajectory_DiskWrite,ts,0,0,0);CHKERRQ(ierr);
329     ts->trajectory->diskwrites++;
330   }
331   /* 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 */
332   ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
333   ierr = PetscLogEventBegin(TSTrajectory_DiskWrite,ts,0,0,0);CHKERRQ(ierr);
334   ierr = WriteToDisk(ts->steps,ts->ptime,ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);CHKERRQ(ierr);
335   ierr = PetscLogEventEnd(TSTrajectory_DiskWrite,ts,0,0,0);CHKERRQ(ierr);
336   ts->trajectory->diskwrites++;
337   for (i=0;i<stack->stacksize;i++) {
338     ierr = StackPop(stack,&e);CHKERRQ(ierr);
339     ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
340   }
341   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
342   PetscFunctionReturn(0);
343 }
344 
345 static PetscErrorCode StackLoadAll(TSTrajectory tj,TS ts,Stack *stack,PetscInt id)
346 {
347   Vec            *Y;
348   PetscInt       i;
349   StackElement   e;
350   PetscViewer    viewer;
351   char           filename[PETSC_MAX_PATH_LEN];
352   PetscErrorCode ierr;
353 
354   PetscFunctionBegin;
355   if (tj->monitor) {
356     ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
357     ierr = PetscViewerASCIIPrintf(tj->monitor,"Load stack from file\n");CHKERRQ(ierr);
358     ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
359   }
360   ierr = PetscSNPrintf(filename,sizeof filename,"SA-data/SA-STACK%06d.bin",id);CHKERRQ(ierr);
361   ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr);
362   for (i=0;i<stack->stacksize;i++) {
363     ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
364     ierr = StackPush(stack,e);CHKERRQ(ierr);
365     ierr = PetscLogEventBegin(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
366     ierr = ReadFromDisk(&e->stepnum,&e->time,&e->timeprev,e->X,e->Y,stack->numY,stack->solution_only,viewer);CHKERRQ(ierr);
367     ierr = PetscLogEventEnd(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
368     ts->trajectory->diskreads++;
369   }
370   /* load the last step into TS */
371   ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
372   ierr = PetscLogEventBegin(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
373   ierr = ReadFromDisk(&ts->steps,&ts->ptime,&ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);CHKERRQ(ierr);
374   ierr = PetscLogEventEnd(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
375   ts->trajectory->diskreads++;
376   ierr = TurnBackward(ts);CHKERRQ(ierr);
377   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
378   PetscFunctionReturn(0);
379 }
380 
381 #if defined(PETSC_HAVE_REVOLVE)
382 static PetscErrorCode StackLoadLast(TSTrajectory tj,TS ts,Stack *stack,PetscInt id)
383 {
384   Vec            *Y;
385   PetscInt       size;
386   PetscViewer    viewer;
387   char           filename[PETSC_MAX_PATH_LEN];
388 #if defined(PETSC_HAVE_MPIIO)
389   PetscBool      usempiio;
390 #endif
391   int            fd;
392   off_t          off,offset;
393   PetscErrorCode ierr;
394 
395   PetscFunctionBegin;
396   if (tj->monitor) {
397     ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
398     ierr = PetscViewerASCIIPrintf(tj->monitor,"Load last stack element from file\n");CHKERRQ(ierr);
399     ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
400   }
401   ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
402   ierr = VecGetSize(Y[0],&size);CHKERRQ(ierr);
403   /* VecView writes to file two extra int's for class id and number of rows */
404   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;
405 
406   ierr = PetscSNPrintf(filename,sizeof filename,"SA-data/SA-STACK%06d.bin",id);CHKERRQ(ierr);
407   ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr);
408 #if defined(PETSC_HAVE_MPIIO)
409   ierr = PetscViewerBinaryGetUseMPIIO(viewer,&usempiio);
410   if (usempiio) {
411     ierr = PetscViewerBinaryGetMPIIODescriptor(viewer,(MPI_File*)&fd);CHKERRQ(ierr);
412     ierr = PetscBinarySynchronizedSeek(PETSC_COMM_WORLD,fd,off,PETSC_BINARY_SEEK_END,&offset);CHKERRQ(ierr);
413   } else {
414 #endif
415     ierr = PetscViewerBinaryGetDescriptor(viewer,&fd);CHKERRQ(ierr);
416     ierr = PetscBinarySeek(fd,off,PETSC_BINARY_SEEK_END,&offset);CHKERRQ(ierr);
417 #if defined(PETSC_HAVE_MPIIO)
418   }
419 #endif
420   /* load the last step into TS */
421   ierr = PetscLogEventBegin(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
422   ierr = ReadFromDisk(&ts->steps,&ts->ptime,&ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);CHKERRQ(ierr);
423   ierr = PetscLogEventEnd(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
424   ts->trajectory->diskreads++;
425   ierr = TurnBackward(ts);CHKERRQ(ierr);
426   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
427   PetscFunctionReturn(0);
428 }
429 #endif
430 
431 static PetscErrorCode DumpSingle(TSTrajectory tj,TS ts,Stack *stack,PetscInt id)
432 {
433   Vec            *Y;
434   PetscInt       stepnum;
435   PetscViewer    viewer;
436   char           filename[PETSC_MAX_PATH_LEN];
437   PetscErrorCode ierr;
438   MPI_Comm       comm;
439 
440   PetscFunctionBegin;
441   ierr = PetscObjectGetComm((PetscObject)ts,&comm);CHKERRQ(ierr);
442   if (tj->monitor) {
443     ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
444     ierr = PetscViewerASCIIPrintf(tj->monitor,"Load a single point from file\n");CHKERRQ(ierr);
445     ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
446   }
447   ierr = TSGetStepNumber(ts,&stepnum);CHKERRQ(ierr);
448   if (id == 1) {
449     PetscMPIInt rank;
450     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
451     if (!rank) {
452       ierr = PetscRMTree("SA-data");CHKERRQ(ierr);
453       ierr = PetscMkdir("SA-data");CHKERRQ(ierr);
454     }
455   }
456   ierr = PetscSNPrintf(filename,sizeof(filename),"SA-data/SA-CPS%06d.bin",id);CHKERRQ(ierr);
457   ierr = OutputBIN(comm,filename,&viewer);CHKERRQ(ierr);
458 
459   ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
460   ierr = PetscLogEventBegin(TSTrajectory_DiskWrite,ts,0,0,0);CHKERRQ(ierr);
461   ierr = WriteToDisk(stepnum,ts->ptime,ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);CHKERRQ(ierr);
462   ierr = PetscLogEventEnd(TSTrajectory_DiskWrite,ts,0,0,0);CHKERRQ(ierr);
463   ts->trajectory->diskwrites++;
464 
465   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
466   PetscFunctionReturn(0);
467 }
468 
469 static PetscErrorCode LoadSingle(TSTrajectory tj,TS ts,Stack *stack,PetscInt id)
470 {
471   Vec            *Y;
472   PetscViewer    viewer;
473   char           filename[PETSC_MAX_PATH_LEN];
474   PetscErrorCode ierr;
475 
476   PetscFunctionBegin;
477   if (tj->monitor) {
478     ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
479     ierr = PetscViewerASCIIPrintf(tj->monitor,"Load a single point from file\n");CHKERRQ(ierr);
480     ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
481   }
482   ierr = PetscSNPrintf(filename,sizeof filename,"SA-data/SA-CPS%06d.bin",id);CHKERRQ(ierr);
483   ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr);
484 
485   ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
486   ierr = PetscLogEventBegin(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
487   ierr = ReadFromDisk(&ts->steps,&ts->ptime,&ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);CHKERRQ(ierr);
488   ierr = PetscLogEventEnd(TSTrajectory_DiskRead,ts,0,0,0);CHKERRQ(ierr);
489   ts->trajectory->diskreads++;
490 
491   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
492   PetscFunctionReturn(0);
493 }
494 
495 static PetscErrorCode UpdateTS(TS ts,Stack *stack,StackElement e)
496 {
497   Vec            *Y;
498   PetscInt       i;
499   PetscErrorCode ierr;
500 
501   PetscFunctionBegin;
502   ierr = VecCopy(e->X,ts->vec_sol);CHKERRQ(ierr);
503   if (!stack->solution_only) {
504     ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
505     for (i=0;i<stack->numY;i++) {
506       ierr = VecCopy(e->Y[i],Y[i]);CHKERRQ(ierr);
507     }
508   }
509   ierr = TSSetTimeStep(ts,e->timeprev-e->time);CHKERRQ(ierr); /* stepsize will be negative */
510   ts->ptime      = e->time;
511   ts->ptime_prev = e->timeprev;
512   PetscFunctionReturn(0);
513 }
514 
515 static PetscErrorCode ReCompute(TS ts,TJScheduler *tjsch,PetscInt stepnumbegin,PetscInt stepnumend)
516 {
517   Stack          *stack = &tjsch->stack;
518   PetscInt       i;
519   PetscErrorCode ierr;
520 
521   PetscFunctionBegin;
522   ts->steps = stepnumbegin; /* global step number */
523   for (i=stepnumbegin;i<stepnumend;i++) { /* assume fixed step size */
524     if (stack->solution_only && !tjsch->skip_trajectory) { /* revolve online need this */
525       ierr = TSTrajectorySet(ts->trajectory,ts,ts->steps,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
526     }
527     ierr = TSMonitor(ts,ts->steps,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
528     ierr = TSStep(ts);CHKERRQ(ierr);
529     if (!stack->solution_only && !tjsch->skip_trajectory) {
530       ierr = TSTrajectorySet(ts->trajectory,ts,ts->steps,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
531     }
532     ierr = TSEventHandler(ts);CHKERRQ(ierr);
533     if (!ts->steprollback) {
534       ierr = TSPostStep(ts);CHKERRQ(ierr);
535     }
536   }
537   ierr = TurnBackward(ts);CHKERRQ(ierr);
538   ts->trajectory->recomps += stepnumend-stepnumbegin; /* recomputation counter */
539   ts->steps = stepnumend;
540   PetscFunctionReturn(0);
541 }
542 
543 static PetscErrorCode TopLevelStore(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscInt localstepnum,PetscInt laststridesize,PetscBool *done)
544 {
545   Stack          *stack = &tjsch->stack;
546   DiskStack      *diskstack = &tjsch->diskstack;
547   PetscInt       stridenum;
548   PetscErrorCode ierr;
549 
550   PetscFunctionBegin;
551   *done = PETSC_FALSE;
552   stridenum    = stepnum/tjsch->stride;
553   /* make sure saved checkpoint id starts from 1
554      skip last stride when using stridenum+1
555      skip first stride when using stridenum */
556   if (stack->solution_only) {
557     if (tjsch->save_stack) {
558       if (localstepnum == tjsch->stride-1 && stepnum < tjsch->total_steps-laststridesize) { /* current step will be saved without going through stack */
559         ierr = StackDumpAll(tj,ts,stack,stridenum+1);CHKERRQ(ierr);
560         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum+1;
561         *done = PETSC_TRUE;
562       }
563     } else {
564       if (localstepnum == 0 && stepnum < tjsch->total_steps-laststridesize) {
565         ierr = DumpSingle(tj,ts,stack,stridenum+1);CHKERRQ(ierr);
566         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum+1;
567         *done = PETSC_TRUE;
568       }
569     }
570   } else {
571     if (tjsch->save_stack) {
572       if (localstepnum == 0 && stepnum < tjsch->total_steps && stepnum != 0) { /* skip the first stride */
573         ierr = StackDumpAll(tj,ts,stack,stridenum);CHKERRQ(ierr);
574         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum;
575         *done = PETSC_TRUE;
576       }
577     } else {
578       if (localstepnum == 1 && stepnum < tjsch->total_steps-laststridesize) {
579         ierr = DumpSingle(tj,ts,stack,stridenum+1);CHKERRQ(ierr);
580         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum+1;
581         *done = PETSC_TRUE;
582       }
583     }
584   }
585   PetscFunctionReturn(0);
586 }
587 
588 static PetscErrorCode SetTrajN(TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
589 {
590   Stack          *stack = &tjsch->stack;
591   StackElement   e;
592   PetscErrorCode ierr;
593 
594   PetscFunctionBegin;
595   /* skip the last step */
596   if (ts->reason) { /* only affect the forward run */
597     /* update total_steps in the end of forward run */
598     if (stepnum != tjsch->total_steps) tjsch->total_steps = stepnum;
599     if (stack->solution_only) {
600       /* get rid of the solution at second last step */
601       ierr = StackPop(stack,&e);CHKERRQ(ierr);
602       ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
603     }
604     PetscFunctionReturn(0);
605   }
606   /*  do not save trajectory at the recompute stage for solution_only mode */
607   if (stack->solution_only && tjsch->recompute) PetscFunctionReturn(0);
608   /* skip the first step for no_solution_only mode */
609   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(0);
610 
611   /* resize the stack */
612   if (stack->top+1 == stack->stacksize) {
613     ierr = StackResize(stack,2*stack->stacksize);CHKERRQ(ierr);
614   }
615   /* update timenext for the previous step; necessary for step adaptivity */
616   if (stack->top > -1) {
617     ierr = StackTop(stack,&e);CHKERRQ(ierr);
618     e->timenext = ts->ptime;
619   }
620   if (stepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
621   ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
622   ierr = ElementSet(ts,stack,&e,stepnum,time,X);CHKERRQ(ierr);
623   ierr = StackPush(stack,e);CHKERRQ(ierr);
624   PetscFunctionReturn(0);
625 }
626 
627 static PetscErrorCode GetTrajN(TS ts,TJScheduler *tjsch,PetscInt stepnum)
628 {
629   Stack          *stack = &tjsch->stack;
630   StackElement   e;
631   PetscErrorCode ierr;
632 
633   PetscFunctionBegin;
634   if (stepnum == tjsch->total_steps) {
635     ierr = TurnBackward(ts);CHKERRQ(ierr);
636     PetscFunctionReturn(0);
637   }
638   /* restore a checkpoint */
639   ierr = StackTop(stack,&e);CHKERRQ(ierr);
640   ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
641   if (stack->solution_only) {/* recompute one step */
642     tjsch->recompute = PETSC_TRUE;
643     ierr = TurnForwardWithStepsize(ts,e->timenext-e->time);CHKERRQ(ierr);
644     ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
645   }
646   ierr = StackPop(stack,&e);CHKERRQ(ierr);
647   ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
648   PetscFunctionReturn(0);
649 }
650 
651 static PetscErrorCode SetTrajTLNR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
652 {
653   Stack          *stack = &tjsch->stack;
654   PetscInt       localstepnum,laststridesize;
655   StackElement   e;
656   PetscBool      done;
657   PetscErrorCode ierr;
658 
659   PetscFunctionBegin;
660   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(0);
661   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(0);
662   if (tjsch->save_stack && tjsch->recompute) PetscFunctionReturn(0);
663 
664   localstepnum = stepnum%tjsch->stride;
665   /* (stride size-1) checkpoints are saved in each stride; an extra point is added by StackDumpAll() */
666   laststridesize = tjsch->total_steps%tjsch->stride;
667   if (!laststridesize) laststridesize = tjsch->stride;
668 
669   if (!tjsch->recompute) {
670     ierr = TopLevelStore(tj,ts,tjsch,stepnum,localstepnum,laststridesize,&done);CHKERRQ(ierr);
671     if (!tjsch->save_stack && stepnum < tjsch->total_steps-laststridesize) PetscFunctionReturn(0);
672   }
673   if (!stack->solution_only && localstepnum == 0) PetscFunctionReturn(0); /* skip last point in each stride at recompute stage or last stride */
674   if (stack->solution_only && localstepnum == tjsch->stride-1) PetscFunctionReturn(0); /* skip last step in each stride at recompute stage or last stride */
675 
676   ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
677   ierr = ElementSet(ts,stack,&e,stepnum,time,X);CHKERRQ(ierr);
678   ierr = StackPush(stack,e);CHKERRQ(ierr);
679   PetscFunctionReturn(0);
680 }
681 
682 static PetscErrorCode GetTrajTLNR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
683 {
684   Stack          *stack = &tjsch->stack;
685   PetscInt       id,localstepnum,laststridesize;
686   StackElement   e;
687   PetscErrorCode ierr;
688 
689   PetscFunctionBegin;
690   if (stepnum == tjsch->total_steps) {
691     ierr = TurnBackward(ts);CHKERRQ(ierr);
692     PetscFunctionReturn(0);
693   }
694 
695   localstepnum = stepnum%tjsch->stride;
696   laststridesize = tjsch->total_steps%tjsch->stride;
697   if (!laststridesize) laststridesize = tjsch->stride;
698   if (stack->solution_only) {
699     /* fill stack with info */
700     if (localstepnum == 0 && tjsch->total_steps-stepnum >= laststridesize) {
701       id = stepnum/tjsch->stride;
702       if (tjsch->save_stack) {
703         ierr = StackLoadAll(tj,ts,stack,id);CHKERRQ(ierr);
704         tjsch->recompute = PETSC_TRUE;
705         tjsch->skip_trajectory = PETSC_TRUE;
706         ierr = TurnForward(ts);CHKERRQ(ierr);
707         ierr = ReCompute(ts,tjsch,id*tjsch->stride-1,id*tjsch->stride);CHKERRQ(ierr);
708         tjsch->skip_trajectory = PETSC_FALSE;
709       } else {
710         ierr = LoadSingle(tj,ts,stack,id);CHKERRQ(ierr);
711         tjsch->recompute = PETSC_TRUE;
712         ierr = TurnForward(ts);CHKERRQ(ierr);
713         ierr = ReCompute(ts,tjsch,(id-1)*tjsch->stride,id*tjsch->stride);CHKERRQ(ierr);
714       }
715       PetscFunctionReturn(0);
716     }
717     /* restore a checkpoint */
718     ierr = StackPop(stack,&e);CHKERRQ(ierr);
719     ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
720     tjsch->recompute = PETSC_TRUE;
721     tjsch->skip_trajectory = PETSC_TRUE;
722     ierr = TurnForward(ts);CHKERRQ(ierr);
723     ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
724     tjsch->skip_trajectory = PETSC_FALSE;
725     ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
726   } else {
727     /* fill stack with info */
728     if (localstepnum == 0 && tjsch->total_steps-stepnum >= laststridesize) {
729       id = stepnum/tjsch->stride;
730       if (tjsch->save_stack) {
731         ierr = StackLoadAll(tj,ts,stack,id);CHKERRQ(ierr);
732       } else {
733         ierr = LoadSingle(tj,ts,stack,id);CHKERRQ(ierr);
734         ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
735         ierr = ElementSet(ts,stack,&e,(id-1)*tjsch->stride+1,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
736         ierr = StackPush(stack,e);CHKERRQ(ierr);
737         tjsch->recompute = PETSC_TRUE;
738         ierr = TurnForward(ts);CHKERRQ(ierr);
739         ierr = ReCompute(ts,tjsch,e->stepnum,id*tjsch->stride);CHKERRQ(ierr);
740       }
741       PetscFunctionReturn(0);
742     }
743     /* restore a checkpoint */
744     ierr = StackPop(stack,&e);CHKERRQ(ierr);
745     ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
746     ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
747   }
748   PetscFunctionReturn(0);
749 }
750 
751 #if defined(PETSC_HAVE_REVOLVE)
752 static PetscErrorCode printwhattodo(PetscViewer viewer,PetscInt whattodo,RevolveCTX *rctx,PetscInt shift)
753 {
754   PetscErrorCode ierr;
755 
756   PetscFunctionBegin;
757   if (!viewer) PetscFunctionReturn(0);
758 
759   switch(whattodo) {
760     case 1:
761       ierr = PetscViewerASCIIPrintf(viewer,"Advance from %D to %D\n",rctx->oldcapo+shift,rctx->capo+shift);CHKERRQ(ierr);
762       break;
763     case 2:
764       ierr = PetscViewerASCIIPrintf(viewer,"Store in checkpoint number %D (located in RAM)\n",rctx->check);CHKERRQ(ierr);
765       break;
766     case 3:
767       ierr = PetscViewerASCIIPrintf(viewer,"First turn: Initialize adjoints and reverse first step\n");CHKERRQ(ierr);
768       break;
769     case 4:
770       ierr = PetscViewerASCIIPrintf(viewer,"Forward and reverse one step\n");CHKERRQ(ierr);
771       break;
772     case 5:
773       ierr = PetscViewerASCIIPrintf(viewer,"Restore in checkpoint number %D (located in RAM)\n",rctx->check);CHKERRQ(ierr);
774       break;
775     case 7:
776       ierr = PetscViewerASCIIPrintf(viewer,"Store in checkpoint number %D (located on disk)\n",rctx->check);CHKERRQ(ierr);
777       break;
778     case 8:
779       ierr = PetscViewerASCIIPrintf(viewer,"Restore in checkpoint number %D (located on disk)\n",rctx->check);CHKERRQ(ierr);
780       break;
781     case -1:
782       ierr = PetscViewerASCIIPrintf(viewer,"Error!");CHKERRQ(ierr);
783       break;
784   }
785   PetscFunctionReturn(0);
786 }
787 
788 static PetscErrorCode printwhattodo2(PetscViewer viewer,PetscInt whattodo,RevolveCTX *rctx,PetscInt shift)
789 {
790   PetscErrorCode ierr;
791 
792   PetscFunctionBegin;
793   if (!viewer) PetscFunctionReturn(0);
794 
795   switch(whattodo) {
796     case 1:
797       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] Advance from stride %D to stride %D\n",rctx->oldcapo+shift,rctx->capo+shift);CHKERRQ(ierr);
798       break;
799     case 2:
800       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] Store in checkpoint number %D\n",rctx->check);CHKERRQ(ierr);
801       break;
802     case 3:
803       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] First turn: Initialize adjoints and reverse first stride\n");CHKERRQ(ierr);
804       break;
805     case 4:
806       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] Forward and reverse one stride\n");CHKERRQ(ierr);
807       break;
808     case 5:
809       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] Restore in checkpoint number %D\n",rctx->check);CHKERRQ(ierr);
810       break;
811     case 7:
812       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] Store in top-level checkpoint number %D\n",rctx->check);CHKERRQ(ierr);
813       break;
814     case 8:
815       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] Restore in top-level checkpoint number %D\n",rctx->check);CHKERRQ(ierr);
816       break;
817     case -1:
818       ierr = PetscViewerASCIIPrintf(viewer,"[Top Level] Error!");CHKERRQ(ierr);
819       break;
820   }
821   PetscFunctionReturn(0);
822 }
823 
824 static PetscErrorCode InitRevolve(PetscInt fine,PetscInt snaps,RevolveCTX *rctx)
825 {
826   PetscFunctionBegin;
827   revolve_reset();
828   revolve_create_offline(fine,snaps);
829   rctx->snaps_in       = snaps;
830   rctx->fine           = fine;
831   rctx->check          = 0;
832   rctx->capo           = 0;
833   rctx->reverseonestep = PETSC_FALSE;
834   /* check stepsleft? */
835   PetscFunctionReturn(0);
836 }
837 
838 static PetscErrorCode FastForwardRevolve(RevolveCTX *rctx)
839 {
840   PetscInt whattodo;
841 
842   PetscFunctionBegin;
843   whattodo = 0;
844   while(whattodo!=3) { /* we have to fast forward revolve to the beginning of the backward sweep due to unfriendly revolve interface */
845     whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
846   }
847   PetscFunctionReturn(0);
848 }
849 
850 static PetscErrorCode ApplyRevolve(PetscViewer viewer,SchedulerType stype,RevolveCTX *rctx,PetscInt total_steps,PetscInt stepnum,PetscInt localstepnum,PetscBool toplevel,PetscInt *store)
851 {
852   PetscErrorCode ierr;
853   PetscInt       shift,whattodo;
854 
855   PetscFunctionBegin;
856   *store = 0;
857   if (rctx->stepsleft > 0) { /* advance the solution without checkpointing anything as Revolve requires */
858     rctx->stepsleft--;
859     PetscFunctionReturn(0);
860   }
861   /* let Revolve determine what to do next */
862   shift         = stepnum-localstepnum;
863   rctx->oldcapo = rctx->capo;
864   rctx->capo    = localstepnum;
865 
866   if (!toplevel) whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
867   else whattodo = revolve2_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
868   if (stype == REVOLVE_ONLINE && whattodo == 8) whattodo = 5;
869   if (stype == REVOLVE_ONLINE && whattodo == 7) whattodo = 2;
870   if (!toplevel) {ierr = printwhattodo(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
871   else {ierr = printwhattodo2(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
872   if (whattodo == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in the Revolve library");
873   if (whattodo == 1) { /* advance some time steps */
874     if (stype == REVOLVE_ONLINE && rctx->capo >= total_steps-1) {
875       revolve_turn(total_steps,&rctx->capo,&rctx->fine);
876       if (!toplevel) {ierr = printwhattodo(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
877       else {ierr = printwhattodo2(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
878     }
879     rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
880   }
881   if (whattodo == 3 || whattodo == 4) { /* ready for a reverse step */
882     rctx->reverseonestep = PETSC_TRUE;
883   }
884   if (whattodo == 5) { /* restore a checkpoint and ask Revolve what to do next */
885     rctx->oldcapo = rctx->capo;
886     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*/
887     else whattodo = revolve2_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
888     if (!toplevel) {ierr = printwhattodo(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
889     else {ierr = printwhattodo2(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
890     if (whattodo == 3 || whattodo == 4) rctx->reverseonestep = PETSC_TRUE;
891     if (whattodo == 1) rctx->stepsleft = rctx->capo-rctx->oldcapo;
892   }
893   if (whattodo == 7) { /* save the checkpoint to disk */
894     *store = 2;
895     rctx->oldcapo = rctx->capo;
896     whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where); /* must return 1 */
897     ierr = printwhattodo(viewer,whattodo,rctx,shift);CHKERRQ(ierr);
898     rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
899   }
900   if (whattodo == 2) { /* store a checkpoint to RAM and ask Revolve how many time steps to advance next */
901     *store = 1;
902     rctx->oldcapo = rctx->capo;
903     if (!toplevel) whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where); /* must return 1 */
904     else whattodo = revolve2_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
905     if (!toplevel) {ierr = printwhattodo(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
906     else {ierr = printwhattodo2(viewer,whattodo,rctx,shift);CHKERRQ(ierr);}
907     if (stype == REVOLVE_ONLINE && rctx->capo >= total_steps-1) {
908       revolve_turn(total_steps,&rctx->capo,&rctx->fine);
909       ierr = printwhattodo(viewer,whattodo,rctx,shift);CHKERRQ(ierr);
910     }
911     rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
912   }
913   PetscFunctionReturn(0);
914 }
915 
916 static PetscErrorCode SetTrajROF(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
917 {
918   Stack          *stack = &tjsch->stack;
919   PetscInt       store;
920   StackElement   e;
921   PetscErrorCode ierr;
922 
923   PetscFunctionBegin;
924   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(0);
925   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(0);
926   ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
927   if (store == 1) {
928     if (stepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
929     ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
930     ierr = ElementSet(ts,stack,&e,stepnum,time,X);CHKERRQ(ierr);
931     ierr = StackPush(stack,e);CHKERRQ(ierr);
932   }
933   PetscFunctionReturn(0);
934 }
935 
936 static PetscErrorCode GetTrajROF(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
937 {
938   Stack          *stack = &tjsch->stack;
939   PetscInt       whattodo,shift,store;
940   StackElement   e;
941   PetscErrorCode ierr;
942 
943   PetscFunctionBegin;
944   if (stepnum == 0 || stepnum == tjsch->total_steps) {
945     ierr = TurnBackward(ts);CHKERRQ(ierr);
946     tjsch->rctx->reverseonestep = PETSC_FALSE;
947     PetscFunctionReturn(0);
948   }
949   /* restore a checkpoint */
950   ierr = StackTop(stack,&e);CHKERRQ(ierr);
951   ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
952   if (stack->solution_only) { /* start with restoring a checkpoint */
953     tjsch->rctx->capo = stepnum;
954     tjsch->rctx->oldcapo = tjsch->rctx->capo;
955     shift = 0;
956     whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where);
957     ierr = printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);CHKERRQ(ierr);
958   } else { /* 2 revolve actions: restore a checkpoint and then advance */
959     ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
960     if (tj->monitor) {
961       ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
962       ierr = PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",tjsch->rctx->oldcapo,tjsch->rctx->oldcapo+1);CHKERRQ(ierr);
963       ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
964     }
965     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
966   }
967   if (stack->solution_only || (!stack->solution_only && e->stepnum < stepnum)) {
968     tjsch->recompute = PETSC_TRUE;
969     ierr = TurnForward(ts);CHKERRQ(ierr);
970     ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
971   }
972   if ((stack->solution_only && e->stepnum+1 == stepnum) || (!stack->solution_only && e->stepnum == stepnum)) {
973     ierr = StackPop(stack,&e);CHKERRQ(ierr);
974     ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
975   }
976   tjsch->rctx->reverseonestep = PETSC_FALSE;
977   PetscFunctionReturn(0);
978 }
979 
980 static PetscErrorCode SetTrajRON(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
981 {
982   Stack          *stack = &tjsch->stack;
983   Vec            *Y;
984   PetscInt       i,store;
985   PetscReal      timeprev;
986   StackElement   e;
987   RevolveCTX     *rctx = tjsch->rctx;
988   PetscErrorCode ierr;
989 
990   PetscFunctionBegin;
991   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(0);
992   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(0);
993   ierr = ApplyRevolve(tj->monitor,tjsch->stype,rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
994   if (store == 1) {
995     if (rctx->check != stack->top+1) { /* overwrite some non-top checkpoint in the stack */
996       ierr = StackFind(stack,&e,rctx->check);CHKERRQ(ierr);
997       ierr = VecCopy(X,e->X);CHKERRQ(ierr);
998       if (stack->numY > 0 && !stack->solution_only) {
999         ierr = TSGetStages(ts,&stack->numY,&Y);CHKERRQ(ierr);
1000         for (i=0;i<stack->numY;i++) {
1001           ierr = VecCopy(Y[i],e->Y[i]);CHKERRQ(ierr);
1002         }
1003       }
1004       e->stepnum  = stepnum;
1005       e->time     = time;
1006       ierr        = TSGetPrevTime(ts,&timeprev);CHKERRQ(ierr);
1007       e->timeprev = timeprev;
1008     } else {
1009       if (stepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
1010       ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
1011       ierr = ElementSet(ts,stack,&e,stepnum,time,X);CHKERRQ(ierr);
1012       ierr = StackPush(stack,e);CHKERRQ(ierr);
1013     }
1014   }
1015   PetscFunctionReturn(0);
1016 }
1017 
1018 static PetscErrorCode GetTrajRON(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
1019 {
1020   Stack          *stack = &tjsch->stack;
1021   PetscInt       whattodo,shift;
1022   StackElement   e;
1023   PetscErrorCode ierr;
1024 
1025   PetscFunctionBegin;
1026   if (stepnum == 0 || stepnum == tjsch->total_steps) {
1027     ierr = TurnBackward(ts);CHKERRQ(ierr);
1028     tjsch->rctx->reverseonestep = PETSC_FALSE;
1029     PetscFunctionReturn(0);
1030   }
1031   tjsch->rctx->capo = stepnum;
1032   tjsch->rctx->oldcapo = tjsch->rctx->capo;
1033   shift = 0;
1034   whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where); /* whattodo=restore */
1035   if (whattodo == 8) whattodo = 5;
1036   ierr = printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);CHKERRQ(ierr);
1037   /* restore a checkpoint */
1038   ierr = StackFind(stack,&e,tjsch->rctx->check);CHKERRQ(ierr);
1039   ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
1040   if (!stack->solution_only) { /* whattodo must be 5 */
1041     /* ask Revolve what to do next */
1042     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1043     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*/
1044     ierr = printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);CHKERRQ(ierr);
1045     if (whattodo == 3 || whattodo == 4) tjsch->rctx->reverseonestep = PETSC_TRUE;
1046     if (whattodo == 1) tjsch->rctx->stepsleft = tjsch->rctx->capo-tjsch->rctx->oldcapo;
1047     if (tj->monitor) {
1048       ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1049       ierr = PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",tjsch->rctx->oldcapo,tjsch->rctx->oldcapo+1);CHKERRQ(ierr);
1050       ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1051     }
1052     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1053   }
1054   if (stack->solution_only || (!stack->solution_only && e->stepnum < stepnum)) {
1055     tjsch->recompute = PETSC_TRUE;
1056     ierr = TurnForward(ts);CHKERRQ(ierr);
1057     ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
1058   }
1059   tjsch->rctx->reverseonestep = PETSC_FALSE;
1060   PetscFunctionReturn(0);
1061 }
1062 
1063 static PetscErrorCode SetTrajTLR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
1064 {
1065   Stack          *stack = &tjsch->stack;
1066   PetscInt       store,localstepnum,laststridesize;
1067   StackElement   e;
1068   PetscBool      done = PETSC_FALSE;
1069   PetscErrorCode ierr;
1070 
1071   PetscFunctionBegin;
1072   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(0);
1073   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(0);
1074 
1075   localstepnum = stepnum%tjsch->stride;
1076   laststridesize = tjsch->total_steps%tjsch->stride;
1077   if (!laststridesize) laststridesize = tjsch->stride;
1078 
1079   if (!tjsch->recompute) {
1080     ierr = TopLevelStore(tj,ts,tjsch,stepnum,localstepnum,laststridesize,&done);CHKERRQ(ierr);
1081     /* revolve is needed for the last stride; different starting points for last stride between solutin_only and !solutin_only */
1082     if (!stack->solution_only && !tjsch->save_stack && stepnum <= tjsch->total_steps-laststridesize) PetscFunctionReturn(0);
1083     if (stack->solution_only && !tjsch->save_stack && stepnum < tjsch->total_steps-laststridesize) PetscFunctionReturn(0);
1084   }
1085   if (tjsch->save_stack && done) {
1086     ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1087     PetscFunctionReturn(0);
1088   }
1089   if (laststridesize < tjsch->stride) {
1090     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 */
1091       ierr = InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1092     }
1093     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 */
1094       ierr = InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1095     }
1096   }
1097   ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
1098   if (store == 1) {
1099     if (localstepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
1100     ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
1101     ierr = ElementSet(ts,stack,&e,stepnum,time,X);CHKERRQ(ierr);
1102     ierr = StackPush(stack,e);CHKERRQ(ierr);
1103   }
1104   PetscFunctionReturn(0);
1105 }
1106 
1107 static PetscErrorCode GetTrajTLR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
1108 {
1109   Stack          *stack = &tjsch->stack;
1110   PetscInt       whattodo,shift;
1111   PetscInt       localstepnum,stridenum,laststridesize,store;
1112   StackElement   e;
1113   PetscErrorCode ierr;
1114 
1115   PetscFunctionBegin;
1116   localstepnum = stepnum%tjsch->stride;
1117   stridenum    = stepnum/tjsch->stride;
1118   if (stepnum == tjsch->total_steps) {
1119     ierr = TurnBackward(ts);CHKERRQ(ierr);
1120     tjsch->rctx->reverseonestep = PETSC_FALSE;
1121     PetscFunctionReturn(0);
1122   }
1123   laststridesize = tjsch->total_steps%tjsch->stride;
1124   if (!laststridesize) laststridesize = tjsch->stride;
1125   if (stack->solution_only) {
1126     /* fill stack */
1127     if (localstepnum == 0 && stepnum <= tjsch->total_steps-laststridesize) {
1128       if (tjsch->save_stack) {
1129         ierr = StackLoadAll(tj,ts,stack,stridenum);CHKERRQ(ierr);
1130         ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1131         ierr = FastForwardRevolve(tjsch->rctx);CHKERRQ(ierr);
1132         tjsch->recompute = PETSC_TRUE;
1133         tjsch->skip_trajectory = PETSC_TRUE;
1134         ierr = TurnForward(ts);CHKERRQ(ierr);
1135         ierr = ReCompute(ts,tjsch,stridenum*tjsch->stride-1,stridenum*tjsch->stride);CHKERRQ(ierr);
1136         tjsch->skip_trajectory = PETSC_FALSE;
1137       } else {
1138         ierr = LoadSingle(tj,ts,stack,stridenum);CHKERRQ(ierr);
1139         ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1140         tjsch->recompute = PETSC_TRUE;
1141         ierr = TurnForward(ts);CHKERRQ(ierr);
1142         ierr = ReCompute(ts,tjsch,(stridenum-1)*tjsch->stride,stridenum*tjsch->stride);CHKERRQ(ierr);
1143       }
1144       PetscFunctionReturn(0);
1145     }
1146     /* restore a checkpoint */
1147     ierr = StackTop(stack,&e);CHKERRQ(ierr);
1148     ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
1149     /* start with restoring a checkpoint */
1150     tjsch->rctx->capo = stepnum;
1151     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1152     shift = stepnum-localstepnum;
1153     whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where);
1154     ierr = printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);CHKERRQ(ierr);
1155     tjsch->recompute = PETSC_TRUE;
1156     ierr = TurnForward(ts);CHKERRQ(ierr);
1157     ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
1158     if (e->stepnum+1 == stepnum) {
1159       ierr = StackPop(stack,&e);CHKERRQ(ierr);
1160       ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
1161     }
1162   } else {
1163     /* fill stack with info */
1164     if (localstepnum == 0 && tjsch->total_steps-stepnum >= laststridesize) {
1165       if (tjsch->save_stack) {
1166         ierr = StackLoadAll(tj,ts,stack,stridenum);CHKERRQ(ierr);
1167         ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1168         ierr = FastForwardRevolve(tjsch->rctx);CHKERRQ(ierr);
1169       } else {
1170         ierr = LoadSingle(tj,ts,stack,stridenum);CHKERRQ(ierr);
1171         ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1172         ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,(stridenum-1)*tjsch->stride+1,1,PETSC_FALSE,&store);CHKERRQ(ierr);
1173         if (tj->monitor) {
1174           ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1175           ierr = 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);CHKERRQ(ierr);
1176           ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1177         }
1178         ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
1179         ierr = ElementSet(ts,stack,&e,(stridenum-1)*tjsch->stride+1,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
1180         ierr = StackPush(stack,e);CHKERRQ(ierr);
1181         tjsch->recompute = PETSC_TRUE;
1182         ierr = TurnForward(ts);CHKERRQ(ierr);
1183         ierr = ReCompute(ts,tjsch,e->stepnum,stridenum*tjsch->stride);CHKERRQ(ierr);
1184       }
1185       PetscFunctionReturn(0);
1186     }
1187     /* restore a checkpoint */
1188     ierr = StackTop(stack,&e);CHKERRQ(ierr);
1189     ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
1190     /* 2 revolve actions: restore a checkpoint and then advance */
1191     ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
1192     if (tj->monitor) {
1193       ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1194       ierr = 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);CHKERRQ(ierr);
1195       ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1196     }
1197     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1198     if (e->stepnum < stepnum) {
1199       tjsch->recompute = PETSC_TRUE;
1200       ierr = TurnForward(ts);CHKERRQ(ierr);
1201       ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
1202     }
1203     if (e->stepnum == stepnum) {
1204       ierr = StackPop(stack,&e);CHKERRQ(ierr);
1205       ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
1206     }
1207   }
1208   tjsch->rctx->reverseonestep = PETSC_FALSE;
1209   PetscFunctionReturn(0);
1210 }
1211 
1212 static PetscErrorCode SetTrajTLTR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
1213 {
1214   Stack          *stack = &tjsch->stack;
1215   PetscInt       store,localstepnum,stridenum,laststridesize;
1216   StackElement   e;
1217   PetscBool      done = PETSC_FALSE;
1218   PetscErrorCode ierr;
1219 
1220   PetscFunctionBegin;
1221   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(0);
1222   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(0);
1223 
1224   localstepnum = stepnum%tjsch->stride; /* index at the bottom level (inside a stride) */
1225   stridenum    = stepnum/tjsch->stride; /* index at the top level */
1226   laststridesize = tjsch->total_steps%tjsch->stride;
1227   if (!laststridesize) laststridesize = tjsch->stride;
1228   if (stack->solution_only && localstepnum == 0 && !tjsch->rctx2->reverseonestep) {
1229     ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx2,(tjsch->total_steps+tjsch->stride-1)/tjsch->stride,stridenum,stridenum,PETSC_TRUE,&tjsch->store_stride);CHKERRQ(ierr);
1230     if (laststridesize < tjsch->stride && stepnum == tjsch->total_steps-laststridesize) {
1231       ierr = InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1232     }
1233   }
1234   if (!stack->solution_only && localstepnum == 1 && !tjsch->rctx2->reverseonestep) {
1235     ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx2,(tjsch->total_steps+tjsch->stride-1)/tjsch->stride,stridenum,stridenum,PETSC_TRUE,&tjsch->store_stride);CHKERRQ(ierr);
1236     if (laststridesize < tjsch->stride && stepnum == tjsch->total_steps-laststridesize+1) {
1237       ierr = InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1238     }
1239   }
1240   if (tjsch->store_stride) {
1241     ierr = TopLevelStore(tj,ts,tjsch,stepnum,localstepnum,laststridesize,&done);CHKERRQ(ierr);
1242     if (done) {
1243       ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1244       PetscFunctionReturn(0);
1245     }
1246   }
1247   if (stepnum < tjsch->total_steps-laststridesize) {
1248     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 */
1249     if (!tjsch->save_stack && !tjsch->rctx2->reverseonestep) PetscFunctionReturn(0); /* store operation does not require revolve be called at bottom level */
1250   }
1251   /* 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 */
1252   if (!stack->solution_only && localstepnum == 0 && stepnum != tjsch->total_steps && !tjsch->recompute) PetscFunctionReturn(0);
1253   ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
1254   if (store == 1) {
1255     if (localstepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
1256     ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
1257     ierr = ElementSet(ts,stack,&e,stepnum,time,X);CHKERRQ(ierr);
1258     ierr = StackPush(stack,e);CHKERRQ(ierr);
1259   }
1260   PetscFunctionReturn(0);
1261 }
1262 
1263 static PetscErrorCode GetTrajTLTR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
1264 {
1265   Stack          *stack = &tjsch->stack;
1266   DiskStack      *diskstack = &tjsch->diskstack;
1267   PetscInt       whattodo,shift;
1268   PetscInt       localstepnum,stridenum,restoredstridenum,laststridesize,store;
1269   StackElement   e;
1270   PetscErrorCode ierr;
1271 
1272   PetscFunctionBegin;
1273   localstepnum = stepnum%tjsch->stride;
1274   stridenum    = stepnum/tjsch->stride;
1275   if (stepnum == tjsch->total_steps) {
1276     ierr = TurnBackward(ts);CHKERRQ(ierr);
1277     tjsch->rctx->reverseonestep = PETSC_FALSE;
1278     PetscFunctionReturn(0);
1279   }
1280   laststridesize = tjsch->total_steps%tjsch->stride;
1281   if (!laststridesize) laststridesize = tjsch->stride;
1282   /*
1283    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:
1284      Case 1 (save_stack)
1285        Restore a disk checkpoint; update TS with the last element in the restored data; recompute to the current point.
1286      Case 2 (!save_stack)
1287        Restore a disk checkpoint; update TS with the restored point; recompute to the current point.
1288   */
1289   if (localstepnum == 0 && stepnum <= tjsch->total_steps-laststridesize) {
1290     /* restore the top element in the stack for disk checkpoints */
1291     restoredstridenum = diskstack->container[diskstack->top];
1292     tjsch->rctx2->reverseonestep = PETSC_FALSE;
1293     /* top-level revolve must be applied before current step, just like the solution_only mode for single-level revolve */
1294     if (!tjsch->save_stack && stack->solution_only) { /* start with restoring a checkpoint */
1295       tjsch->rctx2->capo = stridenum;
1296       tjsch->rctx2->oldcapo = tjsch->rctx2->capo;
1297       shift = 0;
1298       whattodo = revolve2_action(&tjsch->rctx2->check,&tjsch->rctx2->capo,&tjsch->rctx2->fine,tjsch->rctx2->snaps_in,&tjsch->rctx2->info,&tjsch->rctx2->where);
1299       ierr = printwhattodo2(tj->monitor,whattodo,tjsch->rctx2,shift);CHKERRQ(ierr);
1300     } else { /* 2 revolve actions: restore a checkpoint and then advance */
1301       ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx2,(tjsch->total_steps+tjsch->stride-1)/tjsch->stride,stridenum,stridenum,PETSC_TRUE,&tjsch->store_stride);CHKERRQ(ierr);
1302       if (tj->monitor) {
1303         ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1304         ierr = PetscViewerASCIIPrintf(tj->monitor,"[Top Level] Skip the stride from %D to %D (stage values already checkpointed)\n",tjsch->rctx2->oldcapo,tjsch->rctx2->oldcapo+1);CHKERRQ(ierr);
1305         ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1306       }
1307       if (!tjsch->rctx2->reverseonestep && tjsch->rctx2->stepsleft > 0) tjsch->rctx2->stepsleft--;
1308     }
1309     /* fill stack */
1310     if (stack->solution_only) {
1311       if (tjsch->save_stack) {
1312         if (restoredstridenum < stridenum) {
1313           ierr = StackLoadLast(tj,ts,stack,restoredstridenum);CHKERRQ(ierr);
1314         } else {
1315           ierr = StackLoadAll(tj,ts,stack,restoredstridenum);CHKERRQ(ierr);
1316         }
1317         /* recompute one step ahead */
1318         tjsch->recompute = PETSC_TRUE;
1319         tjsch->skip_trajectory = PETSC_TRUE;
1320         ierr = TurnForward(ts);CHKERRQ(ierr);
1321         ierr = ReCompute(ts,tjsch,stridenum*tjsch->stride-1,stridenum*tjsch->stride);CHKERRQ(ierr);
1322         tjsch->skip_trajectory = PETSC_FALSE;
1323         if (restoredstridenum < stridenum) {
1324           ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1325           tjsch->recompute = PETSC_TRUE;
1326           ierr = TurnForward(ts);CHKERRQ(ierr);
1327           ierr = ReCompute(ts,tjsch,restoredstridenum*tjsch->stride,stepnum);CHKERRQ(ierr);
1328         } else { /* stack ready, fast forward revolve status */
1329           ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1330           ierr = FastForwardRevolve(tjsch->rctx);CHKERRQ(ierr);
1331         }
1332       } else {
1333         ierr = LoadSingle(tj,ts,stack,restoredstridenum);CHKERRQ(ierr);
1334         ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1335         tjsch->recompute = PETSC_TRUE;
1336         ierr = TurnForward(ts);CHKERRQ(ierr);
1337         ierr = ReCompute(ts,tjsch,(restoredstridenum-1)*tjsch->stride,stepnum);CHKERRQ(ierr);
1338       }
1339     } else {
1340       if (tjsch->save_stack) {
1341         if (restoredstridenum < stridenum) {
1342           ierr = StackLoadLast(tj,ts,stack,restoredstridenum);CHKERRQ(ierr);
1343           /* reset revolve */
1344           ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1345           tjsch->recompute = PETSC_TRUE;
1346           ierr = TurnForward(ts);CHKERRQ(ierr);
1347           ierr = ReCompute(ts,tjsch,restoredstridenum*tjsch->stride,stepnum);CHKERRQ(ierr);
1348         } else { /* stack ready, fast forward revolve status */
1349           ierr = StackLoadAll(tj,ts,stack,restoredstridenum);CHKERRQ(ierr);
1350           ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1351           ierr = FastForwardRevolve(tjsch->rctx);CHKERRQ(ierr);
1352         }
1353       } else {
1354         ierr = LoadSingle(tj,ts,stack,restoredstridenum);CHKERRQ(ierr);
1355         ierr = InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);CHKERRQ(ierr);
1356         /* push first element to stack */
1357         if (tjsch->store_stride || tjsch->rctx2->reverseonestep) {
1358           shift = (restoredstridenum-1)*tjsch->stride-localstepnum;
1359           ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,(restoredstridenum-1)*tjsch->stride+1,1,PETSC_FALSE,&store);CHKERRQ(ierr);
1360           if (tj->monitor) {
1361             ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1362             ierr = PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",(restoredstridenum-1)*tjsch->stride,(restoredstridenum-1)*tjsch->stride+1);CHKERRQ(ierr);
1363             ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1364           }
1365           ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
1366           ierr = ElementSet(ts,stack,&e,(restoredstridenum-1)*tjsch->stride+1,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
1367           ierr = StackPush(stack,e);CHKERRQ(ierr);
1368         }
1369         tjsch->recompute = PETSC_TRUE;
1370         ierr = TurnForward(ts);CHKERRQ(ierr);
1371         ierr = ReCompute(ts,tjsch,(restoredstridenum-1)*tjsch->stride+1,stepnum);CHKERRQ(ierr);
1372       }
1373     }
1374     if (restoredstridenum == stridenum) diskstack->top--;
1375     tjsch->rctx->reverseonestep = PETSC_FALSE;
1376     PetscFunctionReturn(0);
1377   }
1378 
1379   if (stack->solution_only) {
1380     /* restore a checkpoint */
1381     ierr = StackTop(stack,&e);CHKERRQ(ierr);
1382     ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
1383     /* start with restoring a checkpoint */
1384     tjsch->rctx->capo = stepnum;
1385     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1386     shift = stepnum-localstepnum;
1387     whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where);
1388     ierr = printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);CHKERRQ(ierr);
1389     tjsch->recompute = PETSC_TRUE;
1390     ierr = TurnForward(ts);CHKERRQ(ierr);
1391     ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
1392     if (e->stepnum+1 == stepnum) {
1393       ierr = StackPop(stack,&e);CHKERRQ(ierr);
1394       ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
1395     }
1396   } else {
1397     /* restore a checkpoint */
1398     ierr = StackTop(stack,&e);CHKERRQ(ierr);
1399     ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
1400     /* 2 revolve actions: restore a checkpoint and then advance */
1401     ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
1402     if (tj->monitor) {
1403       ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1404       ierr = 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);CHKERRQ(ierr);
1405       ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1406     }
1407     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1408     if (e->stepnum < stepnum) {
1409       tjsch->recompute = PETSC_TRUE;
1410       ierr = TurnForward(ts);CHKERRQ(ierr);
1411       ierr = ReCompute(ts,tjsch,e->stepnum,stepnum);CHKERRQ(ierr);
1412     }
1413     if (e->stepnum == stepnum) {
1414       ierr = StackPop(stack,&e);CHKERRQ(ierr);
1415       ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
1416     }
1417   }
1418   tjsch->rctx->reverseonestep = PETSC_FALSE;
1419   PetscFunctionReturn(0);
1420 }
1421 
1422 static PetscErrorCode SetTrajRMS(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
1423 {
1424   Stack          *stack = &tjsch->stack;
1425   PetscInt       store;
1426   StackElement   e;
1427   PetscErrorCode ierr;
1428 
1429   PetscFunctionBegin;
1430   if (!stack->solution_only && stepnum == 0) PetscFunctionReturn(0);
1431   if (stack->solution_only && stepnum == tjsch->total_steps) PetscFunctionReturn(0);
1432   ierr = ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);CHKERRQ(ierr);
1433   if (store == 1){
1434     if (stepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
1435     ierr = ElementCreate(ts,stack,&e);CHKERRQ(ierr);
1436     ierr = ElementSet(ts,stack,&e,stepnum,time,X);CHKERRQ(ierr);
1437     ierr = StackPush(stack,e);CHKERRQ(ierr);
1438   } else if (store == 2) {
1439     ierr = DumpSingle(tj,ts,stack,tjsch->rctx->check+1);CHKERRQ(ierr);
1440   }
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 static PetscErrorCode GetTrajRMS(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
1445 {
1446   Stack          *stack = &tjsch->stack;
1447   PetscInt       whattodo,shift;
1448   PetscInt       restart;
1449   PetscBool      ondisk;
1450   StackElement   e;
1451   PetscErrorCode ierr;
1452 
1453   PetscFunctionBegin;
1454   if (stepnum == 0 || stepnum == tjsch->total_steps) {
1455     ierr = TurnBackward(ts);CHKERRQ(ierr);
1456     tjsch->rctx->reverseonestep = PETSC_FALSE;
1457     PetscFunctionReturn(0);
1458   }
1459   tjsch->rctx->capo = stepnum;
1460   tjsch->rctx->oldcapo = tjsch->rctx->capo;
1461   shift = 0;
1462   whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where); /* whattodo=restore */
1463   ierr = printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);CHKERRQ(ierr);
1464   /* restore a checkpoint */
1465   restart = tjsch->rctx->capo;
1466   if (!tjsch->rctx->where) {
1467     ondisk = PETSC_TRUE;
1468     ierr = LoadSingle(tj,ts,stack,tjsch->rctx->check+1);CHKERRQ(ierr);
1469     ierr = TurnBackward(ts);CHKERRQ(ierr);
1470   } else {
1471     ondisk = PETSC_FALSE;
1472     ierr = StackTop(stack,&e);CHKERRQ(ierr);
1473     ierr = UpdateTS(ts,stack,e);CHKERRQ(ierr);
1474   }
1475   if (!stack->solution_only) { /* whattodo must be 5 or 8 */
1476     /* ask Revolve what to do next */
1477     tjsch->rctx->oldcapo = tjsch->rctx->capo;
1478     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*/
1479     ierr = printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);CHKERRQ(ierr);
1480     if (whattodo == 3 || whattodo == 4) tjsch->rctx->reverseonestep = PETSC_TRUE;
1481     if (whattodo == 1) tjsch->rctx->stepsleft = tjsch->rctx->capo-tjsch->rctx->oldcapo;
1482     if (tj->monitor) {
1483       ierr = PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1484       ierr = PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",tjsch->rctx->oldcapo,tjsch->rctx->oldcapo+1);CHKERRQ(ierr);
1485       ierr = PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);CHKERRQ(ierr);
1486     }
1487     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
1488     restart++; /* skip one step */
1489   }
1490   if (stack->solution_only || (!stack->solution_only && restart < stepnum)) {
1491     tjsch->recompute = PETSC_TRUE;
1492     ierr = TurnForward(ts);CHKERRQ(ierr);
1493     ierr = ReCompute(ts,tjsch,restart,stepnum);CHKERRQ(ierr);
1494   }
1495   if (!ondisk && ( (stack->solution_only && e->stepnum+1 == stepnum) || (!stack->solution_only && e->stepnum == stepnum) )) {
1496     ierr = StackPop(stack,&e);CHKERRQ(ierr);
1497     ierr = ElementDestroy(stack,e);CHKERRQ(ierr);
1498   }
1499   tjsch->rctx->reverseonestep = PETSC_FALSE;
1500   PetscFunctionReturn(0);
1501 }
1502 #endif
1503 
1504 static PetscErrorCode TSTrajectorySet_Memory(TSTrajectory tj,TS ts,PetscInt stepnum,PetscReal time,Vec X)
1505 {
1506   TJScheduler *tjsch = (TJScheduler*)tj->data;
1507   PetscErrorCode ierr;
1508 
1509   PetscFunctionBegin;
1510   if (!tjsch->recompute) { /* use global stepnum in the forward sweep */
1511     ierr = TSGetStepNumber(ts,&stepnum);CHKERRQ(ierr);
1512   }
1513   /* for consistency */
1514   if (!tjsch->recompute && stepnum == 0) ts->ptime_prev = ts->ptime-ts->time_step;
1515   switch (tjsch->stype) {
1516     case NONE:
1517       ierr = SetTrajN(ts,tjsch,stepnum,time,X);CHKERRQ(ierr);
1518       break;
1519     case TWO_LEVEL_NOREVOLVE:
1520       ierr = SetTrajTLNR(tj,ts,tjsch,stepnum,time,X);CHKERRQ(ierr);
1521       break;
1522 #if defined(PETSC_HAVE_REVOLVE)
1523     case TWO_LEVEL_REVOLVE:
1524       ierr = SetTrajTLR(tj,ts,tjsch,stepnum,time,X);CHKERRQ(ierr);
1525       break;
1526     case TWO_LEVEL_TWO_REVOLVE:
1527       ierr = SetTrajTLTR(tj,ts,tjsch,stepnum,time,X);CHKERRQ(ierr);
1528       break;
1529     case REVOLVE_OFFLINE:
1530       ierr = SetTrajROF(tj,ts,tjsch,stepnum,time,X);CHKERRQ(ierr);
1531       break;
1532     case REVOLVE_ONLINE:
1533       ierr = SetTrajRON(tj,ts,tjsch,stepnum,time,X);CHKERRQ(ierr);
1534       break;
1535     case REVOLVE_MULTISTAGE:
1536       ierr = SetTrajRMS(tj,ts,tjsch,stepnum,time,X);CHKERRQ(ierr);
1537       break;
1538 #endif
1539     default:
1540       break;
1541   }
1542   PetscFunctionReturn(0);
1543 }
1544 
1545 static PetscErrorCode TSTrajectoryGet_Memory(TSTrajectory tj,TS ts,PetscInt stepnum,PetscReal *t)
1546 {
1547   TJScheduler *tjsch = (TJScheduler*)tj->data;
1548   PetscErrorCode ierr;
1549 
1550   PetscFunctionBegin;
1551   if (stepnum == 0) PetscFunctionReturn(0);
1552   switch (tjsch->stype) {
1553     case NONE:
1554       ierr = GetTrajN(ts,tjsch,stepnum);CHKERRQ(ierr);
1555       break;
1556     case TWO_LEVEL_NOREVOLVE:
1557       ierr = GetTrajTLNR(tj,ts,tjsch,stepnum);CHKERRQ(ierr);
1558       break;
1559 #if defined(PETSC_HAVE_REVOLVE)
1560     case TWO_LEVEL_REVOLVE:
1561       ierr = GetTrajTLR(tj,ts,tjsch,stepnum);CHKERRQ(ierr);
1562       break;
1563     case TWO_LEVEL_TWO_REVOLVE:
1564       ierr = GetTrajTLTR(tj,ts,tjsch,stepnum);CHKERRQ(ierr);
1565       break;
1566     case REVOLVE_OFFLINE:
1567       ierr = GetTrajROF(tj,ts,tjsch,stepnum);CHKERRQ(ierr);
1568       break;
1569     case REVOLVE_ONLINE:
1570       ierr = GetTrajRON(tj,ts,tjsch,stepnum);CHKERRQ(ierr);
1571       break;
1572     case REVOLVE_MULTISTAGE:
1573       ierr = GetTrajRMS(tj,ts,tjsch,stepnum);CHKERRQ(ierr);
1574       break;
1575 #endif
1576     default:
1577       break;
1578   }
1579   PetscFunctionReturn(0);
1580 }
1581 
1582 PETSC_UNUSED static PetscErrorCode TSTrajectorySetStride_Memory(TSTrajectory tj,PetscInt stride)
1583 {
1584   TJScheduler *tjsch = (TJScheduler*)tj->data;
1585 
1586   PetscFunctionBegin;
1587   tjsch->stride = stride;
1588   PetscFunctionReturn(0);
1589 }
1590 
1591 PETSC_UNUSED static PetscErrorCode TSTrajectorySetMaxCpsRAM_Memory(TSTrajectory tj,PetscInt max_cps_ram)
1592 {
1593   TJScheduler *tjsch = (TJScheduler*)tj->data;
1594 
1595   PetscFunctionBegin;
1596   tjsch->max_cps_ram = max_cps_ram;
1597   PetscFunctionReturn(0);
1598 }
1599 
1600 PETSC_UNUSED static PetscErrorCode TSTrajectorySetMaxCpsDisk_Memory(TSTrajectory tj,PetscInt max_cps_disk)
1601 {
1602   TJScheduler *tjsch = (TJScheduler*)tj->data;
1603 
1604   PetscFunctionBegin;
1605   tjsch->max_cps_disk = max_cps_disk;
1606   PetscFunctionReturn(0);
1607 }
1608 
1609 #if defined(PETSC_HAVE_REVOLVE)
1610 PETSC_UNUSED static PetscErrorCode TSTrajectorySetRevolveOnline(TSTrajectory tj,PetscBool use_online)
1611 {
1612   TJScheduler *tjsch = (TJScheduler*)tj->data;
1613 
1614   PetscFunctionBegin;
1615   tjsch->use_online = use_online;
1616   PetscFunctionReturn(0);
1617 }
1618 #endif
1619 
1620 PETSC_UNUSED static PetscErrorCode TSTrajectorySetSaveStack(TSTrajectory tj,PetscBool save_stack)
1621 {
1622   TJScheduler *tjsch = (TJScheduler*)tj->data;
1623 
1624   PetscFunctionBegin;
1625   tjsch->save_stack = save_stack;
1626   PetscFunctionReturn(0);
1627 }
1628 
1629 PETSC_UNUSED static PetscErrorCode TSTrajectorySetSolutionOnly(TSTrajectory tj,PetscBool solution_only)
1630 {
1631   TJScheduler *tjsch = (TJScheduler*)tj->data;
1632   Stack       *stack = &tjsch->stack;
1633 
1634   PetscFunctionBegin;
1635   stack->solution_only = solution_only;
1636   PetscFunctionReturn(0);
1637 }
1638 
1639 PETSC_UNUSED static PetscErrorCode TSTrajectorySetUseDRAM(TSTrajectory tj,PetscBool use_dram)
1640 {
1641   TJScheduler *tjsch = (TJScheduler*)tj->data;
1642 
1643   PetscFunctionBegin;
1644   tjsch->stack.use_dram = use_dram;
1645   PetscFunctionReturn(0);
1646 }
1647 
1648 static PetscErrorCode TSTrajectorySetFromOptions_Memory(PetscOptionItems *PetscOptionsObject,TSTrajectory tj)
1649 {
1650   TJScheduler    *tjsch = (TJScheduler*)tj->data;
1651   PetscErrorCode ierr;
1652 
1653   PetscFunctionBegin;
1654   ierr = PetscOptionsHead(PetscOptionsObject,"Memory based TS trajectory options");CHKERRQ(ierr);
1655   {
1656     ierr = PetscOptionsInt("-ts_trajectory_max_cps_ram","Maximum number of checkpoints in RAM","TSTrajectorySetMaxCpsRAM_Memory",tjsch->max_cps_ram,&tjsch->max_cps_ram,NULL);CHKERRQ(ierr);
1657     ierr = PetscOptionsInt("-ts_trajectory_max_cps_disk","Maximum number of checkpoints on disk","TSTrajectorySetMaxCpsDisk_Memory",tjsch->max_cps_disk,&tjsch->max_cps_disk,NULL);CHKERRQ(ierr);
1658     ierr = PetscOptionsInt("-ts_trajectory_stride","Stride to save checkpoints to file","TSTrajectorySetStride_Memory",tjsch->stride,&tjsch->stride,NULL);CHKERRQ(ierr);
1659 #if defined(PETSC_HAVE_REVOLVE)
1660     ierr = PetscOptionsBool("-ts_trajectory_revolve_online","Trick TS trajectory into using online mode of revolve","TSTrajectorySetRevolveOnline",tjsch->use_online,&tjsch->use_online,NULL);CHKERRQ(ierr);
1661 #endif
1662     ierr = PetscOptionsBool("-ts_trajectory_save_stack","Save all stack to disk","TSTrajectorySetSaveStack",tjsch->save_stack,&tjsch->save_stack,NULL);CHKERRQ(ierr);
1663     ierr = PetscOptionsBool("-ts_trajectory_solution_only","Checkpoint solution only","TSTrajectorySetSolutionOnly",tjsch->stack.solution_only,&tjsch->stack.solution_only,NULL);CHKERRQ(ierr);
1664     ierr = PetscOptionsBool("-ts_trajectory_use_dram","Use DRAM for checkpointing","TSTrajectorySetUseDRAM",tjsch->stack.use_dram,&tjsch->stack.use_dram,NULL);CHKERRQ(ierr);
1665   }
1666   ierr = PetscOptionsTail();CHKERRQ(ierr);
1667   PetscFunctionReturn(0);
1668 }
1669 
1670 static PetscErrorCode TSTrajectorySetUp_Memory(TSTrajectory tj,TS ts)
1671 {
1672   TJScheduler    *tjsch = (TJScheduler*)tj->data;
1673   Stack          *stack = &tjsch->stack;
1674 #if defined(PETSC_HAVE_REVOLVE)
1675   RevolveCTX     *rctx,*rctx2;
1676   DiskStack      *diskstack = &tjsch->diskstack;
1677   PetscInt       diskblocks;
1678 #endif
1679   PetscInt       numY;
1680   PetscBool      flg;
1681   PetscErrorCode ierr;
1682 
1683   PetscFunctionBegin;
1684   PetscStrcmp(((PetscObject)ts->adapt)->type_name,TSADAPTNONE,&flg);
1685   if (flg) tjsch->total_steps = PetscMin(ts->max_steps,(PetscInt)(PetscCeilReal((ts->max_time-ts->ptime)/ts->time_step))); /* fixed time step */
1686   if (tjsch->max_cps_ram > 0) stack->stacksize = tjsch->max_cps_ram;
1687 
1688   if (tjsch->stride > 1) { /* two level mode */
1689     if (tjsch->save_stack && tjsch->max_cps_disk > 1 && tjsch->max_cps_disk <= tjsch->max_cps_ram) SETERRQ(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.");
1690     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 */
1691     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 */
1692     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 */
1693   } else { /* single level mode */
1694     if (flg) { /* fixed time step */
1695       if (tjsch->max_cps_ram >= tjsch->total_steps-1 || tjsch->max_cps_ram < 1) tjsch->stype = NONE; /* checkpoint all */
1696       else tjsch->stype = (tjsch->max_cps_disk>1) ? REVOLVE_MULTISTAGE : REVOLVE_OFFLINE;
1697     } else tjsch->stype = NONE; /* checkpoint all for adaptive time step */
1698 #if defined(PETSC_HAVE_REVOLVE)
1699     if (tjsch->use_online) tjsch->stype = REVOLVE_ONLINE; /* trick into online (for testing purpose only) */
1700 #endif
1701   }
1702 
1703   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
1704 #ifndef PETSC_HAVE_REVOLVE
1705     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.");
1706 #else
1707     switch (tjsch->stype) {
1708       case TWO_LEVEL_REVOLVE:
1709         revolve_create_offline(tjsch->stride,tjsch->max_cps_ram);
1710         break;
1711       case TWO_LEVEL_TWO_REVOLVE:
1712         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. */
1713         diskstack->stacksize = diskblocks;
1714         revolve_create_offline(tjsch->stride,tjsch->max_cps_ram);
1715         revolve2_create_offline((tjsch->total_steps+tjsch->stride-1)/tjsch->stride,diskblocks);
1716         ierr = PetscCalloc1(1,&rctx2);CHKERRQ(ierr);
1717         rctx2->snaps_in       = diskblocks;
1718         rctx2->reverseonestep = PETSC_FALSE;
1719         rctx2->check          = 0;
1720         rctx2->oldcapo        = 0;
1721         rctx2->capo           = 0;
1722         rctx2->info           = 2;
1723         rctx2->fine           = (tjsch->total_steps+tjsch->stride-1)/tjsch->stride;
1724         tjsch->rctx2          = rctx2;
1725         diskstack->top        = -1;
1726         ierr = PetscMalloc1(diskstack->stacksize*sizeof(PetscInt),&diskstack->container);CHKERRQ(ierr);
1727         break;
1728       case REVOLVE_OFFLINE:
1729         revolve_create_offline(tjsch->total_steps,tjsch->max_cps_ram);
1730         break;
1731       case REVOLVE_ONLINE:
1732         stack->stacksize = tjsch->max_cps_ram;
1733         revolve_create_online(tjsch->max_cps_ram);
1734         break;
1735       case REVOLVE_MULTISTAGE:
1736         revolve_create_multistage(tjsch->total_steps,tjsch->max_cps_ram+tjsch->max_cps_disk,tjsch->max_cps_ram);
1737         break;
1738       default:
1739         break;
1740     }
1741     ierr = PetscCalloc1(1,&rctx);CHKERRQ(ierr);
1742     rctx->snaps_in       = tjsch->max_cps_ram; /* for theta methods snaps_in=2*max_cps_ram */
1743     rctx->reverseonestep = PETSC_FALSE;
1744     rctx->check          = 0;
1745     rctx->oldcapo        = 0;
1746     rctx->capo           = 0;
1747     rctx->info           = 2;
1748     rctx->fine           = (tjsch->stride > 1) ? tjsch->stride : tjsch->total_steps;
1749     tjsch->rctx          = rctx;
1750     if (tjsch->stype == REVOLVE_ONLINE) rctx->fine = -1;
1751 #endif
1752   } else {
1753     if (tjsch->stype == TWO_LEVEL_NOREVOLVE) stack->stacksize = tjsch->stride-1; /* need tjsch->stride-1 at most */
1754     if (tjsch->stype == NONE) {
1755       if (flg) stack->stacksize = stack->solution_only ? tjsch->total_steps : tjsch->total_steps-1; /* fix time step */
1756       else { /* adaptive time step */
1757         /* if max_cps_ram is not specified, use maximal allowed number of steps for stack size */
1758         if(tjsch->max_cps_ram == -1) stack->stacksize = ts->max_steps < PETSC_MAX_INT ? ts->max_steps : 10000;
1759         tjsch->total_steps = stack->solution_only ? stack->stacksize : stack->stacksize+1; /* will be updated as time integration advances */
1760       }
1761     }
1762   }
1763 
1764   tjsch->recompute = PETSC_FALSE;
1765   ierr = TSGetStages(ts,&numY,PETSC_IGNORE);CHKERRQ(ierr);
1766   ierr = StackCreate(stack,stack->stacksize,numY);CHKERRQ(ierr);
1767   PetscFunctionReturn(0);
1768 }
1769 
1770 static PetscErrorCode TSTrajectoryDestroy_Memory(TSTrajectory tj)
1771 {
1772   TJScheduler    *tjsch = (TJScheduler*)tj->data;
1773   PetscErrorCode ierr;
1774 
1775   PetscFunctionBegin;
1776   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
1777 #if defined(PETSC_HAVE_REVOLVE)
1778     revolve_reset();
1779     if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) {
1780       revolve2_reset();
1781       ierr = PetscFree(tjsch->diskstack.container);CHKERRQ(ierr);
1782     }
1783 #endif
1784   }
1785   ierr = StackDestroy(&tjsch->stack);CHKERRQ(ierr);
1786 #if defined(PETSC_HAVE_REVOLVE)
1787   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
1788     ierr = PetscFree(tjsch->rctx);CHKERRQ(ierr);
1789     ierr = PetscFree(tjsch->rctx2);CHKERRQ(ierr);
1790   }
1791 #endif
1792   ierr = PetscFree(tjsch);CHKERRQ(ierr);
1793   PetscFunctionReturn(0);
1794 }
1795 
1796 /*MC
1797       TSTRAJECTORYMEMORY - Stores each solution of the ODE/ADE in memory
1798 
1799   Level: intermediate
1800 
1801 .seealso:  TSTrajectoryCreate(), TS, TSTrajectorySetType()
1802 
1803 M*/
1804 PETSC_EXTERN PetscErrorCode TSTrajectoryCreate_Memory(TSTrajectory tj,TS ts)
1805 {
1806   TJScheduler    *tjsch;
1807   PetscErrorCode ierr;
1808 
1809   PetscFunctionBegin;
1810   tj->ops->set            = TSTrajectorySet_Memory;
1811   tj->ops->get            = TSTrajectoryGet_Memory;
1812   tj->ops->setup          = TSTrajectorySetUp_Memory;
1813   tj->ops->destroy        = TSTrajectoryDestroy_Memory;
1814   tj->ops->setfromoptions = TSTrajectorySetFromOptions_Memory;
1815 
1816   ierr = PetscCalloc1(1,&tjsch);CHKERRQ(ierr);
1817   tjsch->stype        = NONE;
1818   tjsch->max_cps_ram  = -1; /* -1 indicates that it is not set */
1819   tjsch->max_cps_disk = -1; /* -1 indicates that it is not set */
1820   tjsch->stride       = 0; /* if not zero, two-level checkpointing will be used */
1821 #if defined(PETSC_HAVE_REVOLVE)
1822   tjsch->use_online   = PETSC_FALSE;
1823 #endif
1824   tjsch->save_stack   = PETSC_TRUE;
1825 
1826   tjsch->stack.solution_only = PETSC_TRUE;
1827 
1828   tj->data = tjsch;
1829   PetscFunctionReturn(0);
1830 }
1831