Actual source code: trajmemory.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      1:  #include <petsc/private/tsimpl.h>
      2:  #include <petscsys.h>
      3: #if defined(PETSC_HAVE_REVOLVE)
      4: #include <revolve_c.h>
      5: #endif

      7: PetscLogEvent TSTrajectory_DiskWrite, TSTrajectory_DiskRead;

      9: typedef enum {NONE,TWO_LEVEL_NOREVOLVE,TWO_LEVEL_REVOLVE,TWO_LEVEL_TWO_REVOLVE,REVOLVE_OFFLINE,REVOLVE_ONLINE,REVOLVE_MULTISTAGE} SchedulerType;

     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;

     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

     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;

     43: typedef struct _DiskStack {
     44:   PetscInt  stacksize;
     45:   PetscInt  top;
     46:   PetscInt  *container;
     47: } DiskStack;

     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;

     67: static PetscErrorCode TurnForwardWithStepsize(TS ts,PetscReal nextstepsize)
     68: {
     69:     PetscReal      stepsize;

     73:     /* reverse the direction */
     74:     TSGetTimeStep(ts,&stepsize);
     75:     stepsize = nextstepsize;
     76:     TSSetTimeStep(ts,stepsize);
     77:     return(0);
     78: }

     80: static PetscErrorCode TurnForward(TS ts)
     81: {
     82:   PetscReal      stepsize;

     86:   /* reverse the direction */
     87:   TSGetTimeStep(ts,&stepsize);
     88:   TSSetTimeStep(ts,-stepsize);
     89:   return(0);
     90: }

     92: static PetscErrorCode TurnBackward(TS ts)
     93: {
     94:   PetscReal      stepsize;

     98:   /* reverse the direction */
     99:   stepsize = ts->ptime_prev-ts->ptime;
    100:   TSSetTimeStep(ts,stepsize);
    101:   return(0);
    102: }

    104: static PetscErrorCode ElementCreate(TS ts,Stack *stack,StackElement *e)
    105: {
    106:   Vec            X;
    107:   Vec            *Y;

    111:   if (stack->use_dram) {
    112:     PetscMallocSetDRAM();
    113:   }
    114:   PetscCalloc1(1,e);
    115:   TSGetSolution(ts,&X);
    116:   VecDuplicate(X,&(*e)->X);
    117:   if (stack->numY > 0 && !stack->solution_only) {
    118:     TSGetStages(ts,&stack->numY,&Y);
    119:     VecDuplicateVecs(Y[0],stack->numY,&(*e)->Y);
    120:   }
    121:   if (stack->use_dram) {
    122:     PetscMallocResetDRAM();
    123:   }
    124:   return(0);
    125: }

    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;

    135:   VecCopy(X,(*e)->X);
    136:   if (stack->numY > 0 && !stack->solution_only) {
    137:     TSGetStages(ts,&stack->numY,&Y);
    138:     for (i=0;i<stack->numY;i++) {
    139:       VecCopy(Y[i],(*e)->Y[i]);
    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:     TSGetPrevTime(ts,&timeprev);
    149:     (*e)->timeprev = timeprev;
    150:   }
    151:   return(0);
    152: }

    154: static PetscErrorCode ElementDestroy(Stack *stack,StackElement e)
    155: {

    159:   if (stack->use_dram) {
    160:     PetscMallocSetDRAM();
    161:   }
    162:   VecDestroy(&e->X);
    163:   if (stack->numY > 0 && !stack->solution_only) {
    164:     VecDestroyVecs(stack->numY,&e->Y);
    165:   }
    166:   PetscFree(e);
    167:   if (stack->use_dram) {
    168:     PetscMallocResetDRAM();
    169:   }
    170:   return(0);
    171: }

    173: static PetscErrorCode StackResize(Stack *stack,PetscInt newsize)
    174: {
    175:   StackElement   *newcontainer;
    176:   PetscInt       i;

    180:   PetscMalloc1(newsize*sizeof(StackElement),&newcontainer);
    181:   for (i=0;i<stack->stacksize;i++) {
    182:     newcontainer[i] = stack->container[i];
    183:   }
    184:   PetscFree(stack->container);
    185:   stack->container = newcontainer;
    186:   stack->stacksize = newsize;
    187:   return(0);
    188: }

    190: static PetscErrorCode StackPush(Stack *stack,StackElement e)
    191: {
    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:   return(0);
    196: }

    198: static PetscErrorCode StackPop(Stack *stack,StackElement *e)
    199: {
    201:   *e = NULL;
    202:   if (stack->top == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Empty stack");
    203:   *e = stack->container[stack->top--];
    204:   return(0);
    205: }

    207: static PetscErrorCode StackTop(Stack *stack,StackElement *e)
    208: {
    210:   *e = stack->container[stack->top];
    211:   return(0);
    212: }

    214: static PetscErrorCode StackCreate(Stack *stack,PetscInt size,PetscInt ny)
    215: {

    219:   stack->top  = -1;
    220:   stack->numY = ny;

    222:   PetscMalloc1(size*sizeof(StackElement),&stack->container);
    223:   return(0);
    224: }

    226: static PetscErrorCode StackDestroy(Stack *stack)
    227: {
    228:   PetscInt       i,n;
    229:   StackElement   e;

    233:   if (stack->top > -1) {
    234:     n = stack->top+1; /* number of elements in the stack */
    235:     for (i=0;i<n;i++) {
    236:       StackPop(stack,&e);
    237:       ElementDestroy(stack,e);
    238:     }
    239:   }
    240:   PetscFree(stack->container);
    241:   return(0);
    242: }

    244: #if defined(PETSC_HAVE_REVOLVE)
    245: static PetscErrorCode StackFind(Stack *stack,StackElement *e,PetscInt index)
    246: {
    248:   *e = stack->container[index];
    249:   return(0);
    250: }
    251: #endif

    253: static PetscErrorCode OutputBIN(MPI_Comm comm,const char *filename,PetscViewer *viewer)
    254: {

    258:   PetscViewerCreate(comm,viewer);
    259:   PetscViewerSetType(*viewer,PETSCVIEWERBINARY);
    260:   PetscViewerFileSetMode(*viewer,FILE_MODE_WRITE);
    261:   PetscViewerFileSetName(*viewer,filename);
    262:   return(0);
    263: }

    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;

    271:   PetscViewerBinaryWrite(viewer,&stepnum,1,PETSC_INT,PETSC_FALSE);
    272:   VecView(X,viewer);
    273:   for (i=0;!solution_only && i<numY;i++) {
    274:     VecView(Y[i],viewer);
    275:   }
    276:   PetscViewerBinaryWrite(viewer,&time,1,PETSC_REAL,PETSC_FALSE);
    277:   PetscViewerBinaryWrite(viewer,&timeprev,1,PETSC_REAL,PETSC_FALSE);
    278:   return(0);
    279: }

    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;

    287:   PetscViewerBinaryRead(viewer,stepnum,1,NULL,PETSC_INT);
    288:   VecLoad(X,viewer);
    289:   for (i=0;!solution_only && i<numY;i++) {
    290:     VecLoad(Y[i],viewer);
    291:   }
    292:   PetscViewerBinaryRead(viewer,time,1,NULL,PETSC_REAL);
    293:   PetscViewerBinaryRead(viewer,timeprev,1,NULL,PETSC_REAL);
    294:   return(0);
    295: }

    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];
    305:   MPI_Comm       comm;

    308:   PetscObjectGetComm((PetscObject)ts,&comm);
    309:   if (tj->monitor) {
    310:     PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    311:     PetscViewerASCIIPrintf(tj->monitor,"Dump stack to file\n");
    312:     PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    313:   }
    314:   if (id == 1) {
    315:     PetscMPIInt rank;
    316:     MPI_Comm_rank(comm,&rank);
    317:     if (!rank) {
    318:       PetscRMTree("SA-data");
    319:       PetscMkdir("SA-data");
    320:     }
    321:   }
    322:   PetscSNPrintf(filename,sizeof(filename),"SA-data/SA-STACK%06d.bin",id);
    323:   OutputBIN(comm,filename,&viewer);
    324:   for (i=0;i<stack->stacksize;i++) {
    325:     e = stack->container[i];
    326:     PetscLogEventBegin(TSTrajectory_DiskWrite,tj,ts,0,0);
    327:     WriteToDisk(e->stepnum,e->time,e->timeprev,e->X,e->Y,stack->numY,stack->solution_only,viewer);
    328:     PetscLogEventEnd(TSTrajectory_DiskWrite,tj,ts,0,0);
    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:   TSGetStages(ts,&stack->numY,&Y);
    333:   PetscLogEventBegin(TSTrajectory_DiskWrite,tj,ts,0,0);
    334:   WriteToDisk(ts->steps,ts->ptime,ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);
    335:   PetscLogEventEnd(TSTrajectory_DiskWrite,tj,ts,0,0);
    336:   ts->trajectory->diskwrites++;
    337:   for (i=0;i<stack->stacksize;i++) {
    338:     StackPop(stack,&e);
    339:     ElementDestroy(stack,e);
    340:   }
    341:   PetscViewerDestroy(&viewer);
    342:   return(0);
    343: }

    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];

    355:   if (tj->monitor) {
    356:     PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    357:     PetscViewerASCIIPrintf(tj->monitor,"Load stack from file\n");
    358:     PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    359:   }
    360:   PetscSNPrintf(filename,sizeof filename,"SA-data/SA-STACK%06d.bin",id);
    361:   PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);
    362:   for (i=0;i<stack->stacksize;i++) {
    363:     ElementCreate(ts,stack,&e);
    364:     StackPush(stack,e);
    365:     PetscLogEventBegin(TSTrajectory_DiskRead,tj,ts,0,0);
    366:     ReadFromDisk(&e->stepnum,&e->time,&e->timeprev,e->X,e->Y,stack->numY,stack->solution_only,viewer);
    367:     PetscLogEventEnd(TSTrajectory_DiskRead,tj,ts,0,0);
    368:     ts->trajectory->diskreads++;
    369:   }
    370:   /* load the last step into TS */
    371:   TSGetStages(ts,&stack->numY,&Y);
    372:   PetscLogEventBegin(TSTrajectory_DiskRead,tj,ts,0,0);
    373:   ReadFromDisk(&ts->steps,&ts->ptime,&ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);
    374:   PetscLogEventEnd(TSTrajectory_DiskRead,tj,ts,0,0);
    375:   ts->trajectory->diskreads++;
    376:   TurnBackward(ts);
    377:   PetscViewerDestroy(&viewer);
    378:   return(0);
    379: }

    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;

    396:   if (tj->monitor) {
    397:     PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    398:     PetscViewerASCIIPrintf(tj->monitor,"Load last stack element from file\n");
    399:     PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    400:   }
    401:   TSGetStages(ts,&stack->numY,&Y);
    402:   VecGetSize(Y[0],&size);
    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;

    406:   PetscSNPrintf(filename,sizeof filename,"SA-data/SA-STACK%06d.bin",id);
    407:   PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);
    408: #if defined(PETSC_HAVE_MPIIO)
    409:   PetscViewerBinaryGetUseMPIIO(viewer,&usempiio);
    410:   if (usempiio) {
    411:     PetscViewerBinaryGetMPIIODescriptor(viewer,(MPI_File*)&fd);
    412:     PetscBinarySynchronizedSeek(PETSC_COMM_WORLD,fd,off,PETSC_BINARY_SEEK_END,&offset);
    413:   } else {
    414: #endif
    415:     PetscViewerBinaryGetDescriptor(viewer,&fd);
    416:     PetscBinarySeek(fd,off,PETSC_BINARY_SEEK_END,&offset);
    417: #if defined(PETSC_HAVE_MPIIO)
    418:   }
    419: #endif
    420:   /* load the last step into TS */
    421:   PetscLogEventBegin(TSTrajectory_DiskRead,tj,ts,0,0);
    422:   ReadFromDisk(&ts->steps,&ts->ptime,&ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);
    423:   PetscLogEventEnd(TSTrajectory_DiskRead,tj,ts,0,0);
    424:   ts->trajectory->diskreads++;
    425:   TurnBackward(ts);
    426:   PetscViewerDestroy(&viewer);
    427:   return(0);
    428: }
    429: #endif

    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];
    438:   MPI_Comm       comm;

    441:   PetscObjectGetComm((PetscObject)ts,&comm);
    442:   if (tj->monitor) {
    443:     PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    444:     PetscViewerASCIIPrintf(tj->monitor,"Load a single point from file\n");
    445:     PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    446:   }
    447:   TSGetStepNumber(ts,&stepnum);
    448:   if (id == 1) {
    449:     PetscMPIInt rank;
    450:     MPI_Comm_rank(comm,&rank);
    451:     if (!rank) {
    452:       PetscRMTree("SA-data");
    453:       PetscMkdir("SA-data");
    454:     }
    455:   }
    456:   PetscSNPrintf(filename,sizeof(filename),"SA-data/SA-CPS%06d.bin",id);
    457:   OutputBIN(comm,filename,&viewer);

    459:   TSGetStages(ts,&stack->numY,&Y);
    460:   PetscLogEventBegin(TSTrajectory_DiskWrite,tj,ts,0,0);
    461:   WriteToDisk(stepnum,ts->ptime,ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);
    462:   PetscLogEventEnd(TSTrajectory_DiskWrite,tj,ts,0,0);
    463:   ts->trajectory->diskwrites++;

    465:   PetscViewerDestroy(&viewer);
    466:   return(0);
    467: }

    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];

    477:   if (tj->monitor) {
    478:     PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    479:     PetscViewerASCIIPrintf(tj->monitor,"Load a single point from file\n");
    480:     PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    481:   }
    482:   PetscSNPrintf(filename,sizeof filename,"SA-data/SA-CPS%06d.bin",id);
    483:   PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);

    485:   TSGetStages(ts,&stack->numY,&Y);
    486:   PetscLogEventBegin(TSTrajectory_DiskRead,tj,ts,0,0);
    487:   ReadFromDisk(&ts->steps,&ts->ptime,&ts->ptime_prev,ts->vec_sol,Y,stack->numY,stack->solution_only,viewer);
    488:   PetscLogEventEnd(TSTrajectory_DiskRead,tj,ts,0,0);
    489:   ts->trajectory->diskreads++;

    491:   PetscViewerDestroy(&viewer);
    492:   return(0);
    493: }

    495: static PetscErrorCode UpdateTS(TS ts,Stack *stack,StackElement e)
    496: {
    497:   Vec            *Y;
    498:   PetscInt       i;

    502:   VecCopy(e->X,ts->vec_sol);
    503:   if (!stack->solution_only) {
    504:     TSGetStages(ts,&stack->numY,&Y);
    505:     for (i=0;i<stack->numY;i++) {
    506:       VecCopy(e->Y[i],Y[i]);
    507:     }
    508:   }
    509:   TSSetTimeStep(ts,e->timeprev-e->time); /* stepsize will be negative */
    510:   ts->ptime      = e->time;
    511:   ts->ptime_prev = e->timeprev;
    512:   return(0);
    513: }

    515: static PetscErrorCode ReCompute(TS ts,TJScheduler *tjsch,PetscInt stepnumbegin,PetscInt stepnumend)
    516: {
    517:   Stack          *stack = &tjsch->stack;
    518:   PetscInt       i;

    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:       TSTrajectorySet(ts->trajectory,ts,ts->steps,ts->ptime,ts->vec_sol);
    526:     }
    527:     TSMonitor(ts,ts->steps,ts->ptime,ts->vec_sol);
    528:     TSStep(ts);
    529:     if (!stack->solution_only && !tjsch->skip_trajectory) {
    530:       TSTrajectorySet(ts->trajectory,ts,ts->steps,ts->ptime,ts->vec_sol);
    531:     }
    532:     TSEventHandler(ts);
    533:     if (!ts->steprollback) {
    534:       TSPostStep(ts);
    535:     }
    536:   }
    537:   TurnBackward(ts);
    538:   ts->trajectory->recomps += stepnumend-stepnumbegin; /* recomputation counter */
    539:   ts->steps = stepnumend;
    540:   return(0);
    541: }

    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;

    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:         StackDumpAll(tj,ts,stack,stridenum+1);
    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:         DumpSingle(tj,ts,stack,stridenum+1);
    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:         StackDumpAll(tj,ts,stack,stridenum);
    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:         DumpSingle(tj,ts,stack,stridenum+1);
    580:         if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) diskstack->container[++diskstack->top] = stridenum+1;
    581:         *done = PETSC_TRUE;
    582:       }
    583:     }
    584:   }
    585:   return(0);
    586: }

    588: static PetscErrorCode SetTrajN(TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
    589: {
    590:   Stack          *stack = &tjsch->stack;
    591:   StackElement   e;

    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:       StackPop(stack,&e);
    602:       ElementDestroy(stack,e);
    603:     }
    604:     return(0);
    605:   }
    606:   /*  do not save trajectory at the recompute stage for solution_only mode */
    607:   if (stack->solution_only && tjsch->recompute) return(0);
    608:   /* skip the first step for no_solution_only mode */
    609:   if (!stack->solution_only && stepnum == 0) return(0);

    611:   /* resize the stack */
    612:   if (stack->top+1 == stack->stacksize) {
    613:     StackResize(stack,2*stack->stacksize);
    614:   }
    615:   /* update timenext for the previous step; necessary for step adaptivity */
    616:   if (stack->top > -1) {
    617:     StackTop(stack,&e);
    618:     e->timenext = ts->ptime;
    619:   }
    620:   if (stepnum < stack->top) {
    621:     SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
    622:   }
    623:   ElementCreate(ts,stack,&e);
    624:   ElementSet(ts,stack,&e,stepnum,time,X);
    625:   StackPush(stack,e);
    626:   return(0);
    627: }

    629: static PetscErrorCode GetTrajN(TS ts,TJScheduler *tjsch,PetscInt stepnum)
    630: {
    631:   Stack          *stack = &tjsch->stack;
    632:   StackElement   e;

    636:   if (stepnum == tjsch->total_steps) {
    637:     TurnBackward(ts);
    638:     return(0);
    639:   }
    640:   /* restore a checkpoint */
    641:   StackTop(stack,&e);
    642:   UpdateTS(ts,stack,e);
    643:   if (stack->solution_only) {/* recompute one step */
    644:     tjsch->recompute = PETSC_TRUE;
    645:     TurnForwardWithStepsize(ts,e->timenext-e->time);
    646:     ReCompute(ts,tjsch,e->stepnum,stepnum);
    647:   }
    648:   StackPop(stack,&e);
    649:   ElementDestroy(stack,e);
    650:   return(0);
    651: }

    653: static PetscErrorCode SetTrajTLNR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
    654: {
    655:   Stack          *stack = &tjsch->stack;
    656:   PetscInt       localstepnum,laststridesize;
    657:   StackElement   e;
    658:   PetscBool      done;

    662:   if (!stack->solution_only && stepnum == 0) return(0);
    663:   if (stack->solution_only && stepnum == tjsch->total_steps) return(0);
    664:   if (tjsch->save_stack && tjsch->recompute) return(0);

    666:   localstepnum = stepnum%tjsch->stride;
    667:   /* (stride size-1) checkpoints are saved in each stride; an extra point is added by StackDumpAll() */
    668:   laststridesize = tjsch->total_steps%tjsch->stride;
    669:   if (!laststridesize) laststridesize = tjsch->stride;

    671:   if (!tjsch->recompute) {
    672:     TopLevelStore(tj,ts,tjsch,stepnum,localstepnum,laststridesize,&done);
    673:     if (!tjsch->save_stack && stepnum < tjsch->total_steps-laststridesize) return(0);
    674:   }
    675:   if (!stack->solution_only && localstepnum == 0) return(0); /* skip last point in each stride at recompute stage or last stride */
    676:   if (stack->solution_only && localstepnum == tjsch->stride-1) return(0); /* skip last step in each stride at recompute stage or last stride */

    678:   ElementCreate(ts,stack,&e);
    679:   ElementSet(ts,stack,&e,stepnum,time,X);
    680:   StackPush(stack,e);
    681:   return(0);
    682: }

    684: static PetscErrorCode GetTrajTLNR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
    685: {
    686:   Stack          *stack = &tjsch->stack;
    687:   PetscInt       id,localstepnum,laststridesize;
    688:   StackElement   e;

    692:   if (stepnum == tjsch->total_steps) {
    693:     TurnBackward(ts);
    694:     return(0);
    695:   }

    697:   localstepnum = stepnum%tjsch->stride;
    698:   laststridesize = tjsch->total_steps%tjsch->stride;
    699:   if (!laststridesize) laststridesize = tjsch->stride;
    700:   if (stack->solution_only) {
    701:     /* fill stack with info */
    702:     if (localstepnum == 0 && tjsch->total_steps-stepnum >= laststridesize) {
    703:       id = stepnum/tjsch->stride;
    704:       if (tjsch->save_stack) {
    705:         StackLoadAll(tj,ts,stack,id);
    706:         tjsch->recompute = PETSC_TRUE;
    707:         tjsch->skip_trajectory = PETSC_TRUE;
    708:         TurnForward(ts);
    709:         ReCompute(ts,tjsch,id*tjsch->stride-1,id*tjsch->stride);
    710:         tjsch->skip_trajectory = PETSC_FALSE;
    711:       } else {
    712:         LoadSingle(tj,ts,stack,id);
    713:         tjsch->recompute = PETSC_TRUE;
    714:         TurnForward(ts);
    715:         ReCompute(ts,tjsch,(id-1)*tjsch->stride,id*tjsch->stride);
    716:       }
    717:       return(0);
    718:     }
    719:     /* restore a checkpoint */
    720:     StackPop(stack,&e);
    721:     UpdateTS(ts,stack,e);
    722:     tjsch->recompute = PETSC_TRUE;
    723:     tjsch->skip_trajectory = PETSC_TRUE;
    724:     TurnForward(ts);
    725:     ReCompute(ts,tjsch,e->stepnum,stepnum);
    726:     tjsch->skip_trajectory = PETSC_FALSE;
    727:     ElementDestroy(stack,e);
    728:   } else {
    729:     /* fill stack with info */
    730:     if (localstepnum == 0 && tjsch->total_steps-stepnum >= laststridesize) {
    731:       id = stepnum/tjsch->stride;
    732:       if (tjsch->save_stack) {
    733:         StackLoadAll(tj,ts,stack,id);
    734:       } else {
    735:         LoadSingle(tj,ts,stack,id);
    736:         ElementCreate(ts,stack,&e);
    737:         ElementSet(ts,stack,&e,(id-1)*tjsch->stride+1,ts->ptime,ts->vec_sol);
    738:         StackPush(stack,e);
    739:         tjsch->recompute = PETSC_TRUE;
    740:         TurnForward(ts);
    741:         ReCompute(ts,tjsch,e->stepnum,id*tjsch->stride);
    742:       }
    743:       return(0);
    744:     }
    745:     /* restore a checkpoint */
    746:     StackPop(stack,&e);
    747:     UpdateTS(ts,stack,e);
    748:     ElementDestroy(stack,e);
    749:   }
    750:   return(0);
    751: }

    753: #if defined(PETSC_HAVE_REVOLVE)
    754: static PetscErrorCode printwhattodo(PetscViewer viewer,PetscInt whattodo,RevolveCTX *rctx,PetscInt shift)
    755: {

    759:   if (!viewer) return(0);

    761:   switch(whattodo) {
    762:     case 1:
    763:       PetscViewerASCIIPrintf(viewer,"Advance from %D to %D\n",rctx->oldcapo+shift,rctx->capo+shift);
    764:       break;
    765:     case 2:
    766:       PetscViewerASCIIPrintf(viewer,"Store in checkpoint number %D (located in RAM)\n",rctx->check);
    767:       break;
    768:     case 3:
    769:       PetscViewerASCIIPrintf(viewer,"First turn: Initialize adjoints and reverse first step\n");
    770:       break;
    771:     case 4:
    772:       PetscViewerASCIIPrintf(viewer,"Forward and reverse one step\n");
    773:       break;
    774:     case 5:
    775:       PetscViewerASCIIPrintf(viewer,"Restore in checkpoint number %D (located in RAM)\n",rctx->check);
    776:       break;
    777:     case 7:
    778:       PetscViewerASCIIPrintf(viewer,"Store in checkpoint number %D (located on disk)\n",rctx->check);
    779:       break;
    780:     case 8:
    781:       PetscViewerASCIIPrintf(viewer,"Restore in checkpoint number %D (located on disk)\n",rctx->check);
    782:       break;
    783:     case -1:
    784:       PetscViewerASCIIPrintf(viewer,"Error!");
    785:       break;
    786:   }
    787:   return(0);
    788: }

    790: static PetscErrorCode printwhattodo2(PetscViewer viewer,PetscInt whattodo,RevolveCTX *rctx,PetscInt shift)
    791: {

    795:   if (!viewer) return(0);

    797:   switch(whattodo) {
    798:     case 1:
    799:       PetscViewerASCIIPrintf(viewer,"[Top Level] Advance from stride %D to stride %D\n",rctx->oldcapo+shift,rctx->capo+shift);
    800:       break;
    801:     case 2:
    802:       PetscViewerASCIIPrintf(viewer,"[Top Level] Store in checkpoint number %D\n",rctx->check);
    803:       break;
    804:     case 3:
    805:       PetscViewerASCIIPrintf(viewer,"[Top Level] First turn: Initialize adjoints and reverse first stride\n");
    806:       break;
    807:     case 4:
    808:       PetscViewerASCIIPrintf(viewer,"[Top Level] Forward and reverse one stride\n");
    809:       break;
    810:     case 5:
    811:       PetscViewerASCIIPrintf(viewer,"[Top Level] Restore in checkpoint number %D\n",rctx->check);
    812:       break;
    813:     case 7:
    814:       PetscViewerASCIIPrintf(viewer,"[Top Level] Store in top-level checkpoint number %D\n",rctx->check);
    815:       break;
    816:     case 8:
    817:       PetscViewerASCIIPrintf(viewer,"[Top Level] Restore in top-level checkpoint number %D\n",rctx->check);
    818:       break;
    819:     case -1:
    820:       PetscViewerASCIIPrintf(viewer,"[Top Level] Error!");
    821:       break;
    822:   }
    823:   return(0);
    824: }

    826: static PetscErrorCode InitRevolve(PetscInt fine,PetscInt snaps,RevolveCTX *rctx)
    827: {
    829:   revolve_reset();
    830:   revolve_create_offline(fine,snaps);
    831:   rctx->snaps_in       = snaps;
    832:   rctx->fine           = fine;
    833:   rctx->check          = 0;
    834:   rctx->capo           = 0;
    835:   rctx->reverseonestep = PETSC_FALSE;
    836:   /* check stepsleft? */
    837:   return(0);
    838: }

    840: static PetscErrorCode FastForwardRevolve(RevolveCTX *rctx)
    841: {
    842:   PetscInt whattodo;

    845:   whattodo = 0;
    846:   while(whattodo!=3) { /* we have to fast forward revolve to the beginning of the backward sweep due to unfriendly revolve interface */
    847:     whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
    848:   }
    849:   return(0);
    850: }

    852: static PetscErrorCode ApplyRevolve(PetscViewer viewer,SchedulerType stype,RevolveCTX *rctx,PetscInt total_steps,PetscInt stepnum,PetscInt localstepnum,PetscBool toplevel,PetscInt *store)
    853: {
    855:   PetscInt       shift,whattodo;

    858:   *store = 0;
    859:   if (rctx->stepsleft > 0) { /* advance the solution without checkpointing anything as Revolve requires */
    860:     rctx->stepsleft--;
    861:     return(0);
    862:   }
    863:   /* let Revolve determine what to do next */
    864:   shift         = stepnum-localstepnum;
    865:   rctx->oldcapo = rctx->capo;
    866:   rctx->capo    = localstepnum;

    868:   if (!toplevel) whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
    869:   else whattodo = revolve2_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
    870:   if (stype == REVOLVE_ONLINE && whattodo == 8) whattodo = 5;
    871:   if (stype == REVOLVE_ONLINE && whattodo == 7) whattodo = 2;
    872:   if (!toplevel) {printwhattodo(viewer,whattodo,rctx,shift);}
    873:   else {printwhattodo2(viewer,whattodo,rctx,shift);}
    874:   if (whattodo == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in the Revolve library");
    875:   if (whattodo == 1) { /* advance some time steps */
    876:     if (stype == REVOLVE_ONLINE && rctx->capo >= total_steps-1) {
    877:       revolve_turn(total_steps,&rctx->capo,&rctx->fine);
    878:       if (!toplevel) {printwhattodo(viewer,whattodo,rctx,shift);}
    879:       else {printwhattodo2(viewer,whattodo,rctx,shift);}
    880:     }
    881:     rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
    882:   }
    883:   if (whattodo == 3 || whattodo == 4) { /* ready for a reverse step */
    884:     rctx->reverseonestep = PETSC_TRUE;
    885:   }
    886:   if (whattodo == 5) { /* restore a checkpoint and ask Revolve what to do next */
    887:     rctx->oldcapo = rctx->capo;
    888:     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*/
    889:     else whattodo = revolve2_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
    890:     if (!toplevel) {printwhattodo(viewer,whattodo,rctx,shift);}
    891:     else {printwhattodo2(viewer,whattodo,rctx,shift);}
    892:     if (whattodo == 3 || whattodo == 4) rctx->reverseonestep = PETSC_TRUE;
    893:     if (whattodo == 1) rctx->stepsleft = rctx->capo-rctx->oldcapo;
    894:   }
    895:   if (whattodo == 7) { /* save the checkpoint to disk */
    896:     *store = 2;
    897:     rctx->oldcapo = rctx->capo;
    898:     whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where); /* must return 1 */
    899:     printwhattodo(viewer,whattodo,rctx,shift);
    900:     rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
    901:   }
    902:   if (whattodo == 2) { /* store a checkpoint to RAM and ask Revolve how many time steps to advance next */
    903:     *store = 1;
    904:     rctx->oldcapo = rctx->capo;
    905:     if (!toplevel) whattodo = revolve_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where); /* must return 1 */
    906:     else whattodo = revolve2_action(&rctx->check,&rctx->capo,&rctx->fine,rctx->snaps_in,&rctx->info,&rctx->where);
    907:     if (!toplevel) {printwhattodo(viewer,whattodo,rctx,shift);}
    908:     else {printwhattodo2(viewer,whattodo,rctx,shift);}
    909:     if (stype == REVOLVE_ONLINE && rctx->capo >= total_steps-1) {
    910:       revolve_turn(total_steps,&rctx->capo,&rctx->fine);
    911:       printwhattodo(viewer,whattodo,rctx,shift);
    912:     }
    913:     rctx->stepsleft = rctx->capo-rctx->oldcapo-1;
    914:   }
    915:   return(0);
    916: }

    918: static PetscErrorCode SetTrajROF(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
    919: {
    920:   Stack          *stack = &tjsch->stack;
    921:   PetscInt       store;
    922:   StackElement   e;

    926:   if (!stack->solution_only && stepnum == 0) return(0);
    927:   if (stack->solution_only && stepnum == tjsch->total_steps) return(0);
    928:   ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);
    929:   if (store == 1) {
    930:     if (stepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
    931:     ElementCreate(ts,stack,&e);
    932:     ElementSet(ts,stack,&e,stepnum,time,X);
    933:     StackPush(stack,e);
    934:   }
    935:   return(0);
    936: }

    938: static PetscErrorCode GetTrajROF(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
    939: {
    940:   Stack          *stack = &tjsch->stack;
    941:   PetscInt       whattodo,shift,store;
    942:   StackElement   e;

    946:   if (stepnum == 0 || stepnum == tjsch->total_steps) {
    947:     TurnBackward(ts);
    948:     tjsch->rctx->reverseonestep = PETSC_FALSE;
    949:     return(0);
    950:   }
    951:   /* restore a checkpoint */
    952:   StackTop(stack,&e);
    953:   UpdateTS(ts,stack,e);
    954:   if (stack->solution_only) { /* start with restoring a checkpoint */
    955:     tjsch->rctx->capo = stepnum;
    956:     tjsch->rctx->oldcapo = tjsch->rctx->capo;
    957:     shift = 0;
    958:     whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where);
    959:     printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);
    960:   } else { /* 2 revolve actions: restore a checkpoint and then advance */
    961:     ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);
    962:     if (tj->monitor) {
    963:       PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    964:       PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",tjsch->rctx->oldcapo,tjsch->rctx->oldcapo+1);
    965:       PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    966:     }
    967:     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
    968:   }
    969:   if (stack->solution_only || (!stack->solution_only && e->stepnum < stepnum)) {
    970:     tjsch->recompute = PETSC_TRUE;
    971:     TurnForward(ts);
    972:     ReCompute(ts,tjsch,e->stepnum,stepnum);
    973:   }
    974:   if ((stack->solution_only && e->stepnum+1 == stepnum) || (!stack->solution_only && e->stepnum == stepnum)) {
    975:     StackPop(stack,&e);
    976:     ElementDestroy(stack,e);
    977:   }
    978:   tjsch->rctx->reverseonestep = PETSC_FALSE;
    979:   return(0);
    980: }

    982: static PetscErrorCode SetTrajRON(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
    983: {
    984:   Stack          *stack = &tjsch->stack;
    985:   Vec            *Y;
    986:   PetscInt       i,store;
    987:   PetscReal      timeprev;
    988:   StackElement   e;
    989:   RevolveCTX     *rctx = tjsch->rctx;

    993:   if (!stack->solution_only && stepnum == 0) return(0);
    994:   if (stack->solution_only && stepnum == tjsch->total_steps) return(0);
    995:   ApplyRevolve(tj->monitor,tjsch->stype,rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);
    996:   if (store == 1) {
    997:     if (rctx->check != stack->top+1) { /* overwrite some non-top checkpoint in the stack */
    998:       StackFind(stack,&e,rctx->check);
    999:       VecCopy(X,e->X);
    1000:       if (stack->numY > 0 && !stack->solution_only) {
    1001:         TSGetStages(ts,&stack->numY,&Y);
    1002:         for (i=0;i<stack->numY;i++) {
    1003:           VecCopy(Y[i],e->Y[i]);
    1004:         }
    1005:       }
    1006:       e->stepnum  = stepnum;
    1007:       e->time     = time;
    1008:       TSGetPrevTime(ts,&timeprev);
    1009:       e->timeprev = timeprev;
    1010:     } else {
    1011:       if (stepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
    1012:       ElementCreate(ts,stack,&e);
    1013:       ElementSet(ts,stack,&e,stepnum,time,X);
    1014:       StackPush(stack,e);
    1015:     }
    1016:   }
    1017:   return(0);
    1018: }

    1020: static PetscErrorCode GetTrajRON(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
    1021: {
    1022:   Stack          *stack = &tjsch->stack;
    1023:   PetscInt       whattodo,shift;
    1024:   StackElement   e;

    1028:   if (stepnum == 0 || stepnum == tjsch->total_steps) {
    1029:     TurnBackward(ts);
    1030:     tjsch->rctx->reverseonestep = PETSC_FALSE;
    1031:     return(0);
    1032:   }
    1033:   tjsch->rctx->capo = stepnum;
    1034:   tjsch->rctx->oldcapo = tjsch->rctx->capo;
    1035:   shift = 0;
    1036:   whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where); /* whattodo=restore */
    1037:   if (whattodo == 8) whattodo = 5;
    1038:   printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);
    1039:   /* restore a checkpoint */
    1040:   StackFind(stack,&e,tjsch->rctx->check);
    1041:   UpdateTS(ts,stack,e);
    1042:   if (!stack->solution_only) { /* whattodo must be 5 */
    1043:     /* ask Revolve what to do next */
    1044:     tjsch->rctx->oldcapo = tjsch->rctx->capo;
    1045:     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*/
    1046:     printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);
    1047:     if (whattodo == 3 || whattodo == 4) tjsch->rctx->reverseonestep = PETSC_TRUE;
    1048:     if (whattodo == 1) tjsch->rctx->stepsleft = tjsch->rctx->capo-tjsch->rctx->oldcapo;
    1049:     if (tj->monitor) {
    1050:       PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    1051:       PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",tjsch->rctx->oldcapo,tjsch->rctx->oldcapo+1);
    1052:       PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    1053:     }
    1054:     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
    1055:   }
    1056:   if (stack->solution_only || (!stack->solution_only && e->stepnum < stepnum)) {
    1057:     tjsch->recompute = PETSC_TRUE;
    1058:     TurnForward(ts);
    1059:     ReCompute(ts,tjsch,e->stepnum,stepnum);
    1060:   }
    1061:   tjsch->rctx->reverseonestep = PETSC_FALSE;
    1062:   return(0);
    1063: }

    1065: static PetscErrorCode SetTrajTLR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
    1066: {
    1067:   Stack          *stack = &tjsch->stack;
    1068:   PetscInt       store,localstepnum,laststridesize;
    1069:   StackElement   e;
    1070:   PetscBool      done = PETSC_FALSE;

    1074:   if (!stack->solution_only && stepnum == 0) return(0);
    1075:   if (stack->solution_only && stepnum == tjsch->total_steps) return(0);

    1077:   localstepnum = stepnum%tjsch->stride;
    1078:   laststridesize = tjsch->total_steps%tjsch->stride;
    1079:   if (!laststridesize) laststridesize = tjsch->stride;

    1081:   if (!tjsch->recompute) {
    1082:     TopLevelStore(tj,ts,tjsch,stepnum,localstepnum,laststridesize,&done);
    1083:     /* revolve is needed for the last stride; different starting points for last stride between solutin_only and !solutin_only */
    1084:     if (!stack->solution_only && !tjsch->save_stack && stepnum <= tjsch->total_steps-laststridesize) return(0);
    1085:     if (stack->solution_only && !tjsch->save_stack && stepnum < tjsch->total_steps-laststridesize) return(0);
    1086:   }
    1087:   if (tjsch->save_stack && done) {
    1088:     InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1089:     return(0);
    1090:   }
    1091:   if (laststridesize < tjsch->stride) {
    1092:     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 */
    1093:       InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);
    1094:     }
    1095:     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 */
    1096:       InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);
    1097:     }
    1098:   }
    1099:   ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);
    1100:   if (store == 1) {
    1101:     if (localstepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
    1102:     ElementCreate(ts,stack,&e);
    1103:     ElementSet(ts,stack,&e,stepnum,time,X);
    1104:     StackPush(stack,e);
    1105:   }
    1106:   return(0);
    1107: }

    1109: static PetscErrorCode GetTrajTLR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
    1110: {
    1111:   Stack          *stack = &tjsch->stack;
    1112:   PetscInt       whattodo,shift;
    1113:   PetscInt       localstepnum,stridenum,laststridesize,store;
    1114:   StackElement   e;

    1118:   localstepnum = stepnum%tjsch->stride;
    1119:   stridenum    = stepnum/tjsch->stride;
    1120:   if (stepnum == tjsch->total_steps) {
    1121:     TurnBackward(ts);
    1122:     tjsch->rctx->reverseonestep = PETSC_FALSE;
    1123:     return(0);
    1124:   }
    1125:   laststridesize = tjsch->total_steps%tjsch->stride;
    1126:   if (!laststridesize) laststridesize = tjsch->stride;
    1127:   if (stack->solution_only) {
    1128:     /* fill stack */
    1129:     if (localstepnum == 0 && stepnum <= tjsch->total_steps-laststridesize) {
    1130:       if (tjsch->save_stack) {
    1131:         StackLoadAll(tj,ts,stack,stridenum);
    1132:         InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1133:         FastForwardRevolve(tjsch->rctx);
    1134:         tjsch->recompute = PETSC_TRUE;
    1135:         tjsch->skip_trajectory = PETSC_TRUE;
    1136:         TurnForward(ts);
    1137:         ReCompute(ts,tjsch,stridenum*tjsch->stride-1,stridenum*tjsch->stride);
    1138:         tjsch->skip_trajectory = PETSC_FALSE;
    1139:       } else {
    1140:         LoadSingle(tj,ts,stack,stridenum);
    1141:         InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1142:         tjsch->recompute = PETSC_TRUE;
    1143:         TurnForward(ts);
    1144:         ReCompute(ts,tjsch,(stridenum-1)*tjsch->stride,stridenum*tjsch->stride);
    1145:       }
    1146:       return(0);
    1147:     }
    1148:     /* restore a checkpoint */
    1149:     StackTop(stack,&e);
    1150:     UpdateTS(ts,stack,e);
    1151:     /* start with restoring a checkpoint */
    1152:     tjsch->rctx->capo = stepnum;
    1153:     tjsch->rctx->oldcapo = tjsch->rctx->capo;
    1154:     shift = stepnum-localstepnum;
    1155:     whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where);
    1156:     printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);
    1157:     tjsch->recompute = PETSC_TRUE;
    1158:     TurnForward(ts);
    1159:     ReCompute(ts,tjsch,e->stepnum,stepnum);
    1160:     if (e->stepnum+1 == stepnum) {
    1161:       StackPop(stack,&e);
    1162:       ElementDestroy(stack,e);
    1163:     }
    1164:   } else {
    1165:     /* fill stack with info */
    1166:     if (localstepnum == 0 && tjsch->total_steps-stepnum >= laststridesize) {
    1167:       if (tjsch->save_stack) {
    1168:         StackLoadAll(tj,ts,stack,stridenum);
    1169:         InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1170:         FastForwardRevolve(tjsch->rctx);
    1171:       } else {
    1172:         LoadSingle(tj,ts,stack,stridenum);
    1173:         InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1174:         ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,(stridenum-1)*tjsch->stride+1,1,PETSC_FALSE,&store);
    1175:         if (tj->monitor) {
    1176:           PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    1177:           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);
    1178:           PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    1179:         }
    1180:         ElementCreate(ts,stack,&e);
    1181:         ElementSet(ts,stack,&e,(stridenum-1)*tjsch->stride+1,ts->ptime,ts->vec_sol);
    1182:         StackPush(stack,e);
    1183:         tjsch->recompute = PETSC_TRUE;
    1184:         TurnForward(ts);
    1185:         ReCompute(ts,tjsch,e->stepnum,stridenum*tjsch->stride);
    1186:       }
    1187:       return(0);
    1188:     }
    1189:     /* restore a checkpoint */
    1190:     StackTop(stack,&e);
    1191:     UpdateTS(ts,stack,e);
    1192:     /* 2 revolve actions: restore a checkpoint and then advance */
    1193:     ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);
    1194:     if (tj->monitor) {
    1195:       PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    1196:       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);
    1197:       PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    1198:     }
    1199:     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
    1200:     if (e->stepnum < stepnum) {
    1201:       tjsch->recompute = PETSC_TRUE;
    1202:       TurnForward(ts);
    1203:       ReCompute(ts,tjsch,e->stepnum,stepnum);
    1204:     }
    1205:     if (e->stepnum == stepnum) {
    1206:       StackPop(stack,&e);
    1207:       ElementDestroy(stack,e);
    1208:     }
    1209:   }
    1210:   tjsch->rctx->reverseonestep = PETSC_FALSE;
    1211:   return(0);
    1212: }

    1214: static PetscErrorCode SetTrajTLTR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
    1215: {
    1216:   Stack          *stack = &tjsch->stack;
    1217:   PetscInt       store,localstepnum,stridenum,laststridesize;
    1218:   StackElement   e;
    1219:   PetscBool      done = PETSC_FALSE;

    1223:   if (!stack->solution_only && stepnum == 0) return(0);
    1224:   if (stack->solution_only && stepnum == tjsch->total_steps) return(0);

    1226:   localstepnum = stepnum%tjsch->stride; /* index at the bottom level (inside a stride) */
    1227:   stridenum    = stepnum/tjsch->stride; /* index at the top level */
    1228:   laststridesize = tjsch->total_steps%tjsch->stride;
    1229:   if (!laststridesize) laststridesize = tjsch->stride;
    1230:   if (stack->solution_only && localstepnum == 0 && !tjsch->rctx2->reverseonestep) {
    1231:     ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx2,(tjsch->total_steps+tjsch->stride-1)/tjsch->stride,stridenum,stridenum,PETSC_TRUE,&tjsch->store_stride);
    1232:     if (laststridesize < tjsch->stride && stepnum == tjsch->total_steps-laststridesize) {
    1233:       InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);
    1234:     }
    1235:   }
    1236:   if (!stack->solution_only && localstepnum == 1 && !tjsch->rctx2->reverseonestep) {
    1237:     ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx2,(tjsch->total_steps+tjsch->stride-1)/tjsch->stride,stridenum,stridenum,PETSC_TRUE,&tjsch->store_stride);
    1238:     if (laststridesize < tjsch->stride && stepnum == tjsch->total_steps-laststridesize+1) {
    1239:       InitRevolve(laststridesize,tjsch->max_cps_ram,tjsch->rctx);
    1240:     }
    1241:   }
    1242:   if (tjsch->store_stride) {
    1243:     TopLevelStore(tj,ts,tjsch,stepnum,localstepnum,laststridesize,&done);
    1244:     if (done) {
    1245:       InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1246:       return(0);
    1247:     }
    1248:   }
    1249:   if (stepnum < tjsch->total_steps-laststridesize) {
    1250:     if (tjsch->save_stack && !tjsch->store_stride && !tjsch->rctx2->reverseonestep) return(0); /* store or forward-and-reverse at top level trigger revolve at bottom level */
    1251:     if (!tjsch->save_stack && !tjsch->rctx2->reverseonestep) return(0); /* store operation does not require revolve be called at bottom level */
    1252:   }
    1253:   /* 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 */
    1254:   if (!stack->solution_only && localstepnum == 0 && stepnum != tjsch->total_steps && !tjsch->recompute) return(0);
    1255:   ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);
    1256:   if (store == 1) {
    1257:     if (localstepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
    1258:     ElementCreate(ts,stack,&e);
    1259:     ElementSet(ts,stack,&e,stepnum,time,X);
    1260:     StackPush(stack,e);
    1261:   }
    1262:   return(0);
    1263: }

    1265: static PetscErrorCode GetTrajTLTR(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
    1266: {
    1267:   Stack          *stack = &tjsch->stack;
    1268:   DiskStack      *diskstack = &tjsch->diskstack;
    1269:   PetscInt       whattodo,shift;
    1270:   PetscInt       localstepnum,stridenum,restoredstridenum,laststridesize,store;
    1271:   StackElement   e;

    1275:   localstepnum = stepnum%tjsch->stride;
    1276:   stridenum    = stepnum/tjsch->stride;
    1277:   if (stepnum == tjsch->total_steps) {
    1278:     TurnBackward(ts);
    1279:     tjsch->rctx->reverseonestep = PETSC_FALSE;
    1280:     return(0);
    1281:   }
    1282:   laststridesize = tjsch->total_steps%tjsch->stride;
    1283:   if (!laststridesize) laststridesize = tjsch->stride;
    1284:   /*
    1285:    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:
    1286:      Case 1 (save_stack)
    1287:        Restore a disk checkpoint; update TS with the last element in the restored data; recompute to the current point.
    1288:      Case 2 (!save_stack)
    1289:        Restore a disk checkpoint; update TS with the restored point; recompute to the current point.
    1290:   */
    1291:   if (localstepnum == 0 && stepnum <= tjsch->total_steps-laststridesize) {
    1292:     /* restore the top element in the stack for disk checkpoints */
    1293:     restoredstridenum = diskstack->container[diskstack->top];
    1294:     tjsch->rctx2->reverseonestep = PETSC_FALSE;
    1295:     /* top-level revolve must be applied before current step, just like the solution_only mode for single-level revolve */
    1296:     if (!tjsch->save_stack && stack->solution_only) { /* start with restoring a checkpoint */
    1297:       tjsch->rctx2->capo = stridenum;
    1298:       tjsch->rctx2->oldcapo = tjsch->rctx2->capo;
    1299:       shift = 0;
    1300:       whattodo = revolve2_action(&tjsch->rctx2->check,&tjsch->rctx2->capo,&tjsch->rctx2->fine,tjsch->rctx2->snaps_in,&tjsch->rctx2->info,&tjsch->rctx2->where);
    1301:       printwhattodo2(tj->monitor,whattodo,tjsch->rctx2,shift);
    1302:     } else { /* 2 revolve actions: restore a checkpoint and then advance */
    1303:       ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx2,(tjsch->total_steps+tjsch->stride-1)/tjsch->stride,stridenum,stridenum,PETSC_TRUE,&tjsch->store_stride);
    1304:       if (tj->monitor) {
    1305:         PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    1306:         PetscViewerASCIIPrintf(tj->monitor,"[Top Level] Skip the stride from %D to %D (stage values already checkpointed)\n",tjsch->rctx2->oldcapo,tjsch->rctx2->oldcapo+1);
    1307:         PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    1308:       }
    1309:       if (!tjsch->rctx2->reverseonestep && tjsch->rctx2->stepsleft > 0) tjsch->rctx2->stepsleft--;
    1310:     }
    1311:     /* fill stack */
    1312:     if (stack->solution_only) {
    1313:       if (tjsch->save_stack) {
    1314:         if (restoredstridenum < stridenum) {
    1315:           StackLoadLast(tj,ts,stack,restoredstridenum);
    1316:         } else {
    1317:           StackLoadAll(tj,ts,stack,restoredstridenum);
    1318:         }
    1319:         /* recompute one step ahead */
    1320:         tjsch->recompute = PETSC_TRUE;
    1321:         tjsch->skip_trajectory = PETSC_TRUE;
    1322:         TurnForward(ts);
    1323:         ReCompute(ts,tjsch,stridenum*tjsch->stride-1,stridenum*tjsch->stride);
    1324:         tjsch->skip_trajectory = PETSC_FALSE;
    1325:         if (restoredstridenum < stridenum) {
    1326:           InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1327:           tjsch->recompute = PETSC_TRUE;
    1328:           TurnForward(ts);
    1329:           ReCompute(ts,tjsch,restoredstridenum*tjsch->stride,stepnum);
    1330:         } else { /* stack ready, fast forward revolve status */
    1331:           InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1332:           FastForwardRevolve(tjsch->rctx);
    1333:         }
    1334:       } else {
    1335:         LoadSingle(tj,ts,stack,restoredstridenum);
    1336:         InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1337:         tjsch->recompute = PETSC_TRUE;
    1338:         TurnForward(ts);
    1339:         ReCompute(ts,tjsch,(restoredstridenum-1)*tjsch->stride,stepnum);
    1340:       }
    1341:     } else {
    1342:       if (tjsch->save_stack) {
    1343:         if (restoredstridenum < stridenum) {
    1344:           StackLoadLast(tj,ts,stack,restoredstridenum);
    1345:           /* reset revolve */
    1346:           InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1347:           tjsch->recompute = PETSC_TRUE;
    1348:           TurnForward(ts);
    1349:           ReCompute(ts,tjsch,restoredstridenum*tjsch->stride,stepnum);
    1350:         } else { /* stack ready, fast forward revolve status */
    1351:           StackLoadAll(tj,ts,stack,restoredstridenum);
    1352:           InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1353:           FastForwardRevolve(tjsch->rctx);
    1354:         }
    1355:       } else {
    1356:         LoadSingle(tj,ts,stack,restoredstridenum);
    1357:         InitRevolve(tjsch->stride,tjsch->max_cps_ram,tjsch->rctx);
    1358:         /* push first element to stack */
    1359:         if (tjsch->store_stride || tjsch->rctx2->reverseonestep) {
    1360:           shift = (restoredstridenum-1)*tjsch->stride-localstepnum;
    1361:           ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,(restoredstridenum-1)*tjsch->stride+1,1,PETSC_FALSE,&store);
    1362:           if (tj->monitor) {
    1363:             PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    1364:             PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",(restoredstridenum-1)*tjsch->stride,(restoredstridenum-1)*tjsch->stride+1);
    1365:             PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    1366:           }
    1367:           ElementCreate(ts,stack,&e);
    1368:           ElementSet(ts,stack,&e,(restoredstridenum-1)*tjsch->stride+1,ts->ptime,ts->vec_sol);
    1369:           StackPush(stack,e);
    1370:         }
    1371:         tjsch->recompute = PETSC_TRUE;
    1372:         TurnForward(ts);
    1373:         ReCompute(ts,tjsch,(restoredstridenum-1)*tjsch->stride+1,stepnum);
    1374:       }
    1375:     }
    1376:     if (restoredstridenum == stridenum) diskstack->top--;
    1377:     tjsch->rctx->reverseonestep = PETSC_FALSE;
    1378:     return(0);
    1379:   }

    1381:   if (stack->solution_only) {
    1382:     /* restore a checkpoint */
    1383:     StackTop(stack,&e);
    1384:     UpdateTS(ts,stack,e);
    1385:     /* start with restoring a checkpoint */
    1386:     tjsch->rctx->capo = stepnum;
    1387:     tjsch->rctx->oldcapo = tjsch->rctx->capo;
    1388:     shift = stepnum-localstepnum;
    1389:     whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where);
    1390:     printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);
    1391:     tjsch->recompute = PETSC_TRUE;
    1392:     TurnForward(ts);
    1393:     ReCompute(ts,tjsch,e->stepnum,stepnum);
    1394:     if (e->stepnum+1 == stepnum) {
    1395:       StackPop(stack,&e);
    1396:       ElementDestroy(stack,e);
    1397:     }
    1398:   } else {
    1399:     /* restore a checkpoint */
    1400:     StackTop(stack,&e);
    1401:     UpdateTS(ts,stack,e);
    1402:     /* 2 revolve actions: restore a checkpoint and then advance */
    1403:     ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,localstepnum,PETSC_FALSE,&store);
    1404:     if (tj->monitor) {
    1405:       PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    1406:       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);
    1407:       PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    1408:     }
    1409:     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
    1410:     if (e->stepnum < stepnum) {
    1411:       tjsch->recompute = PETSC_TRUE;
    1412:       TurnForward(ts);
    1413:       ReCompute(ts,tjsch,e->stepnum,stepnum);
    1414:     }
    1415:     if (e->stepnum == stepnum) {
    1416:       StackPop(stack,&e);
    1417:       ElementDestroy(stack,e);
    1418:     }
    1419:   }
    1420:   tjsch->rctx->reverseonestep = PETSC_FALSE;
    1421:   return(0);
    1422: }

    1424: static PetscErrorCode SetTrajRMS(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum,PetscReal time,Vec X)
    1425: {
    1426:   Stack          *stack = &tjsch->stack;
    1427:   PetscInt       store;
    1428:   StackElement   e;

    1432:   if (!stack->solution_only && stepnum == 0) return(0);
    1433:   if (stack->solution_only && stepnum == tjsch->total_steps) return(0);
    1434:   ApplyRevolve(tj->monitor,tjsch->stype,tjsch->rctx,tjsch->total_steps,stepnum,stepnum,PETSC_FALSE,&store);
    1435:   if (store == 1){
    1436:     if (stepnum < stack->top) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_MEMC,"Illegal modification of a non-top stack element");
    1437:     ElementCreate(ts,stack,&e);
    1438:     ElementSet(ts,stack,&e,stepnum,time,X);
    1439:     StackPush(stack,e);
    1440:   } else if (store == 2) {
    1441:     DumpSingle(tj,ts,stack,tjsch->rctx->check+1);
    1442:   }
    1443:   return(0);
    1444: }

    1446: static PetscErrorCode GetTrajRMS(TSTrajectory tj,TS ts,TJScheduler *tjsch,PetscInt stepnum)
    1447: {
    1448:   Stack          *stack = &tjsch->stack;
    1449:   PetscInt       whattodo,shift;
    1450:   PetscInt       restart;
    1451:   PetscBool      ondisk;
    1452:   StackElement   e;

    1456:   if (stepnum == 0 || stepnum == tjsch->total_steps) {
    1457:     TurnBackward(ts);
    1458:     tjsch->rctx->reverseonestep = PETSC_FALSE;
    1459:     return(0);
    1460:   }
    1461:   tjsch->rctx->capo = stepnum;
    1462:   tjsch->rctx->oldcapo = tjsch->rctx->capo;
    1463:   shift = 0;
    1464:   whattodo = revolve_action(&tjsch->rctx->check,&tjsch->rctx->capo,&tjsch->rctx->fine,tjsch->rctx->snaps_in,&tjsch->rctx->info,&tjsch->rctx->where); /* whattodo=restore */
    1465:   printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);
    1466:   /* restore a checkpoint */
    1467:   restart = tjsch->rctx->capo;
    1468:   if (!tjsch->rctx->where) {
    1469:     ondisk = PETSC_TRUE;
    1470:     LoadSingle(tj,ts,stack,tjsch->rctx->check+1);
    1471:     TurnBackward(ts);
    1472:   } else {
    1473:     ondisk = PETSC_FALSE;
    1474:     StackTop(stack,&e);
    1475:     UpdateTS(ts,stack,e);
    1476:   }
    1477:   if (!stack->solution_only) { /* whattodo must be 5 or 8 */
    1478:     /* ask Revolve what to do next */
    1479:     tjsch->rctx->oldcapo = tjsch->rctx->capo;
    1480:     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*/
    1481:     printwhattodo(tj->monitor,whattodo,tjsch->rctx,shift);
    1482:     if (whattodo == 3 || whattodo == 4) tjsch->rctx->reverseonestep = PETSC_TRUE;
    1483:     if (whattodo == 1) tjsch->rctx->stepsleft = tjsch->rctx->capo-tjsch->rctx->oldcapo;
    1484:     if (tj->monitor) {
    1485:       PetscViewerASCIIAddTab(tj->monitor,((PetscObject)tj)->tablevel);
    1486:       PetscViewerASCIIPrintf(tj->monitor,"Skip the step from %D to %D (stage values already checkpointed)\n",tjsch->rctx->oldcapo,tjsch->rctx->oldcapo+1);
    1487:       PetscViewerASCIISubtractTab(tj->monitor,((PetscObject)tj)->tablevel);
    1488:     }
    1489:     if (!tjsch->rctx->reverseonestep && tjsch->rctx->stepsleft > 0) tjsch->rctx->stepsleft--;
    1490:     restart++; /* skip one step */
    1491:   }
    1492:   if (stack->solution_only || (!stack->solution_only && restart < stepnum)) {
    1493:     tjsch->recompute = PETSC_TRUE;
    1494:     TurnForward(ts);
    1495:     ReCompute(ts,tjsch,restart,stepnum);
    1496:   }
    1497:   if (!ondisk && ( (stack->solution_only && e->stepnum+1 == stepnum) || (!stack->solution_only && e->stepnum == stepnum) )) {
    1498:     StackPop(stack,&e);
    1499:     ElementDestroy(stack,e);
    1500:   }
    1501:   tjsch->rctx->reverseonestep = PETSC_FALSE;
    1502:   return(0);
    1503: }
    1504: #endif

    1506: static PetscErrorCode TSTrajectorySet_Memory(TSTrajectory tj,TS ts,PetscInt stepnum,PetscReal time,Vec X)
    1507: {
    1508:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1512:   if (!tjsch->recompute) { /* use global stepnum in the forward sweep */
    1513:     TSGetStepNumber(ts,&stepnum);
    1514:   }
    1515:   /* for consistency */
    1516:   if (!tjsch->recompute && stepnum == 0) ts->ptime_prev = ts->ptime-ts->time_step;
    1517:   switch (tjsch->stype) {
    1518:     case NONE:
    1519:       SetTrajN(ts,tjsch,stepnum,time,X);
    1520:       break;
    1521:     case TWO_LEVEL_NOREVOLVE:
    1522:       SetTrajTLNR(tj,ts,tjsch,stepnum,time,X);
    1523:       break;
    1524: #if defined(PETSC_HAVE_REVOLVE)
    1525:     case TWO_LEVEL_REVOLVE:
    1526:       SetTrajTLR(tj,ts,tjsch,stepnum,time,X);
    1527:       break;
    1528:     case TWO_LEVEL_TWO_REVOLVE:
    1529:       SetTrajTLTR(tj,ts,tjsch,stepnum,time,X);
    1530:       break;
    1531:     case REVOLVE_OFFLINE:
    1532:       SetTrajROF(tj,ts,tjsch,stepnum,time,X);
    1533:       break;
    1534:     case REVOLVE_ONLINE:
    1535:       SetTrajRON(tj,ts,tjsch,stepnum,time,X);
    1536:       break;
    1537:     case REVOLVE_MULTISTAGE:
    1538:       SetTrajRMS(tj,ts,tjsch,stepnum,time,X);
    1539:       break;
    1540: #endif
    1541:     default:
    1542:       break;
    1543:   }
    1544:   return(0);
    1545: }

    1547: static PetscErrorCode TSTrajectoryGet_Memory(TSTrajectory tj,TS ts,PetscInt stepnum,PetscReal *t)
    1548: {
    1549:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1553:   if (stepnum == 0) return(0);
    1554:   switch (tjsch->stype) {
    1555:     case NONE:
    1556:       GetTrajN(ts,tjsch,stepnum);
    1557:       break;
    1558:     case TWO_LEVEL_NOREVOLVE:
    1559:       GetTrajTLNR(tj,ts,tjsch,stepnum);
    1560:       break;
    1561: #if defined(PETSC_HAVE_REVOLVE)
    1562:     case TWO_LEVEL_REVOLVE:
    1563:       GetTrajTLR(tj,ts,tjsch,stepnum);
    1564:       break;
    1565:     case TWO_LEVEL_TWO_REVOLVE:
    1566:       GetTrajTLTR(tj,ts,tjsch,stepnum);
    1567:       break;
    1568:     case REVOLVE_OFFLINE:
    1569:       GetTrajROF(tj,ts,tjsch,stepnum);
    1570:       break;
    1571:     case REVOLVE_ONLINE:
    1572:       GetTrajRON(tj,ts,tjsch,stepnum);
    1573:       break;
    1574:     case REVOLVE_MULTISTAGE:
    1575:       GetTrajRMS(tj,ts,tjsch,stepnum);
    1576:       break;
    1577: #endif
    1578:     default:
    1579:       break;
    1580:   }
    1581:   return(0);
    1582: }

    1584: PETSC_UNUSED static PetscErrorCode TSTrajectorySetStride_Memory(TSTrajectory tj,PetscInt stride)
    1585: {
    1586:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1589:   tjsch->stride = stride;
    1590:   return(0);
    1591: }

    1593: PETSC_UNUSED static PetscErrorCode TSTrajectorySetMaxCpsRAM_Memory(TSTrajectory tj,PetscInt max_cps_ram)
    1594: {
    1595:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1598:   tjsch->max_cps_ram = max_cps_ram;
    1599:   return(0);
    1600: }

    1602: PETSC_UNUSED static PetscErrorCode TSTrajectorySetMaxCpsDisk_Memory(TSTrajectory tj,PetscInt max_cps_disk)
    1603: {
    1604:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1607:   tjsch->max_cps_disk = max_cps_disk;
    1608:   return(0);
    1609: }

    1611: #if defined(PETSC_HAVE_REVOLVE)
    1612: PETSC_UNUSED static PetscErrorCode TSTrajectorySetRevolveOnline(TSTrajectory tj,PetscBool use_online)
    1613: {
    1614:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1617:   tjsch->use_online = use_online;
    1618:   return(0);
    1619: }
    1620: #endif

    1622: PETSC_UNUSED static PetscErrorCode TSTrajectorySetSaveStack(TSTrajectory tj,PetscBool save_stack)
    1623: {
    1624:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1627:   tjsch->save_stack = save_stack;
    1628:   return(0);
    1629: }

    1631: PETSC_UNUSED static PetscErrorCode TSTrajectorySetSolutionOnly(TSTrajectory tj,PetscBool solution_only)
    1632: {
    1633:   TJScheduler *tjsch = (TJScheduler*)tj->data;
    1634:   Stack       *stack = &tjsch->stack;

    1637:   stack->solution_only = solution_only;
    1638:   return(0);
    1639: }

    1641: PETSC_UNUSED static PetscErrorCode TSTrajectorySetUseDRAM(TSTrajectory tj,PetscBool use_dram)
    1642: {
    1643:   TJScheduler *tjsch = (TJScheduler*)tj->data;

    1646:   tjsch->stack.use_dram = use_dram;
    1647:   return(0);
    1648: }

    1650: static PetscErrorCode TSTrajectorySetFromOptions_Memory(PetscOptionItems *PetscOptionsObject,TSTrajectory tj)
    1651: {
    1652:   TJScheduler    *tjsch = (TJScheduler*)tj->data;

    1656:   PetscOptionsHead(PetscOptionsObject,"Memory based TS trajectory options");
    1657:   {
    1658:     PetscOptionsInt("-ts_trajectory_max_cps_ram","Maximum number of checkpoints in RAM","TSTrajectorySetMaxCpsRAM_Memory",tjsch->max_cps_ram,&tjsch->max_cps_ram,NULL);
    1659:     PetscOptionsInt("-ts_trajectory_max_cps_disk","Maximum number of checkpoints on disk","TSTrajectorySetMaxCpsDisk_Memory",tjsch->max_cps_disk,&tjsch->max_cps_disk,NULL);
    1660:     PetscOptionsInt("-ts_trajectory_stride","Stride to save checkpoints to file","TSTrajectorySetStride_Memory",tjsch->stride,&tjsch->stride,NULL);
    1661: #if defined(PETSC_HAVE_REVOLVE)
    1662:     PetscOptionsBool("-ts_trajectory_revolve_online","Trick TS trajectory into using online mode of revolve","TSTrajectorySetRevolveOnline",tjsch->use_online,&tjsch->use_online,NULL);
    1663: #endif
    1664:     PetscOptionsBool("-ts_trajectory_save_stack","Save all stack to disk","TSTrajectorySetSaveStack",tjsch->save_stack,&tjsch->save_stack,NULL);
    1665:     PetscOptionsBool("-ts_trajectory_solution_only","Checkpoint solution only","TSTrajectorySetSolutionOnly",tjsch->stack.solution_only,&tjsch->stack.solution_only,NULL);
    1666:     PetscOptionsBool("-ts_trajectory_use_dram","Use DRAM for checkpointing","TSTrajectorySetUseDRAM",tjsch->stack.use_dram,&tjsch->stack.use_dram,NULL);
    1667:   }
    1668:   PetscOptionsTail();
    1669:   return(0);
    1670: }

    1672: static PetscErrorCode TSTrajectorySetUp_Memory(TSTrajectory tj,TS ts)
    1673: {
    1674:   TJScheduler    *tjsch = (TJScheduler*)tj->data;
    1675:   Stack          *stack = &tjsch->stack;
    1676: #if defined(PETSC_HAVE_REVOLVE)
    1677:   RevolveCTX     *rctx,*rctx2;
    1678:   DiskStack      *diskstack = &tjsch->diskstack;
    1679:   PetscInt       diskblocks;
    1680: #endif
    1681:   PetscInt       numY;
    1682:   PetscBool      flg;

    1686:   PetscStrcmp(((PetscObject)ts->adapt)->type_name,TSADAPTNONE,&flg);
    1687:   if (flg) tjsch->total_steps = PetscMin(ts->max_steps,(PetscInt)(PetscCeilReal((ts->max_time-ts->ptime)/ts->time_step))); /* fixed time step */
    1688:   if (tjsch->max_cps_ram > 0) stack->stacksize = tjsch->max_cps_ram;

    1690:   if (tjsch->stride > 1) { /* two level mode */
    1691:     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.");
    1692:     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 */
    1693:     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 */
    1694:     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 */
    1695:   } else { /* single level mode */
    1696:     if (flg) { /* fixed time step */
    1697:       if (tjsch->max_cps_ram >= tjsch->total_steps-1 || tjsch->max_cps_ram < 1) tjsch->stype = NONE; /* checkpoint all */
    1698:       else tjsch->stype = (tjsch->max_cps_disk>1) ? REVOLVE_MULTISTAGE : REVOLVE_OFFLINE;
    1699:     } else tjsch->stype = NONE; /* checkpoint all for adaptive time step */
    1700: #if defined(PETSC_HAVE_REVOLVE)
    1701:     if (tjsch->use_online) tjsch->stype = REVOLVE_ONLINE; /* trick into online (for testing purpose only) */
    1702: #endif
    1703:   }

    1705:   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
    1706: #ifndef PETSC_HAVE_REVOLVE
    1707:     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.");
    1708: #else
    1709:     switch (tjsch->stype) {
    1710:       case TWO_LEVEL_REVOLVE:
    1711:         revolve_create_offline(tjsch->stride,tjsch->max_cps_ram);
    1712:         break;
    1713:       case TWO_LEVEL_TWO_REVOLVE:
    1714:         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. */
    1715:         diskstack->stacksize = diskblocks;
    1716:         revolve_create_offline(tjsch->stride,tjsch->max_cps_ram);
    1717:         revolve2_create_offline((tjsch->total_steps+tjsch->stride-1)/tjsch->stride,diskblocks);
    1718:         PetscCalloc1(1,&rctx2);
    1719:         rctx2->snaps_in       = diskblocks;
    1720:         rctx2->reverseonestep = PETSC_FALSE;
    1721:         rctx2->check          = 0;
    1722:         rctx2->oldcapo        = 0;
    1723:         rctx2->capo           = 0;
    1724:         rctx2->info           = 2;
    1725:         rctx2->fine           = (tjsch->total_steps+tjsch->stride-1)/tjsch->stride;
    1726:         tjsch->rctx2          = rctx2;
    1727:         diskstack->top        = -1;
    1728:         PetscMalloc1(diskstack->stacksize*sizeof(PetscInt),&diskstack->container);
    1729:         break;
    1730:       case REVOLVE_OFFLINE:
    1731:         revolve_create_offline(tjsch->total_steps,tjsch->max_cps_ram);
    1732:         break;
    1733:       case REVOLVE_ONLINE:
    1734:         stack->stacksize = tjsch->max_cps_ram;
    1735:         revolve_create_online(tjsch->max_cps_ram);
    1736:         break;
    1737:       case REVOLVE_MULTISTAGE:
    1738:         revolve_create_multistage(tjsch->total_steps,tjsch->max_cps_ram+tjsch->max_cps_disk,tjsch->max_cps_ram);
    1739:         break;
    1740:       default:
    1741:         break;
    1742:     }
    1743:     PetscCalloc1(1,&rctx);
    1744:     rctx->snaps_in       = tjsch->max_cps_ram; /* for theta methods snaps_in=2*max_cps_ram */
    1745:     rctx->reverseonestep = PETSC_FALSE;
    1746:     rctx->check          = 0;
    1747:     rctx->oldcapo        = 0;
    1748:     rctx->capo           = 0;
    1749:     rctx->info           = 2;
    1750:     rctx->fine           = (tjsch->stride > 1) ? tjsch->stride : tjsch->total_steps;
    1751:     tjsch->rctx          = rctx;
    1752:     if (tjsch->stype == REVOLVE_ONLINE) rctx->fine = -1;
    1753: #endif
    1754:   } else {
    1755:     if (tjsch->stype == TWO_LEVEL_NOREVOLVE) stack->stacksize = tjsch->stride-1; /* need tjsch->stride-1 at most */
    1756:     if (tjsch->stype == NONE) {
    1757:       if (flg) stack->stacksize = stack->solution_only ? tjsch->total_steps : tjsch->total_steps-1; /* fix time step */
    1758:       else { /* adaptive time step */
    1759:         /* if max_cps_ram is not specified, use maximal allowed number of steps for stack size */
    1760:         if(tjsch->max_cps_ram == -1) stack->stacksize = ts->max_steps < PETSC_MAX_INT ? ts->max_steps : 10000;
    1761:         tjsch->total_steps = stack->solution_only ? stack->stacksize : stack->stacksize+1; /* will be updated as time integration advances */
    1762:       }
    1763:     }
    1764:   }

    1766:   tjsch->recompute = PETSC_FALSE;
    1767:   TSGetStages(ts,&numY,PETSC_IGNORE);
    1768:   StackCreate(stack,stack->stacksize,numY);
    1769:   return(0);
    1770: }

    1772: static PetscErrorCode TSTrajectoryReset_Memory(TSTrajectory tj)
    1773: {
    1774:   TJScheduler    *tjsch = (TJScheduler*)tj->data;

    1778:   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
    1779: #if defined(PETSC_HAVE_REVOLVE)
    1780:     revolve_reset();
    1781:     if (tjsch->stype == TWO_LEVEL_TWO_REVOLVE) {
    1782:       revolve2_reset();
    1783:       PetscFree(tjsch->diskstack.container);
    1784:     }
    1785: #endif
    1786:   }
    1787:   StackDestroy(&tjsch->stack);
    1788: #if defined(PETSC_HAVE_REVOLVE)
    1789:   if (tjsch->stype > TWO_LEVEL_NOREVOLVE) {
    1790:     PetscFree(tjsch->rctx);
    1791:     PetscFree(tjsch->rctx2);
    1792:   }
    1793: #endif
    1794:   return(0);
    1795: }

    1797: static PetscErrorCode TSTrajectoryDestroy_Memory(TSTrajectory tj)
    1798: {
    1799:   TJScheduler    *tjsch = (TJScheduler*)tj->data;

    1803:   PetscFree(tjsch);
    1804:   return(0);
    1805: }

    1807: /*MC
    1808:       TSTRAJECTORYMEMORY - Stores each solution of the ODE/ADE in memory

    1810:   Level: intermediate

    1812: .seealso:  TSTrajectoryCreate(), TS, TSTrajectorySetType()

    1814: M*/
    1815: PETSC_EXTERN PetscErrorCode TSTrajectoryCreate_Memory(TSTrajectory tj,TS ts)
    1816: {
    1817:   TJScheduler    *tjsch;

    1821:   tj->ops->set            = TSTrajectorySet_Memory;
    1822:   tj->ops->get            = TSTrajectoryGet_Memory;
    1823:   tj->ops->setup          = TSTrajectorySetUp_Memory;
    1824:   tj->ops->setfromoptions = TSTrajectorySetFromOptions_Memory;
    1825:   tj->ops->reset          = TSTrajectoryReset_Memory;
    1826:   tj->ops->destroy        = TSTrajectoryDestroy_Memory;

    1828:   PetscCalloc1(1,&tjsch);
    1829:   tjsch->stype        = NONE;
    1830:   tjsch->max_cps_ram  = -1; /* -1 indicates that it is not set */
    1831:   tjsch->max_cps_disk = -1; /* -1 indicates that it is not set */
    1832:   tjsch->stride       = 0; /* if not zero, two-level checkpointing will be used */
    1833: #if defined(PETSC_HAVE_REVOLVE)
    1834:   tjsch->use_online   = PETSC_FALSE;
    1835: #endif
    1836:   tjsch->save_stack   = PETSC_TRUE;

    1838:   tjsch->stack.solution_only = PETSC_TRUE;

    1840:   tj->data = tjsch;
    1841:   return(0);
    1842: }