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

      1:  #include <petsc/private/tsimpl.h>
      2:  #include <petscdraw.h>

      4: PetscLogEvent TS_AdjointStep, TS_ForwardStep;

      6: /* ------------------------ Sensitivity Context ---------------------------*/

      8: /*@C
      9:   TSSetRHSJacobianP - Sets the function that computes the Jacobian of G w.r.t. the parameters p where y_t = G(y,p,t), as well as the location to store the matrix.

     11:   Logically Collective on TS

     13:   Input Parameters:
     14: + ts   - The TS context obtained from TSCreate()
     15: - func - The function

     17:   Calling sequence of func:
     18: $ func (TS ts,PetscReal t,Vec y,Mat A,void *ctx);
     19: +   t - current timestep
     20: .   y - input vector (current ODE solution)
     21: .   A - output matrix
     22: -   ctx - [optional] user-defined function context

     24:   Level: intermediate

     26:   Notes:
     27:     Amat has the same number of rows and the same row parallel layout as u, Amat has the same number of columns and parallel layout as p

     29: .keywords: TS, sensitivity
     30: .seealso:
     31: @*/
     32: PetscErrorCode TSSetRHSJacobianP(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
     33: {

     40:   ts->rhsjacobianp    = func;
     41:   ts->rhsjacobianpctx = ctx;
     42:   if(Amat) {
     43:     PetscObjectReference((PetscObject)Amat);
     44:     MatDestroy(&ts->Jacp);
     45:     ts->Jacp = Amat;
     46:   }
     47:   return(0);
     48: }

     50: /*@C
     51:   TSComputeRHSJacobianP - Runs the user-defined JacobianP function.

     53:   Collective on TS

     55:   Input Parameters:
     56: . ts   - The TS context obtained from TSCreate()

     58:   Level: developer

     60: .keywords: TS, sensitivity
     61: .seealso: TSSetRHSJacobianP()
     62: @*/
     63: PetscErrorCode TSComputeRHSJacobianP(TS ts,PetscReal t,Vec X,Mat Amat)
     64: {

     72:   PetscStackPush("TS user JacobianP function for sensitivity analysis");
     73:   (*ts->rhsjacobianp)(ts,t,X,Amat,ts->rhsjacobianpctx);
     74:   PetscStackPop;
     75:   return(0);
     76: }

     78: /*@C
     79:     TSSetCostIntegrand - Sets the routine for evaluating the integral term in one or more cost functions

     81:     Logically Collective on TS

     83:     Input Parameters:
     84: +   ts - the TS context obtained from TSCreate()
     85: .   numcost - number of gradients to be computed, this is the number of cost functions
     86: .   costintegral - vector that stores the integral values
     87: .   rf - routine for evaluating the integrand function
     88: .   drdyf - function that computes the gradients of the r's with respect to y
     89: .   drdpf - function that computes the gradients of the r's with respect to p, can be NULL if parametric sensitivity is not desired (mu=NULL)
     90: .   fwd - flag indicating whether to evaluate cost integral in the forward run or the adjoint run
     91: -   ctx - [optional] user-defined context for private data for the function evaluation routine (may be NULL)

     93:     Calling sequence of rf:
     94: $   PetscErrorCode rf(TS ts,PetscReal t,Vec y,Vec f,void *ctx);

     96:     Calling sequence of drdyf:
     97: $   PetscErroCode drdyf(TS ts,PetscReal t,Vec y,Vec *drdy,void *ctx);

     99:     Calling sequence of drdpf:
    100: $   PetscErroCode drdpf(TS ts,PetscReal t,Vec y,Vec *drdp,void *ctx);

    102:     Level: intermediate

    104:     Notes:
    105:     For optimization there is usually a single cost function (numcost = 1). For sensitivities there may be multiple cost functions

    107: .keywords: TS, sensitivity analysis, timestep, set, quadrature, function

    109: .seealso: TSSetRHSJacobianP(), TSGetCostGradients(), TSSetCostGradients()
    110: @*/
    111: PetscErrorCode TSSetCostIntegrand(TS ts,PetscInt numcost,Vec costintegral,PetscErrorCode (*rf)(TS,PetscReal,Vec,Vec,void*),
    112:                                                           PetscErrorCode (*drdyf)(TS,PetscReal,Vec,Vec*,void*),
    113:                                                           PetscErrorCode (*drdpf)(TS,PetscReal,Vec,Vec*,void*),
    114:                                                           PetscBool fwd,void *ctx)
    115: {

    121:   if (ts->numcost && ts->numcost!=numcost) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The number of cost functions (2rd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostGradients() or TSForwardSetIntegralGradients()");
    122:   if (!ts->numcost) ts->numcost=numcost;

    124:   if (costintegral) {
    125:     PetscObjectReference((PetscObject)costintegral);
    126:     VecDestroy(&ts->vec_costintegral);
    127:     ts->vec_costintegral = costintegral;
    128:   } else {
    129:     if (!ts->vec_costintegral) { /* Create a seq vec if user does not provide one */
    130:       VecCreateSeq(PETSC_COMM_SELF,numcost,&ts->vec_costintegral);
    131:     } else {
    132:       VecSet(ts->vec_costintegral,0.0);
    133:     }
    134:   }
    135:   if (!ts->vec_costintegrand) {
    136:     VecDuplicate(ts->vec_costintegral,&ts->vec_costintegrand);
    137:   } else {
    138:     VecSet(ts->vec_costintegrand,0.0);
    139:   }
    140:   ts->costintegralfwd  = fwd; /* Evaluate the cost integral in forward run if fwd is true */
    141:   ts->costintegrand    = rf;
    142:   ts->costintegrandctx = ctx;
    143:   ts->drdyfunction     = drdyf;
    144:   ts->drdpfunction     = drdpf;
    145:   return(0);
    146: }

    148: /*@
    149:    TSGetCostIntegral - Returns the values of the integral term in the cost functions.
    150:    It is valid to call the routine after a backward run.

    152:    Not Collective

    154:    Input Parameter:
    155: .  ts - the TS context obtained from TSCreate()

    157:    Output Parameter:
    158: .  v - the vector containing the integrals for each cost function

    160:    Level: intermediate

    162: .seealso: TSSetCostIntegrand()

    164: .keywords: TS, sensitivity analysis
    165: @*/
    166: PetscErrorCode  TSGetCostIntegral(TS ts,Vec *v)
    167: {
    171:   *v = ts->vec_costintegral;
    172:   return(0);
    173: }

    175: /*@
    176:    TSComputeCostIntegrand - Evaluates the integral function in the cost functions.

    178:    Input Parameters:
    179: +  ts - the TS context
    180: .  t - current time
    181: -  y - state vector, i.e. current solution

    183:    Output Parameter:
    184: .  q - vector of size numcost to hold the outputs

    186:    Note:
    187:    Most users should not need to explicitly call this routine, as it
    188:    is used internally within the sensitivity analysis context.

    190:    Level: developer

    192: .keywords: TS, compute

    194: .seealso: TSSetCostIntegrand()
    195: @*/
    196: PetscErrorCode TSComputeCostIntegrand(TS ts,PetscReal t,Vec y,Vec q)
    197: {

    205:   PetscLogEventBegin(TS_FunctionEval,ts,y,q,0);
    206:   if (ts->costintegrand) {
    207:     PetscStackPush("TS user integrand in the cost function");
    208:     (*ts->costintegrand)(ts,t,y,q,ts->costintegrandctx);
    209:     PetscStackPop;
    210:   } else {
    211:     VecZeroEntries(q);
    212:   }

    214:   PetscLogEventEnd(TS_FunctionEval,ts,y,q,0);
    215:   return(0);
    216: }

    218: /*@
    219:   TSComputeDRDYFunction - Runs the user-defined DRDY function.

    221:   Collective on TS

    223:   Input Parameters:
    224: . ts   - The TS context obtained from TSCreate()

    226:   Notes:
    227:   TSAdjointComputeDRDYFunction() is typically used for sensitivity implementation,
    228:   so most users would not generally call this routine themselves.

    230:   Level: developer

    232: .keywords: TS, sensitivity
    233: .seealso: TSSetCostIntegrand()
    234: @*/
    235: PetscErrorCode TSComputeDRDYFunction(TS ts,PetscReal t,Vec y,Vec *drdy)
    236: {

    243:   PetscStackPush("TS user DRDY function for sensitivity analysis");
    244:   (*ts->drdyfunction)(ts,t,y,drdy,ts->costintegrandctx);
    245:   PetscStackPop;
    246:   return(0);
    247: }

    249: /*@
    250:   TSComputeDRDPFunction - Runs the user-defined DRDP function.

    252:   Collective on TS

    254:   Input Parameters:
    255: . ts   - The TS context obtained from TSCreate()

    257:   Notes:
    258:   TSDRDPFunction() is typically used for sensitivity implementation,
    259:   so most users would not generally call this routine themselves.

    261:   Level: developer

    263: .keywords: TS, sensitivity
    264: .seealso: TSSetCostIntegrand()
    265: @*/
    266: PetscErrorCode TSComputeDRDPFunction(TS ts,PetscReal t,Vec y,Vec *drdp)
    267: {

    274:   PetscStackPush("TS user DRDP function for sensitivity analysis");
    275:   (*ts->drdpfunction)(ts,t,y,drdp,ts->costintegrandctx);
    276:   PetscStackPop;
    277:   return(0);
    278: }

    280: /* --------------------------- Adjoint sensitivity ---------------------------*/

    282: /*@
    283:    TSSetCostGradients - Sets the initial value of the gradients of the cost function w.r.t. initial values and w.r.t. the problem parameters
    284:       for use by the TSAdjoint routines.

    286:    Logically Collective on TS and Vec

    288:    Input Parameters:
    289: +  ts - the TS context obtained from TSCreate()
    290: .  lambda - gradients with respect to the initial condition variables, the dimension and parallel layout of these vectors is the same as the ODE solution vector
    291: -  mu - gradients with respect to the parameters, the number of entries in these vectors is the same as the number of parameters

    293:    Level: beginner

    295:    Notes:
    296:     the entries in these vectors must be correctly initialized with the values lamda_i = df/dy|finaltime  mu_i = df/dp|finaltime

    298:    After TSAdjointSolve() is called the lamba and the mu contain the computed sensitivities

    300: .keywords: TS, timestep, set, sensitivity, initial values
    301: @*/
    302: PetscErrorCode TSSetCostGradients(TS ts,PetscInt numcost,Vec *lambda,Vec *mu)
    303: {
    307:   ts->vecs_sensi  = lambda;
    308:   ts->vecs_sensip = mu;
    309:   if (ts->numcost && ts->numcost!=numcost) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The number of cost functions (2rd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand");
    310:   ts->numcost  = numcost;
    311:   return(0);
    312: }

    314: /*@
    315:    TSGetCostGradients - Returns the gradients from the TSAdjointSolve()

    317:    Not Collective, but Vec returned is parallel if TS is parallel

    319:    Input Parameter:
    320: .  ts - the TS context obtained from TSCreate()

    322:    Output Parameter:
    323: +  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
    324: -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters

    326:    Level: intermediate

    328: .seealso: TSGetTimeStep()

    330: .keywords: TS, timestep, get, sensitivity
    331: @*/
    332: PetscErrorCode TSGetCostGradients(TS ts,PetscInt *numcost,Vec **lambda,Vec **mu)
    333: {
    336:   if (numcost) *numcost = ts->numcost;
    337:   if (lambda)  *lambda  = ts->vecs_sensi;
    338:   if (mu)      *mu      = ts->vecs_sensip;
    339:   return(0);
    340: }

    342: /*@
    343:    TSAdjointSetUp - Sets up the internal data structures for the later use
    344:    of an adjoint solver

    346:    Collective on TS

    348:    Input Parameter:
    349: .  ts - the TS context obtained from TSCreate()

    351:    Level: advanced

    353: .keywords: TS, timestep, setup

    355: .seealso: TSCreate(), TSAdjointStep(), TSSetCostGradients()
    356: @*/
    357: PetscErrorCode TSAdjointSetUp(TS ts)
    358: {

    363:   if (ts->adjointsetupcalled) return(0);
    364:   if (!ts->vecs_sensi) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSSetCostGradients() first");
    365:   if (ts->vecs_sensip && !ts->Jacp) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_WRONGSTATE,"Must call TSAdjointSetRHSJacobian() first");

    367:   if (ts->vec_costintegral) { /* if there is integral in the cost function */
    368:     VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&ts->vecs_drdy);
    369:     if (ts->vecs_sensip){
    370:       VecDuplicateVecs(ts->vecs_sensip[0],ts->numcost,&ts->vecs_drdp);
    371:     }
    372:   }

    374:   if (ts->ops->adjointsetup) {
    375:     (*ts->ops->adjointsetup)(ts);
    376:   }
    377:   ts->adjointsetupcalled = PETSC_TRUE;
    378:   return(0);
    379: }

    381: /*@
    382:    TSAdjointSetSteps - Sets the number of steps the adjoint solver should take backward in time

    384:    Logically Collective on TS

    386:    Input Parameters:
    387: +  ts - the TS context obtained from TSCreate()
    388: .  steps - number of steps to use

    390:    Level: intermediate

    392:    Notes:
    393:     Normally one does not call this and TSAdjointSolve() integrates back to the original timestep. One can call this
    394:           so as to integrate back to less than the original timestep

    396: .keywords: TS, timestep, set, maximum, iterations

    398: .seealso: TSSetExactFinalTime()
    399: @*/
    400: PetscErrorCode  TSAdjointSetSteps(TS ts,PetscInt steps)
    401: {
    405:   if (steps < 0) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back a negative number of steps");
    406:   if (steps > ts->steps) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Cannot step back more than the total number of forward steps");
    407:   ts->adjoint_max_steps = steps;
    408:   return(0);
    409: }

    411: /*@C
    412:   TSAdjointSetRHSJacobian - Deprecated, use TSSetRHSJacobianP()

    414:   Level: deprecated

    416: @*/
    417: PetscErrorCode TSAdjointSetRHSJacobian(TS ts,Mat Amat,PetscErrorCode (*func)(TS,PetscReal,Vec,Mat,void*),void *ctx)
    418: {

    425:   ts->rhsjacobianp    = func;
    426:   ts->rhsjacobianpctx = ctx;
    427:   if(Amat) {
    428:     PetscObjectReference((PetscObject)Amat);
    429:     MatDestroy(&ts->Jacp);
    430:     ts->Jacp = Amat;
    431:   }
    432:   return(0);
    433: }

    435: /*@C
    436:   TSAdjointComputeRHSJacobian - Deprecated, use TSComputeRHSJacobianP()

    438:   Level: deprecated

    440: @*/
    441: PetscErrorCode TSAdjointComputeRHSJacobian(TS ts,PetscReal t,Vec X,Mat Amat)
    442: {

    450:   PetscStackPush("TS user JacobianP function for sensitivity analysis");
    451:   (*ts->rhsjacobianp)(ts,t,X,Amat,ts->rhsjacobianpctx);
    452:   PetscStackPop;
    453:   return(0);
    454: }

    456: /*@
    457:   TSAdjointComputeDRDYFunction - Deprecated, use TSComputeDRDYFunction()

    459:   Level: deprecated

    461: @*/
    462: PetscErrorCode TSAdjointComputeDRDYFunction(TS ts,PetscReal t,Vec y,Vec *drdy)
    463: {

    470:   PetscStackPush("TS user DRDY function for sensitivity analysis");
    471:   (*ts->drdyfunction)(ts,t,y,drdy,ts->costintegrandctx);
    472:   PetscStackPop;
    473:   return(0);
    474: }

    476: /*@
    477:   TSAdjointComputeDRDPFunction - Deprecated, use TSComputeDRDPFunction()

    479:   Level: deprecated

    481: @*/
    482: PetscErrorCode TSAdjointComputeDRDPFunction(TS ts,PetscReal t,Vec y,Vec *drdp)
    483: {

    490:   PetscStackPush("TS user DRDP function for sensitivity analysis");
    491:   (*ts->drdpfunction)(ts,t,y,drdp,ts->costintegrandctx);
    492:   PetscStackPop;
    493:   return(0);
    494: }

    496: /*@C
    497:    TSAdjointMonitorSensi - monitors the first lambda sensitivity

    499:    Level: intermediate

    501: .keywords: TS, set, monitor

    503: .seealso: TSAdjointMonitorSet()
    504: @*/
    505: PetscErrorCode TSAdjointMonitorSensi(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
    506: {
    508:   PetscViewer    viewer = vf->viewer;

    512:   PetscViewerPushFormat(viewer,vf->format);
    513:   VecView(lambda[0],viewer);
    514:   PetscViewerPopFormat(viewer);
    515:   return(0);
    516: }

    518: /*@C
    519:    TSAdjointMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

    521:    Collective on TS

    523:    Input Parameters:
    524: +  ts - TS object you wish to monitor
    525: .  name - the monitor type one is seeking
    526: .  help - message indicating what monitoring is done
    527: .  manual - manual page for the monitor
    528: .  monitor - the monitor function
    529: -  monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the TS or PetscViewer objects

    531:    Level: developer

    533: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
    534:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
    535:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
    536:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
    537:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
    538:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
    539:           PetscOptionsFList(), PetscOptionsEList()
    540: @*/
    541: PetscErrorCode TSAdjointMonitorSetFromOptions(TS ts,const char name[],const char help[], const char manual[],PetscErrorCode (*monitor)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,PetscViewerAndFormat*),PetscErrorCode (*monitorsetup)(TS,PetscViewerAndFormat*))
    542: {
    543:   PetscErrorCode    ierr;
    544:   PetscViewer       viewer;
    545:   PetscViewerFormat format;
    546:   PetscBool         flg;

    549:   PetscOptionsGetViewer(PetscObjectComm((PetscObject)ts),((PetscObject)ts)->prefix,name,&viewer,&format,&flg);
    550:   if (flg) {
    551:     PetscViewerAndFormat *vf;
    552:     PetscViewerAndFormatCreate(viewer,format,&vf);
    553:     PetscObjectDereference((PetscObject)viewer);
    554:     if (monitorsetup) {
    555:       (*monitorsetup)(ts,vf);
    556:     }
    557:     TSAdjointMonitorSet(ts,(PetscErrorCode (*)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*))monitor,vf,(PetscErrorCode (*)(void**))PetscViewerAndFormatDestroy);
    558:   }
    559:   return(0);
    560: }

    562: /*@C
    563:    TSAdjointMonitorSet - Sets an ADDITIONAL function that is to be used at every
    564:    timestep to display the iteration's  progress.

    566:    Logically Collective on TS

    568:    Input Parameters:
    569: +  ts - the TS context obtained from TSCreate()
    570: .  adjointmonitor - monitoring routine
    571: .  adjointmctx - [optional] user-defined context for private data for the
    572:              monitor routine (use NULL if no context is desired)
    573: -  adjointmonitordestroy - [optional] routine that frees monitor context
    574:           (may be NULL)

    576:    Calling sequence of monitor:
    577: $    int adjointmonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec *lambda, Vec *mu,void *adjointmctx)

    579: +    ts - the TS context
    580: .    steps - iteration number (after the final time step the monitor routine is called with a step of -1, this is at the final time which may have
    581:                                been interpolated to)
    582: .    time - current time
    583: .    u - current iterate
    584: .    numcost - number of cost functionos
    585: .    lambda - sensitivities to initial conditions
    586: .    mu - sensitivities to parameters
    587: -    adjointmctx - [optional] adjoint monitoring context

    589:    Notes:
    590:    This routine adds an additional monitor to the list of monitors that
    591:    already has been loaded.

    593:    Fortran Notes:
    594:     Only a single monitor function can be set for each TS object

    596:    Level: intermediate

    598: .keywords: TS, timestep, set, adjoint, monitor

    600: .seealso: TSAdjointMonitorCancel()
    601: @*/
    602: PetscErrorCode TSAdjointMonitorSet(TS ts,PetscErrorCode (*adjointmonitor)(TS,PetscInt,PetscReal,Vec,PetscInt,Vec*,Vec*,void*),void *adjointmctx,PetscErrorCode (*adjointmdestroy)(void**))
    603: {
    605:   PetscInt       i;
    606:   PetscBool      identical;

    610:   for (i=0; i<ts->numbermonitors;i++) {
    611:     PetscMonitorCompare((PetscErrorCode (*)(void))adjointmonitor,adjointmctx,adjointmdestroy,(PetscErrorCode (*)(void))ts->adjointmonitor[i],ts->adjointmonitorcontext[i],ts->adjointmonitordestroy[i],&identical);
    612:     if (identical) return(0);
    613:   }
    614:   if (ts->numberadjointmonitors >= MAXTSMONITORS) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many adjoint monitors set");
    615:   ts->adjointmonitor[ts->numberadjointmonitors]          = adjointmonitor;
    616:   ts->adjointmonitordestroy[ts->numberadjointmonitors]   = adjointmdestroy;
    617:   ts->adjointmonitorcontext[ts->numberadjointmonitors++] = (void*)adjointmctx;
    618:   return(0);
    619: }

    621: /*@C
    622:    TSAdjointMonitorCancel - Clears all the adjoint monitors that have been set on a time-step object.

    624:    Logically Collective on TS

    626:    Input Parameters:
    627: .  ts - the TS context obtained from TSCreate()

    629:    Notes:
    630:    There is no way to remove a single, specific monitor.

    632:    Level: intermediate

    634: .keywords: TS, timestep, set, adjoint, monitor

    636: .seealso: TSAdjointMonitorSet()
    637: @*/
    638: PetscErrorCode TSAdjointMonitorCancel(TS ts)
    639: {
    641:   PetscInt       i;

    645:   for (i=0; i<ts->numberadjointmonitors; i++) {
    646:     if (ts->adjointmonitordestroy[i]) {
    647:       (*ts->adjointmonitordestroy[i])(&ts->adjointmonitorcontext[i]);
    648:     }
    649:   }
    650:   ts->numberadjointmonitors = 0;
    651:   return(0);
    652: }

    654: /*@C
    655:    TSAdjointMonitorDefault - the default monitor of adjoint computations

    657:    Level: intermediate

    659: .keywords: TS, set, monitor

    661: .seealso: TSAdjointMonitorSet()
    662: @*/
    663: PetscErrorCode TSAdjointMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,PetscInt numcost,Vec *lambda,Vec *mu,PetscViewerAndFormat *vf)
    664: {
    666:   PetscViewer    viewer = vf->viewer;

    670:   PetscViewerPushFormat(viewer,vf->format);
    671:   PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);
    672:   PetscViewerASCIIPrintf(viewer,"%D TS dt %g time %g%s",step,(double)ts->time_step,(double)ptime,ts->steprollback ? " (r)\n" : "\n");
    673:   PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);
    674:   PetscViewerPopFormat(viewer);
    675:   return(0);
    676: }

    678: /*@C
    679:    TSAdjointMonitorDrawSensi - Monitors progress of the adjoint TS solvers by calling
    680:    VecView() for the sensitivities to initial states at each timestep

    682:    Collective on TS

    684:    Input Parameters:
    685: +  ts - the TS context
    686: .  step - current time-step
    687: .  ptime - current time
    688: .  u - current state
    689: .  numcost - number of cost functions
    690: .  lambda - sensitivities to initial conditions
    691: .  mu - sensitivities to parameters
    692: -  dummy - either a viewer or NULL

    694:    Level: intermediate

    696: .keywords: TS,  vector, adjoint, monitor, view

    698: .seealso: TSAdjointMonitorSet(), TSAdjointMonitorDefault(), VecView()
    699: @*/
    700: PetscErrorCode TSAdjointMonitorDrawSensi(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda,Vec *mu,void *dummy)
    701: {
    702:   PetscErrorCode   ierr;
    703:   TSMonitorDrawCtx ictx = (TSMonitorDrawCtx)dummy;
    704:   PetscDraw        draw;
    705:   PetscReal        xl,yl,xr,yr,h;
    706:   char             time[32];

    709:   if (!(((ictx->howoften > 0) && (!(step % ictx->howoften))) || ((ictx->howoften == -1) && ts->reason))) return(0);

    711:   VecView(lambda[0],ictx->viewer);
    712:   PetscViewerDrawGetDraw(ictx->viewer,0,&draw);
    713:   PetscSNPrintf(time,32,"Timestep %d Time %g",(int)step,(double)ptime);
    714:   PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr);
    715:   h    = yl + .95*(yr - yl);
    716:   PetscDrawStringCentered(draw,.5*(xl+xr),h,PETSC_DRAW_BLACK,time);
    717:   PetscDrawFlush(draw);
    718:   return(0);
    719: }

    721: /*
    722:    TSAdjointSetFromOptions - Sets various TSAdjoint parameters from user options.

    724:    Collective on TSAdjoint

    726:    Input Parameter:
    727: .  ts - the TS context

    729:    Options Database Keys:
    730: +  -ts_adjoint_solve <yes,no> After solving the ODE/DAE solve the adjoint problem (requires -ts_save_trajectory)
    731: .  -ts_adjoint_monitor - print information at each adjoint time step
    732: -  -ts_adjoint_monitor_draw_sensi - monitor the sensitivity of the first cost function wrt initial conditions (lambda[0]) graphically

    734:    Level: developer

    736:    Notes:
    737:     This is not normally called directly by users

    739: .keywords: TS, trajectory, timestep, set, options, database

    741: .seealso: TSSetSaveTrajectory(), TSTrajectorySetUp()
    742: */
    743: PetscErrorCode TSAdjointSetFromOptions(PetscOptionItems *PetscOptionsObject,TS ts)
    744: {
    745:   PetscBool      tflg,opt;

    750:   PetscOptionsHead(PetscOptionsObject,"TS Adjoint options");
    751:   tflg = ts->adjoint_solve ? PETSC_TRUE : PETSC_FALSE;
    752:   PetscOptionsBool("-ts_adjoint_solve","Solve the adjoint problem immediately after solving the forward problem","",tflg,&tflg,&opt);
    753:   if (opt) {
    754:     TSSetSaveTrajectory(ts);
    755:     ts->adjoint_solve = tflg;
    756:   }
    757:   TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor","Monitor adjoint timestep size","TSAdjointMonitorDefault",TSAdjointMonitorDefault,NULL);
    758:   TSAdjointMonitorSetFromOptions(ts,"-ts_adjoint_monitor_sensi","Monitor sensitivity in the adjoint computation","TSAdjointMonitorSensi",TSAdjointMonitorSensi,NULL);
    759:   opt  = PETSC_FALSE;
    760:   PetscOptionsName("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",&opt);
    761:   if (opt) {
    762:     TSMonitorDrawCtx ctx;
    763:     PetscInt         howoften = 1;

    765:     PetscOptionsInt("-ts_adjoint_monitor_draw_sensi","Monitor adjoint sensitivities (lambda only) graphically","TSAdjointMonitorDrawSensi",howoften,&howoften,NULL);
    766:     TSMonitorDrawCtxCreate(PetscObjectComm((PetscObject)ts),0,0,PETSC_DECIDE,PETSC_DECIDE,300,300,howoften,&ctx);
    767:     TSAdjointMonitorSet(ts,TSAdjointMonitorDrawSensi,ctx,(PetscErrorCode (*)(void**))TSMonitorDrawCtxDestroy);
    768:   }
    769:   return(0);
    770: }

    772: /*@
    773:    TSAdjointStep - Steps one time step backward in the adjoint run

    775:    Collective on TS

    777:    Input Parameter:
    778: .  ts - the TS context obtained from TSCreate()

    780:    Level: intermediate

    782: .keywords: TS, adjoint, step

    784: .seealso: TSAdjointSetUp(), TSAdjointSolve()
    785: @*/
    786: PetscErrorCode TSAdjointStep(TS ts)
    787: {
    788:   DM               dm;
    789:   PetscErrorCode   ierr;

    793:   TSGetDM(ts,&dm);
    794:   TSAdjointSetUp(ts);

    796:   VecViewFromOptions(ts->vec_sol,(PetscObject)ts,"-ts_view_solution");

    798:   ts->reason = TS_CONVERGED_ITERATING;
    799:   ts->ptime_prev = ts->ptime;
    800:   if (!ts->ops->adjointstep) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSStep has failed because the adjoint of  %s has not been implemented, try other time stepping methods for adjoint sensitivity analysis",((PetscObject)ts)->type_name);
    801:   PetscLogEventBegin(TS_AdjointStep,ts,0,0,0);
    802:   (*ts->ops->adjointstep)(ts);
    803:   PetscLogEventEnd(TS_AdjointStep,ts,0,0,0);
    804:   ts->adjoint_steps++; ts->steps--;

    806:   if (ts->reason < 0) {
    807:     if (ts->errorifstepfailed) {
    808:       if (ts->reason == TS_DIVERGED_NONLINEAR_SOLVE) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSStep has failed due to %s, increase -ts_max_snes_failures or make negative to attempt recovery",TSConvergedReasons[ts->reason]);
    809:       else if (ts->reason == TS_DIVERGED_STEP_REJECTED) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSStep has failed due to %s, increase -ts_max_reject or make negative to attempt recovery",TSConvergedReasons[ts->reason]);
    810:       else SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_NOT_CONVERGED,"TSStep has failed due to %s",TSConvergedReasons[ts->reason]);
    811:     }
    812:   } else if (!ts->reason) {
    813:     if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;
    814:   }
    815:   return(0);
    816: }

    818: /*@
    819:    TSAdjointSolve - Solves the discrete ajoint problem for an ODE/DAE

    821:    Collective on TS

    823:    Input Parameter:
    824: .  ts - the TS context obtained from TSCreate()

    826:    Options Database:
    827: . -ts_adjoint_view_solution <viewerinfo> - views the first gradient with respect to the initial values

    829:    Level: intermediate

    831:    Notes:
    832:    This must be called after a call to TSSolve() that solves the forward problem

    834:    By default this will integrate back to the initial time, one can use TSAdjointSetSteps() to step back to a later time

    836: .keywords: TS, timestep, solve

    838: .seealso: TSCreate(), TSSetCostGradients(), TSSetSolution(), TSAdjointStep()
    839: @*/
    840: PetscErrorCode TSAdjointSolve(TS ts)
    841: {
    842:   PetscErrorCode    ierr;

    846:   TSAdjointSetUp(ts);

    848:   /* reset time step and iteration counters */
    849:   ts->adjoint_steps     = 0;
    850:   ts->ksp_its           = 0;
    851:   ts->snes_its          = 0;
    852:   ts->num_snes_failures = 0;
    853:   ts->reject            = 0;
    854:   ts->reason            = TS_CONVERGED_ITERATING;

    856:   if (!ts->adjoint_max_steps) ts->adjoint_max_steps = ts->steps;
    857:   if (ts->adjoint_steps >= ts->adjoint_max_steps) ts->reason = TS_CONVERGED_ITS;

    859:   while (!ts->reason) {
    860:     TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);
    861:     TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);
    862:     TSAdjointEventHandler(ts);
    863:     TSAdjointStep(ts);
    864:     if (ts->vec_costintegral && !ts->costintegralfwd) {
    865:       TSAdjointCostIntegral(ts);
    866:     }
    867:   }
    868:   TSTrajectoryGet(ts->trajectory,ts,ts->steps,&ts->ptime);
    869:   TSAdjointMonitor(ts,ts->steps,ts->ptime,ts->vec_sol,ts->numcost,ts->vecs_sensi,ts->vecs_sensip);
    870:   ts->solvetime = ts->ptime;
    871:   TSTrajectoryViewFromOptions(ts->trajectory,NULL,"-ts_trajectory_view");
    872:   VecViewFromOptions(ts->vecs_sensi[0],(PetscObject) ts, "-ts_adjoint_view_solution");
    873:   ts->adjoint_max_steps = 0;
    874:   return(0);
    875: }

    877: /*@C
    878:    TSAdjointMonitor - Runs all user-provided adjoint monitor routines set using TSAdjointMonitorSet()

    880:    Collective on TS

    882:    Input Parameters:
    883: +  ts - time stepping context obtained from TSCreate()
    884: .  step - step number that has just completed
    885: .  ptime - model time of the state
    886: .  u - state at the current model time
    887: .  numcost - number of cost functions (dimension of lambda  or mu)
    888: .  lambda - vectors containing the gradients of the cost functions with respect to the ODE/DAE solution variables
    889: -  mu - vectors containing the gradients of the cost functions with respect to the problem parameters

    891:    Notes:
    892:    TSAdjointMonitor() is typically used automatically within the time stepping implementations.
    893:    Users would almost never call this routine directly.

    895:    Level: developer

    897: .keywords: TS, timestep
    898: @*/
    899: PetscErrorCode TSAdjointMonitor(TS ts,PetscInt step,PetscReal ptime,Vec u,PetscInt numcost,Vec *lambda, Vec *mu)
    900: {
    902:   PetscInt       i,n = ts->numberadjointmonitors;

    907:   VecLockPush(u);
    908:   for (i=0; i<n; i++) {
    909:     (*ts->adjointmonitor[i])(ts,step,ptime,u,numcost,lambda,mu,ts->adjointmonitorcontext[i]);
    910:   }
    911:   VecLockPop(u);
    912:   return(0);
    913: }

    915: /*@
    916:  TSAdjointCostIntegral - Evaluate the cost integral in the adjoint run.

    918:  Collective on TS

    920:  Input Arguments:
    921:  .  ts - time stepping context

    923:  Level: advanced

    925:  Notes:
    926:  This function cannot be called until TSAdjointStep() has been completed.

    928:  .seealso: TSAdjointSolve(), TSAdjointStep
    929:  @*/
    930: PetscErrorCode TSAdjointCostIntegral(TS ts)
    931: {
    934:     if (!ts->ops->adjointintegral) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide integral evaluation in the adjoint run",((PetscObject)ts)->type_name);
    935:     (*ts->ops->adjointintegral)(ts);
    936:     return(0);
    937: }

    939: /* ------------------ Forward (tangent linear) sensitivity  ------------------*/

    941: /*@
    942:   TSForwardSetUp - Sets up the internal data structures for the later use
    943:   of forward sensitivity analysis

    945:   Collective on TS

    947:   Input Parameter:
    948: . ts - the TS context obtained from TSCreate()

    950:   Level: advanced

    952: .keywords: TS, forward sensitivity, setup

    954: .seealso: TSCreate(), TSDestroy(), TSSetUp()
    955: @*/
    956: PetscErrorCode TSForwardSetUp(TS ts)
    957: {

    962:   if (ts->forwardsetupcalled) return(0);
    963:   if (ts->vec_costintegral && !ts->vecs_integral_sensip ) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call TSForwardSetIntegralGradients() before TSSetCostIntegrand()");
    964:   if (ts->vecs_integral_sensip) {
    965:     VecDuplicateVecs(ts->vec_sol,ts->numcost,&ts->vecs_drdy);
    966:     VecDuplicateVecs(ts->vecs_integral_sensip[0],ts->numcost,&ts->vecs_drdp);
    967:   }

    969:   if (ts->ops->forwardsetup) {
    970:     (*ts->ops->forwardsetup)(ts);
    971:   }
    972:   ts->forwardsetupcalled = PETSC_TRUE;
    973:   return(0);
    974: }

    976: /*@
    977:   TSForwardSetIntegralGradients - Set the vectors holding forward sensitivities of the integral term.

    979:   Input Parameter:
    980: . ts- the TS context obtained from TSCreate()
    981: . numfwdint- number of integrals
    982: . vp = the vectors containing the gradients for each integral w.r.t. parameters

    984:   Level: intermediate

    986: .keywords: TS, forward sensitivity

    988: .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
    989: @*/
    990: PetscErrorCode TSForwardSetIntegralGradients(TS ts,PetscInt numfwdint,Vec *vp)
    991: {
    994:   if (ts->numcost && ts->numcost!=numfwdint) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"The number of cost functions (2rd parameter of TSSetCostIntegrand()) is inconsistent with the one set by TSSetCostIntegrand()");
    995:   if (!ts->numcost) ts->numcost = numfwdint;

    997:   ts->vecs_integral_sensip = vp;
    998:   return(0);
    999: }

    1001: /*@
    1002:   TSForwardGetIntegralGradients - Returns the forward sensitivities ofthe integral term.

    1004:   Input Parameter:
    1005: . ts- the TS context obtained from TSCreate()

    1007:   Output Parameter:
    1008: . vp = the vectors containing the gradients for each integral w.r.t. parameters

    1010:   Level: intermediate

    1012: .keywords: TS, forward sensitivity

    1014: .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
    1015: @*/
    1016: PetscErrorCode TSForwardGetIntegralGradients(TS ts,PetscInt *numfwdint,Vec **vp)
    1017: {
    1021:   if (numfwdint) *numfwdint = ts->numcost;
    1022:   if (vp) *vp = ts->vecs_integral_sensip;
    1023:   return(0);
    1024: }

    1026: /*@
    1027:   TSForwardStep - Compute the forward sensitivity for one time step.

    1029:   Collective on TS

    1031:   Input Arguments:
    1032: . ts - time stepping context

    1034:   Level: advanced

    1036:   Notes:
    1037:   This function cannot be called until TSStep() has been completed.

    1039: .keywords: TS, forward sensitivity

    1041: .seealso: TSForwardSetSensitivities(), TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardSetUp()
    1042: @*/
    1043: PetscErrorCode TSForwardStep(TS ts)
    1044: {
    1047:   if (!ts->ops->forwardstep) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide forward sensitivity analysis",((PetscObject)ts)->type_name);
    1048:   PetscLogEventBegin(TS_ForwardStep,ts,0,0,0);
    1049:   (*ts->ops->forwardstep)(ts);
    1050:   PetscLogEventEnd(TS_ForwardStep,ts,0,0,0);
    1051:   return(0);
    1052: }

    1054: /*@
    1055:   TSForwardSetSensitivities - Sets the initial value of the trajectory sensitivities of solution  w.r.t. the problem parameters and initial values.

    1057:   Logically Collective on TS and Vec

    1059:   Input Parameters:
    1060: + ts - the TS context obtained from TSCreate()
    1061: . nump - number of parameters
    1062: - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters

    1064:   Level: beginner

    1066:   Notes:
    1067:   Forward sensitivity is also called 'trajectory sensitivity' in some fields such as power systems.
    1068:   This function turns on a flag to trigger TSSolve() to compute forward sensitivities automatically.
    1069:   You must call this function before TSSolve().
    1070:   The entries in the sensitivity matrix must be correctly initialized with the values S = dy/dp|startingtime.

    1072: .keywords: TS, timestep, set, forward sensitivity, initial values

    1074: .seealso: TSForwardGetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
    1075: @*/
    1076: PetscErrorCode TSForwardSetSensitivities(TS ts,PetscInt nump,Mat Smat)
    1077: {

    1083:   ts->forward_solve  = PETSC_TRUE;
    1084:   ts->num_parameters = nump;
    1085:   PetscObjectReference((PetscObject)Smat);
    1086:   MatDestroy(&ts->mat_sensip);
    1087:   ts->mat_sensip = Smat;
    1088:   return(0);
    1089: }

    1091: /*@
    1092:   TSForwardGetSensitivities - Returns the trajectory sensitivities

    1094:   Not Collective, but Vec returned is parallel if TS is parallel

    1096:   Output Parameter:
    1097: + ts - the TS context obtained from TSCreate()
    1098: . nump - number of parameters
    1099: - Smat - sensitivities with respect to the parameters, the number of entries in these vectors is the same as the number of parameters

    1101:   Level: intermediate

    1103: .keywords: TS, forward sensitivity

    1105: .seealso: TSForwardSetSensitivities(), TSForwardSetIntegralGradients(), TSForwardGetIntegralGradients(), TSForwardStep()
    1106: @*/
    1107: PetscErrorCode TSForwardGetSensitivities(TS ts,PetscInt *nump,Mat *Smat)
    1108: {
    1111:   if (nump) *nump = ts->num_parameters;
    1112:   if (Smat) *Smat = ts->mat_sensip;
    1113:   return(0);
    1114: }

    1116: /*@
    1117:    TSForwardCostIntegral - Evaluate the cost integral in the forward run.

    1119:    Collective on TS

    1121:    Input Arguments:
    1122: .  ts - time stepping context

    1124:    Level: advanced

    1126:    Notes:
    1127:    This function cannot be called until TSStep() has been completed.

    1129: .seealso: TSSolve(), TSAdjointCostIntegral()
    1130: @*/
    1131: PetscErrorCode TSForwardCostIntegral(TS ts)
    1132: {
    1135:   if (!ts->ops->forwardintegral) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"%s does not provide integral evaluation in the forward run",((PetscObject)ts)->type_name);
    1136:   (*ts->ops->forwardintegral)(ts);
    1137:   return(0);
    1138: }