xref: /petsc/src/ts/trajectory/impls/memory/trajmemory.c (revision 0cae4918803fd82f5a591f5abedafe7d4432033f)
1 #include <petsc/private/tsimpl.h>        /*I "petscts.h"  I*/
2 #include <petscsys.h>
3 
4 #ifdef PETSC_HAVE_REVOLVE
5 #include <revolve_c.h>
6 #endif
7 
8 typedef enum {NONE,TWO_LEVEL_NOREVOLVE,TWO_LEVEL_REVOLVE,REVOLVE_OFFLINE,REVOLVE_ONLINE,REVOLVE_MULTISTAGE} SchedulerType;
9 
10 typedef struct _StackElement {
11   PetscInt  stepnum;
12   Vec       X;
13   Vec       *Y;
14   PetscReal time;
15   PetscReal timeprev;
16 } *StackElement;
17 
18 typedef struct _RevolveCTX {
19   PetscBool reverseonestep;
20   PetscInt  where;
21   PetscInt  snaps_in;
22   PetscInt  stepsleft;
23   PetscInt  check;
24   PetscInt  oldcapo;
25   PetscInt  capo;
26   PetscInt  fine;
27   PetscInt  info;
28 } RevolveCTX;
29 
30 typedef struct _Stack {
31   SchedulerType stype;
32   PetscBool     recompute;
33   MPI_Comm      comm;
34   RevolveCTX    *rctx;
35   PetscInt      max_cps_ram;  /* maximum checkpoints in RAM */
36   PetscInt      max_cps_disk; /* maximum checkpoints on disk */
37   PetscInt      stride;
38   PetscInt      total_steps; /* total number of steps */
39   PetscInt      numY;
40   PetscInt      stacksize;
41   PetscInt      top;         /* top of the stack */
42   StackElement  *stack;      /* container */
43 } Stack;
44 
45 static PetscErrorCode StackCreate(MPI_Comm,Stack *,PetscInt,PetscInt);
46 static PetscErrorCode StackDestroy(Stack*);
47 static PetscErrorCode StackPush(Stack*,StackElement);
48 static PetscErrorCode StackPop(Stack*,StackElement*);
49 static PetscErrorCode StackTop(Stack*,StackElement*);
50 static PetscErrorCode StackDumpAll(TS,Stack*,PetscInt);
51 static PetscErrorCode StackLoadAll(TS,Stack*,PetscInt);
52 
53 #ifdef PETSC_HAVE_REVOLVE
54 static void printwhattodo(PetscInt whattodo,RevolveCTX *rctx,PetscInt shift)
55 {
56   switch(whattodo) {
57     case 1:
58       PetscPrintf(PETSC_COMM_WORLD,"\x1B[35mAdvance from %D to %D\033[0m\n",rctx->oldcapo+shift,rctx->capo+shift);
59       break;
60     case 2:
61       PetscPrintf(PETSC_COMM_WORLD,"\x1B[35mStore in checkpoint number %D\n\033[0m",rctx->check);
62       break;
63     case 3:
64       PetscPrintf(PETSC_COMM_WORLD,"\x1B[35mFirst turn: Initialize adjoints and reverse first step\033[0m\n");
65       break;
66     case 4:
67       PetscPrintf(PETSC_COMM_WORLD,"\x1B[35mForward and reverse one step\033[0m\n");
68       break;
69     case 5:
70       PetscPrintf(PETSC_COMM_WORLD,"\x1B[35mRestore in checkpoint number %D\033[0m\n",rctx->check);
71       break;
72     case -1:
73       PetscPrintf(PETSC_COMM_WORLD,"\x1B[35mError!");
74       break;
75   }
76 }
77 #endif
78 
79 #undef __FUNCT__
80 #define __FUNCT__ "StackCreate"
81 static PetscErrorCode StackCreate(MPI_Comm comm,Stack *s,PetscInt size,PetscInt ny)
82 {
83   PetscErrorCode ierr;
84 
85   PetscFunctionBegin;
86   s->top  = -1;
87   s->comm = comm;
88   s->numY = ny;
89 
90   ierr = PetscMalloc1(size*sizeof(StackElement),&s->stack);CHKERRQ(ierr);
91   PetscFunctionReturn(0);
92 }
93 
94 #undef __FUNCT__
95 #define __FUNCT__ "StackDestroy"
96 static PetscErrorCode StackDestroy(Stack *s)
97 {
98   PetscInt       i;
99   PetscErrorCode ierr;
100 
101   PetscFunctionBegin;
102   if (s->top>-1) {
103     for (i=0;i<=s->top;i++) {
104       ierr = VecDestroy(&s->stack[i]->X);CHKERRQ(ierr);
105       ierr = VecDestroyVecs(s->numY,&s->stack[i]->Y);CHKERRQ(ierr);
106       ierr = PetscFree(s->stack[i]);CHKERRQ(ierr);
107     }
108   }
109   ierr = PetscFree(s->stack);CHKERRQ(ierr);
110   if (s->stype) {
111     ierr = PetscFree(s->rctx);CHKERRQ(ierr);
112   }
113   ierr = PetscFree(s);CHKERRQ(ierr);
114   PetscFunctionReturn(0);
115 }
116 
117 #undef __FUNCT__
118 #define __FUNCT__ "StackPush"
119 static PetscErrorCode StackPush(Stack *s,StackElement e)
120 {
121   PetscFunctionBegin;
122   if (s->top+1 >= s->stacksize) SETERRQ1(s->comm,PETSC_ERR_MEMC,"Maximum stack size (%D) exceeded",s->stacksize);
123   s->stack[++s->top] = e;
124   PetscFunctionReturn(0);
125 }
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "StackPop"
129 static PetscErrorCode StackPop(Stack *s,StackElement *e)
130 {
131   PetscFunctionBegin;
132   if (s->top == -1) SETERRQ(s->comm,PETSC_ERR_MEMC,"Emptry stack");
133   *e = s->stack[s->top--];
134   PetscFunctionReturn(0);
135 }
136 
137 #undef __FUNCT__
138 #define __FUNCT__ "StackTop"
139 static PetscErrorCode StackTop(Stack *s,StackElement *e)
140 {
141   PetscFunctionBegin;
142   *e = s->stack[s->top];
143   PetscFunctionReturn(0);
144 }
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "OutputBIN"
148 static PetscErrorCode OutputBIN(const char *filename,PetscViewer *viewer)
149 {
150   PetscErrorCode ierr;
151 
152   PetscFunctionBegin;
153   ierr = PetscViewerCreate(PETSC_COMM_WORLD,viewer);CHKERRQ(ierr);
154   ierr = PetscViewerSetType(*viewer,PETSCVIEWERBINARY);CHKERRQ(ierr);
155   ierr = PetscViewerFileSetMode(*viewer,FILE_MODE_WRITE);CHKERRQ(ierr);
156   ierr = PetscViewerFileSetName(*viewer,filename);CHKERRQ(ierr);
157   PetscFunctionReturn(0);
158 }
159 
160 #undef __FUNCT__
161 #define __FUNCT__ "StackDumpAll"
162 static PetscErrorCode StackDumpAll(TS ts,Stack *s,PetscInt id)
163 {
164   PetscInt       i,j;
165   StackElement   e;
166   PetscViewer    viewer;
167   char           filename[PETSC_MAX_PATH_LEN];
168   Vec            *Y;
169   PetscErrorCode ierr;
170 
171   PetscFunctionBegin;
172   if (id == 1) {
173 #if defined(PETSC_HAVE_POPEN)
174     PetscMPIInt rank;
175     ierr = MPI_Comm_rank(s->comm,&rank);CHKERRQ(ierr);
176     if (!rank) {
177       char command[PETSC_MAX_PATH_LEN];
178       FILE *fd;
179       int  err;
180 
181       ierr = PetscMemzero(command,sizeof(command));CHKERRQ(ierr);
182       ierr = PetscSNPrintf(command,PETSC_MAX_PATH_LEN,"rm -fr %s","SA-data");CHKERRQ(ierr);
183       ierr = PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);CHKERRQ(ierr);
184       ierr = PetscPClose(PETSC_COMM_SELF,fd,&err);CHKERRQ(ierr);
185       ierr = PetscSNPrintf(command,PETSC_MAX_PATH_LEN,"mkdir %s","SA-data");CHKERRQ(ierr);
186       ierr = PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fd);CHKERRQ(ierr);
187       ierr = PetscPClose(PETSC_COMM_SELF,fd,&err);CHKERRQ(ierr);
188     }
189 #endif
190   }
191   ierr = PetscSNPrintf(filename,sizeof(filename),"SA-data/SA-STACK%06d.bin",id);CHKERRQ(ierr);
192   ierr = OutputBIN(filename,&viewer);CHKERRQ(ierr);
193   for (i=0;i<s->stacksize;i++) {
194     e = s->stack[i];
195     ierr = PetscViewerBinaryWrite(viewer,&e->stepnum,1,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr);
196     ierr = VecView(e->X,viewer);CHKERRQ(ierr);
197     for (j=0;j<s->numY;j++) {
198       ierr = VecView(e->Y[j],viewer);CHKERRQ(ierr);
199     }
200     ierr = PetscViewerBinaryWrite(viewer,&e->time,1,PETSC_REAL,PETSC_FALSE);CHKERRQ(ierr);
201     ierr = PetscViewerBinaryWrite(viewer,&e->timeprev,1,PETSC_REAL,PETSC_FALSE);CHKERRQ(ierr);
202   }
203   /* dump the state inside TS from the current step */
204   ierr = PetscViewerBinaryWrite(viewer,&ts->total_steps,1,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr);
205   ierr = VecView(ts->vec_sol,viewer);CHKERRQ(ierr);
206   ierr = TSGetStages(ts,&s->numY,&Y);CHKERRQ(ierr);
207   for (j=0;j<s->numY;j++) {
208     ierr = VecView(Y[j],viewer);CHKERRQ(ierr);
209   }
210   ierr = PetscViewerBinaryWrite(viewer,&ts->ptime,1,PETSC_REAL,PETSC_FALSE);CHKERRQ(ierr);
211   ierr = PetscViewerBinaryWrite(viewer,&ts->ptime_prev,1,PETSC_REAL,PETSC_FALSE);CHKERRQ(ierr);
212   for (i=0;i<s->stacksize;i++) {
213     ierr = StackPop(s,&e);CHKERRQ(ierr);
214     ierr = VecDestroy(&e->X);CHKERRQ(ierr);
215     ierr = VecDestroyVecs(s->numY,&e->Y);CHKERRQ(ierr);
216     ierr = PetscFree(e);CHKERRQ(ierr);
217   }
218   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
219   PetscFunctionReturn(0);
220 }
221 
222 #undef __FUNCT__
223 #define __FUNCT__ "StackLoadAll"
224 static PetscErrorCode StackLoadAll(TS ts,Stack *s,PetscInt id)
225 {
226   Vec            *Y;
227   PetscInt       i,j;
228   StackElement   e;
229   PetscViewer    viewer;
230   char           filename[PETSC_MAX_PATH_LEN];
231   PetscErrorCode ierr;
232 
233   PetscFunctionBegin;
234   ierr = PetscSNPrintf(filename,sizeof filename,"SA-data/SA-STACK%06d.bin",id);CHKERRQ(ierr);
235   ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr);
236   for (i=0;i<s->stacksize;i++) {
237     ierr = PetscCalloc1(1,&e);
238     ierr = TSGetStages(ts,&s->numY,&Y);CHKERRQ(ierr);
239     ierr = VecDuplicate(Y[0],&e->X);CHKERRQ(ierr);
240     if (s->numY > 0) {
241       ierr = VecDuplicateVecs(Y[0],s->numY,&e->Y);CHKERRQ(ierr);
242     }
243     ierr = StackPush(s,e);CHKERRQ(ierr);
244   }
245   for (i=0;i<s->stacksize;i++) {
246     e = s->stack[i];
247     ierr = PetscViewerBinaryRead(viewer,&e->stepnum,1,NULL,PETSC_INT);CHKERRQ(ierr);
248     ierr = VecLoad(e->X,viewer);CHKERRQ(ierr);
249     for (j=0;j<s->numY;j++) {
250       ierr = VecLoad(e->Y[j],viewer);CHKERRQ(ierr);
251     }
252     ierr = PetscViewerBinaryRead(viewer,&e->time,1,NULL,PETSC_REAL);CHKERRQ(ierr);
253     ierr = PetscViewerBinaryRead(viewer,&e->timeprev,1,NULL,PETSC_REAL);CHKERRQ(ierr);
254   }
255   /* load the additioinal state into TS */
256   ierr = PetscViewerBinaryRead(viewer,&ts->total_steps,1,NULL,PETSC_INT);CHKERRQ(ierr);
257   ierr = VecLoad(ts->vec_sol,viewer);CHKERRQ(ierr);
258   ierr = TSGetStages(ts,&s->numY,&Y);CHKERRQ(ierr);
259   for (j=0;j<s->numY;j++) {
260     ierr = VecLoad(Y[j],viewer);CHKERRQ(ierr);
261   }
262   ierr = PetscViewerBinaryRead(viewer,&ts->ptime,1,NULL,PETSC_REAL);CHKERRQ(ierr);
263   ierr = PetscViewerBinaryRead(viewer,&ts->ptime_prev,1,NULL,PETSC_REAL);CHKERRQ(ierr);
264   ierr = TSSetTimeStep(ts,ts->ptime-ts->ptime_prev);CHKERRQ(ierr);
265   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
266   PetscFunctionReturn(0);
267 }
268 
269 #undef __FUNCT__
270 #define __FUNCT__ "TSTrajectorySetStride_Memory"
271 PetscErrorCode TSTrajectorySetStride_Memory(TSTrajectory tj,TS ts,PetscInt stride)
272 {
273   Stack *s = (Stack*)tj->data;
274 
275   PetscFunctionBegin;
276   s->stride = stride;
277   PetscFunctionReturn(0);
278 }
279 
280 #undef __FUNCT__
281 #define __FUNCT__ "TSTrajectorySetMaxCheckpoints_Memory"
282 PetscErrorCode TSTrajectorySetMaxCheckpoints_Memory(TSTrajectory tj,TS ts,PetscInt max_cps_ram)
283 {
284   Stack *s = (Stack*)tj->data;
285 
286   PetscFunctionBegin;
287   s->max_cps_ram = max_cps_ram;
288   PetscFunctionReturn(0);
289 }
290 
291 #undef __FUNCT__
292 #define __FUNCT__ "TSTrajectorySetFromOptions_Memory"
293 PetscErrorCode TSTrajectorySetFromOptions_Memory(PetscOptions *PetscOptionsObject,TSTrajectory tj)
294 {
295   Stack          *s = (Stack*)tj->data;
296   PetscErrorCode ierr;
297 
298   PetscFunctionBegin;
299   ierr = PetscOptionsHead(PetscOptionsObject,"Memory based TS trajectory options");CHKERRQ(ierr);
300   {
301     ierr = PetscOptionsInt("-tstrajectory_max_cps_ram","Maximum number of checkpoints","TSTrajectorySetMaxCheckpoints_Memory",s->max_cps_ram,&s->max_cps_ram,NULL);CHKERRQ(ierr);
302     ierr = PetscOptionsInt("-tstrajectory_stride","Stride to save checkpoints to file","TSTrajectorySetStride_Memory",s->stride,&s->stride,NULL);CHKERRQ(ierr);
303   }
304   ierr = PetscOptionsTail();CHKERRQ(ierr);
305   PetscFunctionReturn(0);
306 }
307 
308 #undef __FUNCT__
309 #define __FUNCT__ "TSTrajectorySetUp_Memory"
310 PetscErrorCode TSTrajectorySetUp_Memory(TSTrajectory tj,TS ts)
311 {
312   Stack          *s = (Stack*)tj->data;
313   RevolveCTX     *rctx;
314   PetscInt       numY;
315   PetscBool      flg;
316   PetscErrorCode ierr;
317 
318   PetscFunctionBegin;
319   PetscStrcmp(((PetscObject)ts->adapt)->type_name,TSADAPTNONE,&flg);
320   if (flg) { /* fixed time step */
321     s->total_steps = PetscMin(ts->max_steps,(PetscInt)(ceil(ts->max_time/ts->time_step)));
322   }
323   if (s->max_cps_ram > 1) s->stacksize = s->max_cps_ram;
324   if (s->stride > 1) { /* two level mode works for both fixed time step and adaptive time step */
325     if (s->max_cps_ram > 1 && s->max_cps_ram < s->stride-1) { /* use revolve_offline for each stride */
326       s->stype = TWO_LEVEL_REVOLVE;
327     }else { /* checkpoint all for each stride */
328       s->stype     = TWO_LEVEL_NOREVOLVE;
329       s->stacksize = s->stride-1;
330     }
331   } else {
332     if (flg) { /* fixed time step */
333       if (s->max_cps_ram >= s->total_steps-1 || s->max_cps_ram < 1) { /* checkpoint all */
334         s->stype     = NONE;
335         s->stacksize = s->total_steps-1;
336       } else {
337         if (s->max_cps_disk > 1) { /* disk can be used */
338           s->stype = REVOLVE_MULTISTAGE;
339         } else { /* memory only */
340           s->stype = REVOLVE_OFFLINE;
341         }
342       }
343     } else { /* adaptive time step */
344       s->stype = REVOLVE_ONLINE;
345     }
346   }
347 
348   if (s->stype > TWO_LEVEL_NOREVOLVE) {
349 #ifndef PETSC_HAVE_REVOLVE
350     SETERRQ(s->comm,PETSC_ERR_SUP,"revolve is needed when there is not enought memory to checkpoint all time steps according to the user's settings, please reconfigure with the additional option --download-revolve.");
351 #else
352     if (s->stype == TWO_LEVEL_REVOLVE) revolve_create_offline(s->stride,s->max_cps_ram);
353     else if (s->stype == REVOLVE_OFFLINE) revolve_create_offline(s->total_steps,s->max_cps_ram);
354     else if (s->stype == REVOLVE_ONLINE) revolve_create_online(s->max_cps_ram);
355     else if (s->stype ==REVOLVE_MULTISTAGE) revolve_create_multistage(s->total_steps,s->max_cps_ram+s->max_cps_disk,s->max_cps_ram);
356 
357     ierr = PetscCalloc1(1,&rctx);CHKERRQ(ierr);
358     rctx->snaps_in       = s->max_cps_ram; /* for theta methods snaps_in=2*max_cps_ram */
359     rctx->reverseonestep = PETSC_FALSE;
360     rctx->check          = -1;
361     rctx->oldcapo        = 0;
362     rctx->capo           = 0;
363     rctx->info           = 2;
364     rctx->fine           = (s->stride > 1) ? s->stride : s->total_steps;
365 
366     s->rctx      = rctx;
367 #endif
368   }
369 
370   s->recompute = PETSC_FALSE;
371 
372   ierr = TSGetStages(ts,&numY,PETSC_IGNORE);CHKERRQ(ierr);
373   ierr = StackCreate(PetscObjectComm((PetscObject)ts),s,s->stacksize,numY);CHKERRQ(ierr);
374   PetscFunctionReturn(0);
375 }
376 
377 #undef __FUNCT__
378 #define __FUNCT__ "TSTrajectorySet_Memory"
379 PetscErrorCode TSTrajectorySet_Memory(TSTrajectory tj,TS ts,PetscInt stepnum,PetscReal time,Vec X)
380 {
381   PetscInt       i;
382   Vec            *Y;
383   PetscReal      timeprev;
384   StackElement   e;
385   Stack          *s = (Stack*)tj->data;
386   PetscInt       localstepnum,id;
387   RevolveCTX     *rctx;
388 #ifdef PETSC_HAVE_REVOLVE
389   PetscInt       whattodo,shift;
390 #endif
391   PetscErrorCode ierr;
392 
393   PetscFunctionBegin;
394   if (!s->recompute) { /* use global stepnum in the forward sweep */
395     ierr = TSGetTotalSteps(ts,&stepnum);CHKERRQ(ierr);
396   }
397   if (s->stype == TWO_LEVEL_REVOLVE || s->stype == TWO_LEVEL_NOREVOLVE) { /* two-level mode */
398     localstepnum = stepnum%s->stride;
399     if (stepnum!=0 && stepnum!=s->total_steps && localstepnum==0 && !s->recompute) { /* never need to recompute localstepnum=0 */
400 #ifdef PETSC_HAVE_REVOLVE
401       PetscPrintf(PETSC_COMM_WORLD,"\x1B[33mDump stack to file\033[0m\n");
402 #endif
403       id = stepnum/s->stride;
404       ierr = StackDumpAll(ts,s,id);CHKERRQ(ierr);
405       s->top = -1; /* reset top */
406 #ifdef PETSC_HAVE_REVOLVE
407       if (s->stype == TWO_LEVEL_REVOLVE) {
408         revolve_reset();
409         revolve_create_offline(s->stride,s->max_cps_ram);
410         rctx = s->rctx;
411         rctx->check = 0;
412         rctx->capo  = 0;
413         rctx->fine  = s->stride;
414       }
415 #endif
416     }
417   } else {
418     localstepnum = stepnum;
419   }
420 
421   if (s->stype > TWO_LEVEL_NOREVOLVE) {
422 #ifdef PETSC_HAVE_REVOLVE
423     rctx = s->rctx;
424     if (rctx->reverseonestep && stepnum==s->total_steps) { /* intermediate information is ready inside TS, this happens at last time step */
425       rctx->reverseonestep = PETSC_FALSE;
426       PetscFunctionReturn(0);
427     }
428     if (rctx->stepsleft != 0) { /* advance the solution without checkpointing anything as Revolve requires */
429       rctx->stepsleft--;
430       PetscFunctionReturn(0);
431     }
432 
433     /* let Revolve determine what to do next */
434     shift         = stepnum-localstepnum;
435     rctx->capo    = localstepnum;
436     rctx->oldcapo = rctx->capo;
437     whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
438     printwhattodo(whattodo,rctx,shift);
439     if (whattodo == -1) SETERRQ(s->comm,PETSC_ERR_LIB,"Error in the Revolve library");
440     if (whattodo == 1) { /* advance some time steps */
441       rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
442       PetscFunctionReturn(0);
443     }
444     if (whattodo == 3 || whattodo == 4) { /* ready for a reverse step */
445       rctx->reverseonestep = PETSC_TRUE;
446       PetscFunctionReturn(0);
447     }
448     if (whattodo == 5) { /* restore a checkpoint and ask Revolve what to do next */
449       rctx->oldcapo = rctx->capo;
450       whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where); /* must return 1*/
451       printwhattodo(whattodo,rctx,shift);
452       rctx->stepsleft = rctx->capo-rctx->oldcapo;
453       PetscFunctionReturn(0);
454     }
455     if (whattodo == 2) { /* store a checkpoint and ask Revolve how many time steps to advance next */
456       rctx->oldcapo = rctx->capo;
457       whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where); /* must return 1*/
458       printwhattodo(whattodo,rctx,shift);
459       rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
460     }
461 #endif
462   } else { /* Revolve is not used */
463     /* skip the first and the last steps of each stride or the whole interval */
464     if (localstepnum == 0 || stepnum == s->total_steps) PetscFunctionReturn(0);
465   }
466 
467   /* checkpoint to memory */
468   if (localstepnum == s->top) { /* overwrite the top checkpoint, this might happen when the time interval is split into several smaller ones, each corresponding to a call of TSSolve() */
469     ierr = StackTop(s,&e);CHKERRQ(ierr);
470     ierr = VecCopy(X,e->X);CHKERRQ(ierr);
471     ierr = TSGetStages(ts,&s->numY,&Y);CHKERRQ(ierr);
472     for (i=0;i<s->numY;i++) {
473       ierr = VecCopy(Y[i],e->Y[i]);CHKERRQ(ierr);
474     }
475     e->stepnum  = stepnum;
476     e->time     = time;
477     ierr        = TSGetPrevTime(ts,&timeprev);CHKERRQ(ierr);
478     e->timeprev = timeprev;
479   } else {
480     if (localstepnum < s->top) SETERRQ(s->comm,PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
481     ierr = PetscCalloc1(1,&e);CHKERRQ(ierr);
482     ierr = VecDuplicate(X,&e->X);CHKERRQ(ierr);
483     ierr = VecCopy(X,e->X);CHKERRQ(ierr);
484     ierr = TSGetStages(ts,&s->numY,&Y);CHKERRQ(ierr);
485     if (s->numY > 0) {
486       ierr = VecDuplicateVecs(Y[0],s->numY,&e->Y);CHKERRQ(ierr);
487     }
488     for (i=0;i<s->numY;i++) {
489       ierr = VecCopy(Y[i],e->Y[i]);CHKERRQ(ierr);
490     }
491     e->stepnum  = stepnum;
492     e->time     = time;
493     /* for consistency */
494     if (stepnum == 0) {
495       e->timeprev = e->time - ts->time_step;
496     } else {
497       ierr = TSGetPrevTime(ts,&timeprev);CHKERRQ(ierr);
498       e->timeprev = timeprev;
499     }
500     ierr = StackPush(s,e);CHKERRQ(ierr);
501   }
502   PetscFunctionReturn(0);
503 }
504 
505 #undef __FUNCT__
506 #define __FUNCT__ "TSTrajectoryGet_Memory"
507 PetscErrorCode TSTrajectoryGet_Memory(TSTrajectory tj,TS ts,PetscInt stepnum,PetscReal *t)
508 {
509   Vec            *Y;
510   PetscInt       i;
511   StackElement   e;
512   Stack          *s = (Stack*)tj->data;
513   PetscReal      stepsize;
514   PetscInt       localstepnum,id;
515 #ifdef PETSC_HAVE_REVOLVE
516   PetscInt       whattodo,shift;
517 #endif
518   PetscErrorCode ierr;
519 
520   PetscFunctionBegin;
521   ierr = TSGetTotalSteps(ts,&stepnum);CHKERRQ(ierr);
522   if (s->stype == TWO_LEVEL_REVOLVE || s->stype == TWO_LEVEL_NOREVOLVE) { /* two-level mode */
523     localstepnum = stepnum%s->stride;
524     if (localstepnum == 0 && stepnum != 0 && stepnum != s->total_steps) {
525 #ifdef PETSC_HAVE_REVOLVE
526       PetscPrintf(PETSC_COMM_WORLD,"\x1B[33mLoad stack from file\033[0m\n");
527 #endif
528       id = stepnum/s->stride;
529       ierr = StackLoadAll(ts,s,id);CHKERRQ(ierr);
530       s->top = s->stacksize-1;
531 #ifdef PETSC_HAVE_REVOLVE
532       if (s->stype == TWO_LEVEL_REVOLVE) {
533         revolve_reset();
534         revolve_create_offline(s->stride,s->max_cps_ram);
535         s->rctx->check = 0;
536         s->rctx->capo  = 0;
537         s->rctx->fine  = s->stride;
538         whattodo = 0;
539         while(whattodo!=3) { /* stupid revolve */
540           whattodo = revolve_action(&s->rctx->check,&s->rctx->capo,&s->rctx->fine,s->rctx->snaps_in,&s->rctx->info,&s->rctx->where);
541         }
542       }
543 #endif
544     }
545   } else {
546     localstepnum = stepnum;
547   }
548 #ifdef PETSC_HAVE_REVOLVE
549   if (s->stype > TWO_LEVEL_NOREVOLVE && s->rctx->reverseonestep) { /* ready for the reverse step */
550     ierr = TSGetTimeStep(ts,&stepsize);CHKERRQ(ierr);
551     ierr = TSSetTimeStep(ts,-stepsize);CHKERRQ(ierr);
552     s->rctx->reverseonestep = PETSC_FALSE;
553     PetscFunctionReturn(0);
554   }
555 #endif
556   if (localstepnum == 0 || stepnum == s->total_steps) {
557     ierr = TSGetTimeStep(ts,&stepsize);CHKERRQ(ierr);
558     ierr = TSSetTimeStep(ts,-stepsize);CHKERRQ(ierr);
559     PetscFunctionReturn(0);
560   }
561   /* restore a checkpoint */
562   ierr = StackTop(s,&e);CHKERRQ(ierr);
563   ierr = VecCopy(e->X,ts->vec_sol);CHKERRQ(ierr);
564   ierr = TSGetStages(ts,&s->numY,&Y);CHKERRQ(ierr);
565   for (i=0;i<s->numY;i++) {
566     ierr = VecCopy(e->Y[i],Y[i]);CHKERRQ(ierr);
567   }
568   *t = e->time;
569 
570   if (e->stepnum < stepnum) { /* need recomputation */
571     s->recompute = PETSC_TRUE;
572     shift = stepnum-localstepnum;
573 #ifdef PETSC_HAVE_REVOLVE
574     s->rctx->capo = localstepnum;
575     whattodo = revolve_action(&s->rctx->check,&s->rctx->capo,&s->rctx->fine,s->rctx->snaps_in,&s->rctx->info,&s->rctx->where);
576     printwhattodo(whattodo,s->rctx,shift);
577 #endif
578     ierr = TSSetTimeStep(ts,(*t)-e->timeprev);CHKERRQ(ierr);
579     /* reset ts context */
580     PetscInt steps = ts->steps;
581     ts->steps      = e->stepnum;
582     ts->ptime      = e->time;
583     ts->ptime_prev = e->timeprev;
584     for (i=e->stepnum;i<stepnum;i++) { /* assume fixed step size */
585       ierr = TSTrajectorySet(ts->trajectory,ts,ts->steps,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
586       ierr = TSMonitor(ts,ts->steps,ts->ptime,ts->vec_sol);CHKERRQ(ierr);
587       ierr = TSStep(ts);CHKERRQ(ierr);
588       if (ts->event) {
589         ierr = TSEventMonitor(ts);CHKERRQ(ierr);
590       }
591       if (!ts->steprollback) {
592         ierr = TSPostStep(ts);CHKERRQ(ierr);
593       }
594     }
595     /* reverseonestep must be true after the for loop */
596     ts->steps = steps;
597     ts->total_steps = stepnum;
598     ierr = TSGetTimeStep(ts,&stepsize);CHKERRQ(ierr);
599     ierr = TSSetTimeStep(ts,-stepsize);CHKERRQ(ierr);
600     if (stepnum-e->stepnum==1) { /* the restored checkpoint can be deleted now */
601       ierr = StackPop(s,&e);CHKERRQ(ierr);
602       ierr = VecDestroy(&e->X);CHKERRQ(ierr);
603       ierr = VecDestroyVecs(s->numY,&e->Y);CHKERRQ(ierr);
604       ierr = PetscFree(e);CHKERRQ(ierr);
605     }
606 #ifdef PETSC_HAVE_REVOLVE
607     s->rctx->reverseonestep = PETSC_FALSE;
608 #endif
609   } else if (e->stepnum == stepnum) { /* restore the data directly from checkpoints */
610     ierr = TSSetTimeStep(ts,-(*t)+e->timeprev);CHKERRQ(ierr);
611     ierr = StackPop(s,&e);CHKERRQ(ierr);
612     ierr = VecDestroy(&e->X);CHKERRQ(ierr);
613     ierr = VecDestroyVecs(s->numY,&e->Y);CHKERRQ(ierr);
614     ierr = PetscFree(e);CHKERRQ(ierr);
615   } else {
616     SETERRQ2(s->comm,PETSC_ERR_ARG_OUTOFRANGE,"The current step no. is %D, but the step number at top of the stack is %D",stepnum,e->stepnum);
617   }
618 
619   PetscFunctionReturn(0);
620 }
621 
622 #undef __FUNCT__
623 #define __FUNCT__ "TSTrajectoryDestroy_Memory"
624 PETSC_EXTERN PetscErrorCode TSTrajectoryDestroy_Memory(TSTrajectory tj)
625 {
626   Stack          *s = (Stack*)tj->data;
627   PetscErrorCode ierr;
628 
629   PetscFunctionBegin;
630   if (s->stype > TWO_LEVEL_NOREVOLVE) {
631 #ifdef PETSC_HAVE_REVOLVE
632     revolve_reset();
633 #endif
634   }
635   ierr = StackDestroy(s);CHKERRQ(ierr);
636   PetscFunctionReturn(0);
637 }
638 
639 /*MC
640       TSTRAJECTORYMEMORY - Stores each solution of the ODE/ADE in memory
641 
642   Level: intermediate
643 
644 .seealso:  TSTrajectoryCreate(), TS, TSTrajectorySetType()
645 
646 M*/
647 #undef __FUNCT__
648 #define __FUNCT__ "TSTrajectoryCreate_Memory"
649 PETSC_EXTERN PetscErrorCode TSTrajectoryCreate_Memory(TSTrajectory tj,TS ts)
650 {
651   Stack          *s;
652   PetscErrorCode ierr;
653 
654   PetscFunctionBegin;
655   tj->ops->set            = TSTrajectorySet_Memory;
656   tj->ops->get            = TSTrajectoryGet_Memory;
657   tj->ops->setup          = TSTrajectorySetUp_Memory;
658   tj->ops->destroy        = TSTrajectoryDestroy_Memory;
659   tj->ops->setfromoptions = TSTrajectorySetFromOptions_Memory;
660 
661   ierr = PetscCalloc1(1,&s);CHKERRQ(ierr);
662   s->stype        = NONE;
663   s->max_cps_ram  = -1; /* -1 indicates that it is not set */
664   s->max_cps_disk = -1; /* -1 indicates that it is not set */
665   s->stride       = 0; /* if not zero, two-level checkpointing will be used */
666   tj->data        = s;
667   PetscFunctionReturn(0);
668 }
669