Date: 2022-03-04T17:39:38+00:00

Actual source code: ex20opt_p.c

      2: static char help[] = "Solves the van der Pol equation.\n\
      3: Input parameters include:\n";

      5: /*
      6:    Concepts: TS^time-dependent nonlinear problems
      7:    Concepts: TS^van der Pol equation DAE equivalent
      8:    Concepts: TS^Optimization using adjoint sensitivity analysis
      9:    Processors: 1
     10: */
     11: /* ------------------------------------------------------------------------

     13:   Notes:
     14:   This code demonstrates how to solve a DAE-constrained optimization problem with TAO, TSAdjoint and TS.
     15:   The nonlinear problem is written in a DAE equivalent form.
     16:   The objective is to minimize the difference between observation and model prediction by finding an optimal value for parameter \mu.
     17:   The gradient is computed with the discrete adjoint of an implicit theta method, see ex20adj.c for details.
     18:   ------------------------------------------------------------------------- */
     19: #include <petsctao.h>
     20: #include <petscts.h>

     22: typedef struct _n_User *User;
     23: struct _n_User {
     24:   TS        ts;
     25:   PetscReal mu;
     26:   PetscReal next_output;

     28:   /* Sensitivity analysis support */
     29:   PetscReal ftime;
     30:   Mat       A;                       /* Jacobian matrix */
     31:   Mat       Jacp;                    /* JacobianP matrix */
     32:   Mat       H;                       /* Hessian matrix for optimization */
     33:   Vec       U,Lambda[1],Mup[1];      /* adjoint variables */
     34:   Vec       Lambda2[1],Mup2[1];      /* second-order adjoint variables */
     35:   Vec       Ihp1[1];                 /* working space for Hessian evaluations */
     36:   Vec       Ihp2[1];                 /* working space for Hessian evaluations */
     37:   Vec       Ihp3[1];                 /* working space for Hessian evaluations */
     38:   Vec       Ihp4[1];                 /* working space for Hessian evaluations */
     39:   Vec       Dir;                     /* direction vector */
     40:   PetscReal ob[2];                   /* observation used by the cost function */
     41:   PetscBool implicitform;            /* implicit ODE? */
     42: };

     44: PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*);
     45: PetscErrorCode FormHessian(Tao,Vec,Mat,Mat,void*);
     46: PetscErrorCode Adjoint2(Vec,PetscScalar[],User);

     48: /* ----------------------- Explicit form of the ODE  -------------------- */

     50: static PetscErrorCode RHSFunction(TS ts,PetscReal t,Vec U,Vec F,void *ctx)
     51: {
     52:   PetscErrorCode    ierr;
     53:   User              user = (User)ctx;
     54:   PetscScalar       *f;
     55:   const PetscScalar *u;

     58:   VecGetArrayRead(U,&u);
     59:   VecGetArray(F,&f);
     60:   f[0] = u[1];
     61:   f[1] = user->mu*((1.-u[0]*u[0])*u[1]-u[0]);
     62:   VecRestoreArrayRead(U,&u);
     63:   VecRestoreArray(F,&f);
     64:   return(0);
     65: }

     67: static PetscErrorCode RHSJacobian(TS ts,PetscReal t,Vec U,Mat A,Mat B,void *ctx)
     68: {
     69:   PetscErrorCode    ierr;
     70:   User              user = (User)ctx;
     71:   PetscReal         mu   = user->mu;
     72:   PetscInt          rowcol[] = {0,1};
     73:   PetscScalar       J[2][2];
     74:   const PetscScalar *u;

     77:   VecGetArrayRead(U,&u);

     79:   J[0][0] = 0;
     80:   J[1][0] = -mu*(2.0*u[1]*u[0]+1.);
     81:   J[0][1] = 1.0;
     82:   J[1][1] = mu*(1.0-u[0]*u[0]);
     83:   MatSetValues(A,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
     84:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
     85:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
     86:   if (B && A != B) {
     87:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
     88:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
     89:   }

     91:   VecRestoreArrayRead(U,&u);
     92:   return(0);
     93: }

     95: static PetscErrorCode RHSHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
     96: {
     97:   const PetscScalar *vl,*vr,*u;
     98:   PetscScalar       *vhv;
     99:   PetscScalar       dJdU[2][2][2]={{{0}}};
    100:   PetscInt          i,j,k;
    101:   User              user = (User)ctx;
    102:   PetscErrorCode    ierr;

    105:   VecGetArrayRead(U,&u);
    106:   VecGetArrayRead(Vl[0],&vl);
    107:   VecGetArrayRead(Vr,&vr);
    108:   VecGetArray(VHV[0],&vhv);

    110:   dJdU[1][0][0] = -2.*user->mu*u[1];
    111:   dJdU[1][1][0] = -2.*user->mu*u[0];
    112:   dJdU[1][0][1] = -2.*user->mu*u[0];
    113:   for (j=0; j<2; j++) {
    114:     vhv[j] = 0;
    115:     for (k=0; k<2; k++)
    116:       for (i=0; i<2; i++)
    117:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
    118:   }

    120:   VecRestoreArrayRead(U,&u);
    121:   VecRestoreArrayRead(Vl[0],&vl);
    122:   VecRestoreArrayRead(Vr,&vr);
    123:   VecRestoreArray(VHV[0],&vhv);
    124:   return(0);
    125: }

    127: static PetscErrorCode RHSHessianProductUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    128: {
    129:   const PetscScalar *vl,*vr,*u;
    130:   PetscScalar       *vhv;
    131:   PetscScalar       dJdP[2][2][1]={{{0}}};
    132:   PetscInt          i,j,k;
    133:   PetscErrorCode    ierr;

    136:   VecGetArrayRead(U,&u);
    137:   VecGetArrayRead(Vl[0],&vl);
    138:   VecGetArrayRead(Vr,&vr);
    139:   VecGetArray(VHV[0],&vhv);

    141:   dJdP[1][0][0] = -(1.+2.*u[0]*u[1]);
    142:   dJdP[1][1][0] = 1.-u[0]*u[0];
    143:   for (j=0; j<2; j++) {
    144:     vhv[j] = 0;
    145:     for (k=0; k<1; k++)
    146:       for (i=0; i<2; i++)
    147:         vhv[j] += vl[i]*dJdP[i][j][k]*vr[k];
    148:   }

    150:   VecRestoreArrayRead(U,&u);
    151:   VecRestoreArrayRead(Vl[0],&vl);
    152:   VecRestoreArrayRead(Vr,&vr);
    153:   VecRestoreArray(VHV[0],&vhv);
    154:   return(0);
    155: }

    157: static PetscErrorCode RHSHessianProductPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    158: {
    159:   const PetscScalar *vl,*vr,*u;
    160:   PetscScalar       *vhv;
    161:   PetscScalar       dJdU[2][1][2]={{{0}}};
    162:   PetscInt          i,j,k;
    163:   PetscErrorCode    ierr;

    166:   VecGetArrayRead(U,&u);
    167:   VecGetArrayRead(Vl[0],&vl);
    168:   VecGetArrayRead(Vr,&vr);
    169:   VecGetArray(VHV[0],&vhv);

    171:   dJdU[1][0][0] = -1.-2.*u[1]*u[0];
    172:   dJdU[1][0][1] = 1.-u[0]*u[0];
    173:   for (j=0; j<1; j++) {
    174:     vhv[j] = 0;
    175:     for (k=0; k<2; k++)
    176:       for (i=0; i<2; i++)
    177:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
    178:   }

    180:   VecRestoreArrayRead(U,&u);
    181:   VecRestoreArrayRead(Vl[0],&vl);
    182:   VecRestoreArrayRead(Vr,&vr);
    183:   VecRestoreArray(VHV[0],&vhv);
    184:   return(0);
    185: }

    187: static PetscErrorCode RHSHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    188: {
    190:   return(0);
    191: }

    193: /* ----------------------- Implicit form of the ODE  -------------------- */

    195: static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,void *ctx)
    196: {
    197:   PetscErrorCode    ierr;
    198:   User              user = (User)ctx;
    199:   PetscScalar       *f;
    200:   const PetscScalar *u,*udot;

    203:   VecGetArrayRead(U,&u);
    204:   VecGetArrayRead(Udot,&udot);
    205:   VecGetArray(F,&f);

    207:   f[0] = udot[0] - u[1];
    208:   f[1] = udot[1] - user->mu*((1.0-u[0]*u[0])*u[1] - u[0]) ;

    210:   VecRestoreArrayRead(U,&u);
    211:   VecRestoreArrayRead(Udot,&udot);
    212:   VecRestoreArray(F,&f);
    213:   return(0);
    214: }

    216: static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,void *ctx)
    217: {
    218:   PetscErrorCode    ierr;
    219:   User              user     = (User)ctx;
    220:   PetscInt          rowcol[] = {0,1};
    221:   PetscScalar       J[2][2];
    222:   const PetscScalar *u;

    225:   VecGetArrayRead(U,&u);

    227:   J[0][0] = a;     J[0][1] =  -1.0;
    228:   J[1][0] = user->mu*(1.0 + 2.0*u[0]*u[1]);   J[1][1] = a - user->mu*(1.0-u[0]*u[0]);
    229:   MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
    230:   VecRestoreArrayRead(U,&u);
    231:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    232:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    233:   if (A != B) {
    234:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
    235:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
    236:   }

    238:   VecRestoreArrayRead(U,&u);
    239:   return(0);
    240: }

    242: static PetscErrorCode RHSJacobianP(TS ts,PetscReal t,Vec U,Mat A,void *ctx)
    243: {
    244:   PetscErrorCode    ierr;
    245:   PetscInt          row[] = {0,1},col[]={0};
    246:   PetscScalar       J[2][1];
    247:   const PetscScalar *u;

    250:   VecGetArrayRead(U,&u);

    252:   J[0][0] = 0;
    253:   J[1][0] = (1.-u[0]*u[0])*u[1]-u[0];
    254:   MatSetValues(A,2,row,1,col,&J[0][0],INSERT_VALUES);
    255:   VecRestoreArrayRead(U,&u);
    256:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    257:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);

    259:   VecRestoreArrayRead(U,&u);
    260:   return(0);
    261: }

    263: static PetscErrorCode IHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    264: {
    265:   const PetscScalar *vl,*vr,*u;
    266:   PetscScalar       *vhv;
    267:   PetscScalar       dJdU[2][2][2]={{{0}}};
    268:   PetscInt          i,j,k;
    269:   User              user = (User)ctx;
    270:   PetscErrorCode    ierr;

    273:   VecGetArrayRead(U,&u);
    274:   VecGetArrayRead(Vl[0],&vl);
    275:   VecGetArrayRead(Vr,&vr);
    276:   VecGetArray(VHV[0],&vhv);

    278:   dJdU[1][0][0] = 2.*user->mu*u[1];
    279:   dJdU[1][1][0] = 2.*user->mu*u[0];
    280:   dJdU[1][0][1] = 2.*user->mu*u[0];
    281:   for (j=0; j<2; j++) {
    282:     vhv[j] = 0;
    283:     for (k=0; k<2; k++)
    284:       for (i=0; i<2; i++)
    285:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
    286:   }

    288:   VecRestoreArrayRead(U,&u);
    289:   VecRestoreArrayRead(Vl[0],&vl);
    290:   VecRestoreArrayRead(Vr,&vr);
    291:   VecRestoreArray(VHV[0],&vhv);
    292:   return(0);
    293: }

    295: static PetscErrorCode IHessianProductUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    296: {
    297:   const PetscScalar *vl,*vr,*u;
    298:   PetscScalar       *vhv;
    299:   PetscScalar       dJdP[2][2][1]={{{0}}};
    300:   PetscInt          i,j,k;
    301:   PetscErrorCode    ierr;

    304:   VecGetArrayRead(U,&u);
    305:   VecGetArrayRead(Vl[0],&vl);
    306:   VecGetArrayRead(Vr,&vr);
    307:   VecGetArray(VHV[0],&vhv);

    309:   dJdP[1][0][0] = 1.+2.*u[0]*u[1];
    310:   dJdP[1][1][0] = u[0]*u[0]-1.;
    311:   for (j=0; j<2; j++) {
    312:     vhv[j] = 0;
    313:     for (k=0; k<1; k++)
    314:       for (i=0; i<2; i++)
    315:         vhv[j] += vl[i]*dJdP[i][j][k]*vr[k];
    316:   }

    318:   VecRestoreArrayRead(U,&u);
    319:   VecRestoreArrayRead(Vl[0],&vl);
    320:   VecRestoreArrayRead(Vr,&vr);
    321:   VecRestoreArray(VHV[0],&vhv);
    322:   return(0);
    323: }

    325: static PetscErrorCode IHessianProductPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    326: {
    327:   const PetscScalar *vl,*vr,*u;
    328:   PetscScalar       *vhv;
    329:   PetscScalar       dJdU[2][1][2]={{{0}}};
    330:   PetscInt          i,j,k;
    331:   PetscErrorCode    ierr;

    334:   VecGetArrayRead(U,&u);
    335:   VecGetArrayRead(Vl[0],&vl);
    336:   VecGetArrayRead(Vr,&vr);
    337:   VecGetArray(VHV[0],&vhv);

    339:   dJdU[1][0][0] = 1.+2.*u[1]*u[0];
    340:   dJdU[1][0][1] = u[0]*u[0]-1.;
    341:   for (j=0; j<1; j++) {
    342:     vhv[j] = 0;
    343:     for (k=0; k<2; k++)
    344:       for (i=0; i<2; i++)
    345:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
    346:   }

    348:   VecRestoreArrayRead(U,&u);
    349:   VecRestoreArrayRead(Vl[0],&vl);
    350:   VecRestoreArrayRead(Vr,&vr);
    351:   VecRestoreArray(VHV[0],&vhv);
    352:   return(0);
    353: }

    355: static PetscErrorCode IHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    356: {
    358:   return(0);
    359: }

    361: /* Monitor timesteps and use interpolation to output at integer multiples of 0.1 */
    362: static PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal t,Vec X,void *ctx)
    363: {
    364:   PetscErrorCode    ierr;
    365:   const PetscScalar *x;
    366:   PetscReal         tfinal, dt;
    367:   User              user = (User)ctx;
    368:   Vec               interpolatedX;

    371:   TSGetTimeStep(ts,&dt);
    372:   TSGetMaxTime(ts,&tfinal);

    374:   while (user->next_output <= t && user->next_output <= tfinal) {
    375:     VecDuplicate(X,&interpolatedX);
    376:     TSInterpolate(ts,user->next_output,interpolatedX);
    377:     VecGetArrayRead(interpolatedX,&x);
    378:     PetscPrintf(PETSC_COMM_WORLD,"[%g] %D TS %g (dt = %g) X %g %g\n",
    379:                        (double)user->next_output,step,(double)t,(double)dt,(double)PetscRealPart(x[0]),
    380:                        (double)PetscRealPart(x[1]));
    381:     VecRestoreArrayRead(interpolatedX,&x);
    382:     VecDestroy(&interpolatedX);
    383:     user->next_output += PetscRealConstant(0.1);
    384:   }
    385:   return(0);
    386: }

    388: int main(int argc,char **argv)
    389: {
    390:   Vec                P;
    391:   PetscBool          monitor = PETSC_FALSE;
    392:   PetscScalar        *x_ptr;
    393:   const PetscScalar  *y_ptr;
    394:   PetscMPIInt        size;
    395:   struct _n_User     user;
    396:   PetscErrorCode     ierr;
    397:   Tao                tao;
    398:   KSP                ksp;
    399:   PC                 pc;

    401:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    402:      Initialize program
    403:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    404:   PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr;
    405:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
    406:   if (size != 1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"This is a uniprocessor example only!");

    408:   /* Create TAO solver and set desired solution method */
    409:   TaoCreate(PETSC_COMM_WORLD,&tao);
    410:   TaoSetType(tao,TAOBQNLS);

    412:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    413:     Set runtime options
    414:     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    415:   user.next_output  = 0.0;
    416:   user.mu           = PetscRealConstant(1.0e3);
    417:   user.ftime        = PetscRealConstant(0.5);
    418:   user.implicitform = PETSC_TRUE;

    420:   PetscOptionsGetBool(NULL,NULL,"-monitor",&monitor,NULL);
    421:   PetscOptionsGetReal(NULL,NULL,"-mu",&user.mu,NULL);
    422:   PetscOptionsGetBool(NULL,NULL,"-implicitform",&user.implicitform,NULL);

    424:   /* Create necessary matrix and vectors, solve same ODE on every process */
    425:   MatCreate(PETSC_COMM_WORLD,&user.A);
    426:   MatSetSizes(user.A,PETSC_DECIDE,PETSC_DECIDE,2,2);
    427:   MatSetFromOptions(user.A);
    428:   MatSetUp(user.A);
    429:   MatCreateVecs(user.A,&user.U,NULL);
    430:   MatCreateVecs(user.A,&user.Lambda[0],NULL);
    431:   MatCreateVecs(user.A,&user.Lambda2[0],NULL);
    432:   MatCreateVecs(user.A,&user.Ihp1[0],NULL);
    433:   MatCreateVecs(user.A,&user.Ihp2[0],NULL);

    435:   MatCreate(PETSC_COMM_WORLD,&user.Jacp);
    436:   MatSetSizes(user.Jacp,PETSC_DECIDE,PETSC_DECIDE,2,1);
    437:   MatSetFromOptions(user.Jacp);
    438:   MatSetUp(user.Jacp);
    439:   MatCreateVecs(user.Jacp,&user.Dir,NULL);
    440:   MatCreateVecs(user.Jacp,&user.Mup[0],NULL);
    441:   MatCreateVecs(user.Jacp,&user.Mup2[0],NULL);
    442:   MatCreateVecs(user.Jacp,&user.Ihp3[0],NULL);
    443:   MatCreateVecs(user.Jacp,&user.Ihp4[0],NULL);

    445:   /* Create timestepping solver context */
    446:   TSCreate(PETSC_COMM_WORLD,&user.ts);
    447:   TSSetEquationType(user.ts,TS_EQ_ODE_EXPLICIT); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
    448:   if (user.implicitform) {
    449:     TSSetIFunction(user.ts,NULL,IFunction,&user);
    450:     TSSetIJacobian(user.ts,user.A,user.A,IJacobian,&user);
    451:     TSSetType(user.ts,TSCN);
    452:   } else {
    453:     TSSetRHSFunction(user.ts,NULL,RHSFunction,&user);
    454:     TSSetRHSJacobian(user.ts,user.A,user.A,RHSJacobian,&user);
    455:     TSSetType(user.ts,TSRK);
    456:   }
    457:   TSSetRHSJacobianP(user.ts,user.Jacp,RHSJacobianP,&user);
    458:   TSSetMaxTime(user.ts,user.ftime);
    459:   TSSetExactFinalTime(user.ts,TS_EXACTFINALTIME_MATCHSTEP);

    461:   if (monitor) {
    462:     TSMonitorSet(user.ts,Monitor,&user,NULL);
    463:   }

    465:   /* Set ODE initial conditions */
    466:   VecGetArray(user.U,&x_ptr);
    467:   x_ptr[0] = 2.0;
    468:   x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user.mu) - 292.0/(2187.0*user.mu*user.mu);
    469:   VecRestoreArray(user.U,&x_ptr);
    470:   TSSetTimeStep(user.ts,PetscRealConstant(0.001));

    472:   /* Set runtime options */
    473:   TSSetFromOptions(user.ts);

    475:   TSSolve(user.ts,user.U);
    476:   VecGetArrayRead(user.U,&y_ptr);
    477:   user.ob[0] = y_ptr[0];
    478:   user.ob[1] = y_ptr[1];
    479:   VecRestoreArrayRead(user.U,&y_ptr);

    481:   /* Save trajectory of solution so that TSAdjointSolve() may be used.
    482:      Skip checkpointing for the first TSSolve since no adjoint run follows it.
    483:    */
    484:   TSSetSaveTrajectory(user.ts);

    486:   /* Optimization starts */
    487:   MatCreate(PETSC_COMM_WORLD,&user.H);
    488:   MatSetSizes(user.H,PETSC_DECIDE,PETSC_DECIDE,1,1);
    489:   MatSetUp(user.H); /* Hessian should be symmetric. Do we need to do MatSetOption(user.H,MAT_SYMMETRIC,PETSC_TRUE) ? */

    491:   /* Set initial solution guess */
    492:   MatCreateVecs(user.Jacp,&P,NULL);
    493:   VecGetArray(P,&x_ptr);
    494:   x_ptr[0] = PetscRealConstant(1.2);
    495:   VecRestoreArray(P,&x_ptr);
    496:   TaoSetInitialVector(tao,P);

    498:   /* Set routine for function and gradient evaluation */
    499:   TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&user);
    500:   TaoSetHessianRoutine(tao,user.H,user.H,FormHessian,(void *)&user);

    502:   /* Check for any TAO command line options */
    503:   TaoGetKSP(tao,&ksp);
    504:   if (ksp) {
    505:     KSPGetPC(ksp,&pc);
    506:     PCSetType(pc,PCNONE);
    507:   }
    508:   TaoSetFromOptions(tao);

    510:   TaoSolve(tao);

    512:   VecView(P,PETSC_VIEWER_STDOUT_WORLD);
    513:   /* Free TAO data structures */
    514:   TaoDestroy(&tao);

    516:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    517:      Free work space.  All PETSc objects should be destroyed when they
    518:      are no longer needed.
    519:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    520:   MatDestroy(&user.H);
    521:   MatDestroy(&user.A);
    522:   VecDestroy(&user.U);
    523:   MatDestroy(&user.Jacp);
    524:   VecDestroy(&user.Lambda[0]);
    525:   VecDestroy(&user.Mup[0]);
    526:   VecDestroy(&user.Lambda2[0]);
    527:   VecDestroy(&user.Mup2[0]);
    528:   VecDestroy(&user.Ihp1[0]);
    529:   VecDestroy(&user.Ihp2[0]);
    530:   VecDestroy(&user.Ihp3[0]);
    531:   VecDestroy(&user.Ihp4[0]);
    532:   VecDestroy(&user.Dir);
    533:   TSDestroy(&user.ts);
    534:   VecDestroy(&P);
    535:   PetscFinalize();
    536:   return ierr;
    537: }

    539: /* ------------------------------------------------------------------ */
    540: /*
    541:    FormFunctionGradient - Evaluates the function and corresponding gradient.

    543:    Input Parameters:
    544:    tao - the Tao context
    545:    X   - the input vector
    546:    ptr - optional user-defined context, as set by TaoSetObjectiveAndGradientRoutine()

    548:    Output Parameters:
    549:    f   - the newly evaluated function
    550:    G   - the newly evaluated gradient
    551: */
    552: PetscErrorCode FormFunctionGradient(Tao tao,Vec P,PetscReal *f,Vec G,void *ctx)
    553: {
    554:   User              user_ptr = (User)ctx;
    555:   TS                ts = user_ptr->ts;
    556:   PetscScalar       *x_ptr,*g;
    557:   const PetscScalar *y_ptr;
    558:   PetscErrorCode    ierr;

    561:   VecGetArrayRead(P,&y_ptr);
    562:   user_ptr->mu = y_ptr[0];
    563:   VecRestoreArrayRead(P,&y_ptr);

    565:   TSSetTime(ts,0.0);
    566:   TSSetStepNumber(ts,0);
    567:   TSSetTimeStep(ts,PetscRealConstant(0.001)); /* can be overwritten by command line options */
    568:   TSSetFromOptions(ts);
    569:   VecGetArray(user_ptr->U,&x_ptr);
    570:   x_ptr[0] = 2.0;
    571:   x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user_ptr->mu) - 292.0/(2187.0*user_ptr->mu*user_ptr->mu);
    572:   VecRestoreArray(user_ptr->U,&x_ptr);

    574:   TSSolve(ts,user_ptr->U);

    576:   VecGetArrayRead(user_ptr->U,&y_ptr);
    577:   *f   = (y_ptr[0]-user_ptr->ob[0])*(y_ptr[0]-user_ptr->ob[0])+(y_ptr[1]-user_ptr->ob[1])*(y_ptr[1]-user_ptr->ob[1]);

    579:   /*   Reset initial conditions for the adjoint integration */
    580:   VecGetArray(user_ptr->Lambda[0],&x_ptr);
    581:   x_ptr[0] = 2.*(y_ptr[0]-user_ptr->ob[0]);
    582:   x_ptr[1] = 2.*(y_ptr[1]-user_ptr->ob[1]);
    583:   VecRestoreArrayRead(user_ptr->U,&y_ptr);
    584:   VecRestoreArray(user_ptr->Lambda[0],&x_ptr);

    586:   VecGetArray(user_ptr->Mup[0],&x_ptr);
    587:   x_ptr[0] = 0.0;
    588:   VecRestoreArray(user_ptr->Mup[0],&x_ptr);
    589:   TSSetCostGradients(ts,1,user_ptr->Lambda,user_ptr->Mup);

    591:   TSAdjointSolve(ts);

    593:   VecGetArray(user_ptr->Mup[0],&x_ptr);
    594:   VecGetArrayRead(user_ptr->Lambda[0],&y_ptr);
    595:   VecGetArray(G,&g);
    596:   g[0] = y_ptr[1]*(-10.0/(81.0*user_ptr->mu*user_ptr->mu)+2.0*292.0/(2187.0*user_ptr->mu*user_ptr->mu*user_ptr->mu))+x_ptr[0];
    597:   VecRestoreArray(user_ptr->Mup[0],&x_ptr);
    598:   VecRestoreArrayRead(user_ptr->Lambda[0],&y_ptr);
    599:   VecRestoreArray(G,&g);
    600:   return(0);
    601: }

    603: PetscErrorCode FormHessian(Tao tao,Vec P,Mat H,Mat Hpre,void *ctx)
    604: {
    605:   User           user_ptr = (User)ctx;
    606:   PetscScalar    harr[1];
    607:   const PetscInt rows[1] = {0};
    608:   PetscInt       col = 0;

    612:   Adjoint2(P,harr,user_ptr);
    613:   MatSetValues(H,1,rows,1,&col,harr,INSERT_VALUES);

    615:   MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);
    616:   MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);
    617:   if (H != Hpre) {
    618:     MatAssemblyBegin(Hpre,MAT_FINAL_ASSEMBLY);
    619:     MatAssemblyEnd(Hpre,MAT_FINAL_ASSEMBLY);
    620:   }
    621:   return(0);
    622: }

    624: PetscErrorCode Adjoint2(Vec P,PetscScalar arr[],User ctx)
    625: {
    626:   TS                ts = ctx->ts;
    627:   const PetscScalar *z_ptr;
    628:   PetscScalar       *x_ptr,*y_ptr,dzdp,dzdp2;
    629:   Mat               tlmsen;
    630:   PetscErrorCode    ierr;

    633:   /* Reset TSAdjoint so that AdjointSetUp will be called again */
    634:   TSAdjointReset(ts);

    636:   /* The directional vector should be 1 since it is one-dimensional */
    637:   VecGetArray(ctx->Dir,&x_ptr);
    638:   x_ptr[0] = 1.;
    639:   VecRestoreArray(ctx->Dir,&x_ptr);

    641:   VecGetArrayRead(P,&z_ptr);
    642:   ctx->mu = z_ptr[0];
    643:   VecRestoreArrayRead(P,&z_ptr);

    645:   dzdp  = -10.0/(81.0*ctx->mu*ctx->mu) + 2.0*292.0/(2187.0*ctx->mu*ctx->mu*ctx->mu);
    646:   dzdp2 = 2.*10.0/(81.0*ctx->mu*ctx->mu*ctx->mu) - 3.0*2.0*292.0/(2187.0*ctx->mu*ctx->mu*ctx->mu*ctx->mu);

    648:   TSSetTime(ts,0.0);
    649:   TSSetStepNumber(ts,0);
    650:   TSSetTimeStep(ts,PetscRealConstant(0.001)); /* can be overwritten by command line options */
    651:   TSSetFromOptions(ts);
    652:   TSSetCostHessianProducts(ts,1,ctx->Lambda2,ctx->Mup2,ctx->Dir);

    654:   MatZeroEntries(ctx->Jacp);
    655:   MatSetValue(ctx->Jacp,1,0,dzdp,INSERT_VALUES);
    656:   MatAssemblyBegin(ctx->Jacp,MAT_FINAL_ASSEMBLY);
    657:   MatAssemblyEnd(ctx->Jacp,MAT_FINAL_ASSEMBLY);

    659:   TSAdjointSetForward(ts,ctx->Jacp);
    660:   VecGetArray(ctx->U,&y_ptr);
    661:   y_ptr[0] = 2.0;
    662:   y_ptr[1] = -2.0/3.0 + 10.0/(81.0*ctx->mu) - 292.0/(2187.0*ctx->mu*ctx->mu);
    663:   VecRestoreArray(ctx->U,&y_ptr);
    664:   TSSolve(ts,ctx->U);

    666:   /* Set terminal conditions for first- and second-order adjonts */
    667:   VecGetArrayRead(ctx->U,&z_ptr);
    668:   VecGetArray(ctx->Lambda[0],&y_ptr);
    669:   y_ptr[0] = 2.*(z_ptr[0]-ctx->ob[0]);
    670:   y_ptr[1] = 2.*(z_ptr[1]-ctx->ob[1]);
    671:   VecRestoreArray(ctx->Lambda[0],&y_ptr);
    672:   VecRestoreArrayRead(ctx->U,&z_ptr);
    673:   VecGetArray(ctx->Mup[0],&y_ptr);
    674:   y_ptr[0] = 0.0;
    675:   VecRestoreArray(ctx->Mup[0],&y_ptr);
    676:   TSForwardGetSensitivities(ts,NULL,&tlmsen);
    677:   MatDenseGetColumn(tlmsen,0,&x_ptr);
    678:   VecGetArray(ctx->Lambda2[0],&y_ptr);
    679:   y_ptr[0] = 2.*x_ptr[0];
    680:   y_ptr[1] = 2.*x_ptr[1];
    681:   VecRestoreArray(ctx->Lambda2[0],&y_ptr);
    682:   VecGetArray(ctx->Mup2[0],&y_ptr);
    683:   y_ptr[0] = 0.0;
    684:   VecRestoreArray(ctx->Mup2[0],&y_ptr);
    685:   MatDenseRestoreColumn(tlmsen,&x_ptr);
    686:   TSSetCostGradients(ts,1,ctx->Lambda,ctx->Mup);
    687:   if (ctx->implicitform) {
    688:     TSSetIHessianProduct(ts,ctx->Ihp1,IHessianProductUU,ctx->Ihp2,IHessianProductUP,ctx->Ihp3,IHessianProductPU,ctx->Ihp4,IHessianProductPP,ctx);
    689:   } else {
    690:     TSSetRHSHessianProduct(ts,ctx->Ihp1,RHSHessianProductUU,ctx->Ihp2,RHSHessianProductUP,ctx->Ihp3,RHSHessianProductPU,ctx->Ihp4,RHSHessianProductPP,ctx);
    691:   }
    692:   TSAdjointSolve(ts);

    694:   VecGetArray(ctx->Lambda[0],&x_ptr);
    695:   VecGetArray(ctx->Lambda2[0],&y_ptr);
    696:   VecGetArrayRead(ctx->Mup2[0],&z_ptr);

    698:   arr[0] = x_ptr[1]*dzdp2 + y_ptr[1]*dzdp2 + z_ptr[0];

    700:   VecRestoreArray(ctx->Lambda2[0],&x_ptr);
    701:   VecRestoreArray(ctx->Lambda2[0],&y_ptr);
    702:   VecRestoreArrayRead(ctx->Mup2[0],&z_ptr);

    704:   /* Disable second-order adjoint mode */
    705:   TSAdjointReset(ts);
    706:   TSAdjointResetForward(ts);
    707:   return(0);
    708: }

    710: /*TEST
    711:     build:
    712:       requires: !complex !single
    713:     test:
    714:       args:  -implicitform 0 -ts_type rk -ts_adapt_type none -mu 10 -ts_dt 0.1 -viewer_binary_skip_info -tao_monitor -tao_view
    715:       output_file: output/ex20opt_p_1.out

    717:     test:
    718:       suffix: 2
    719:       args:  -implicitform 0 -ts_type rk -ts_adapt_type none -mu 10 -ts_dt 0.01 -viewer_binary_skip_info -tao_monitor -tao_type bntr -tao_bnk_pc_type none
    720:       output_file: output/ex20opt_p_2.out

    722:     test:
    723:       suffix: 3
    724:       args:  -ts_type cn -ts_adapt_type none -mu 100 -ts_dt 0.01 -viewer_binary_skip_info -tao_monitor -tao_view
    725:       output_file: output/ex20opt_p_3.out

    727:     test:
    728:       suffix: 4
    729:       args:  -ts_type cn -ts_adapt_type none -mu 100 -ts_dt 0.01 -viewer_binary_skip_info -tao_monitor -tao_type bntr -tao_bnk_pc_type none
    730:       output_file: output/ex20opt_p_4.out

    732: TEST*/