Date: 2022-03-31T04:48:46+00:00

Actual source code: ex20opt_ic.c

      1: static char help[] = "Solves a ODE-constrained optimization problem -- finding the optimal initial conditions for the van der Pol equation.\n";

      3: /*
      4:   Concepts: TS^time-dependent nonlinear problems
      5:   Concepts: TS^van der Pol equation DAE equivalent
      6:   Concepts: TS^Optimization using adjoint sensitivity analysis
      7:   Processors: 1
      8: */
      9: /*
     10:   Notes:
     11:   This code demonstrates how to solve an ODE-constrained optimization problem with TAO, TSAdjoint and TS.
     12:   The nonlinear problem is written in an ODE equivalent form.
     13:   The objective is to minimize the difference between observation and model prediction by finding optimal values for initial conditions.
     14:   The gradient is computed with the discrete adjoint of an implicit method or an explicit method, see ex20adj.c for details.
     15: */

     17: #include <petsctao.h>
     18: #include <petscts.h>

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

     26:   /* Sensitivity analysis support */
     27:   PetscInt  steps;
     28:   PetscReal ftime;
     29:   Mat       A;                       /* Jacobian matrix for ODE */
     30:   Mat       Jacp;                    /* JacobianP matrix for ODE*/
     31:   Mat       H;                       /* Hessian matrix for optimization */
     32:   Vec       U,Lambda[1],Mup[1];      /* first-order adjoint variables */
     33:   Vec       Lambda2[2];              /* second-order adjoint variables */
     34:   Vec       Ihp1[1];                 /* working space for Hessian evaluations */
     35:   Vec       Dir;                     /* direction vector */
     36:   PetscReal ob[2];                   /* observation used by the cost function */
     37:   PetscBool implicitform;            /* implicit ODE? */
     38: };
     39: PetscErrorCode Adjoint2(Vec,PetscScalar[],User);

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

     43: static PetscErrorCode RHSFunction(TS ts,PetscReal t,Vec U,Vec F,void *ctx)
     44: {
     45:   User              user = (User)ctx;
     46:   PetscScalar       *f;
     47:   const PetscScalar *u;

     50:   VecGetArrayRead(U,&u);
     51:   VecGetArray(F,&f);
     52:   f[0] = u[1];
     53:   f[1] = user->mu*((1.-u[0]*u[0])*u[1]-u[0]);
     54:   VecRestoreArrayRead(U,&u);
     55:   VecRestoreArray(F,&f);
     56:   return 0;
     57: }

     59: static PetscErrorCode RHSJacobian(TS ts,PetscReal t,Vec U,Mat A,Mat B,void *ctx)
     60: {
     61:   User              user = (User)ctx;
     62:   PetscReal         mu   = user->mu;
     63:   PetscInt          rowcol[] = {0,1};
     64:   PetscScalar       J[2][2];
     65:   const PetscScalar *u;

     68:   VecGetArrayRead(U,&u);
     69:   J[0][0] = 0;
     70:   J[1][0] = -mu*(2.0*u[1]*u[0]+1.);
     71:   J[0][1] = 1.0;
     72:   J[1][1] = mu*(1.0-u[0]*u[0]);
     73:   MatSetValues(A,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
     74:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
     75:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
     76:   if (A != B) {
     77:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
     78:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
     79:   }
     80:   VecRestoreArrayRead(U,&u);
     81:   return 0;
     82: }

     84: static PetscErrorCode RHSHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
     85: {
     86:   const PetscScalar *vl,*vr,*u;
     87:   PetscScalar       *vhv;
     88:   PetscScalar       dJdU[2][2][2]={{{0}}};
     89:   PetscInt          i,j,k;
     90:   User              user = (User)ctx;

     93:   VecGetArrayRead(U,&u);
     94:   VecGetArrayRead(Vl[0],&vl);
     95:   VecGetArrayRead(Vr,&vr);
     96:   VecGetArray(VHV[0],&vhv);

     98:   dJdU[1][0][0] = -2.*user->mu*u[1];
     99:   dJdU[1][1][0] = -2.*user->mu*u[0];
    100:   dJdU[1][0][1] = -2.*user->mu*u[0];
    101:   for (j=0;j<2;j++) {
    102:     vhv[j] = 0;
    103:     for (k=0;k<2;k++)
    104:       for (i=0;i<2;i++)
    105:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
    106:   }
    107:   VecRestoreArrayRead(U,&u);
    108:   VecRestoreArrayRead(Vl[0],&vl);
    109:   VecRestoreArrayRead(Vr,&vr);
    110:   VecRestoreArray(VHV[0],&vhv);
    111:   return 0;
    112: }

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

    116: static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,void *ctx)
    117: {
    118:   User              user = (User)ctx;
    119:   const PetscScalar *u,*udot;
    120:   PetscScalar       *f;

    123:   VecGetArrayRead(U,&u);
    124:   VecGetArrayRead(Udot,&udot);
    125:   VecGetArray(F,&f);
    126:   f[0] = udot[0] - u[1];
    127:   f[1] = udot[1] - user->mu*((1.0-u[0]*u[0])*u[1] - u[0]) ;
    128:   VecRestoreArrayRead(U,&u);
    129:   VecRestoreArrayRead(Udot,&udot);
    130:   VecRestoreArray(F,&f);
    131:   return 0;
    132: }

    134: static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,void *ctx)
    135: {
    136:   User              user = (User)ctx;
    137:   PetscInt          rowcol[] = {0,1};
    138:   PetscScalar       J[2][2];
    139:   const PetscScalar *u;

    142:   VecGetArrayRead(U,&u);
    143:   J[0][0] = a;     J[0][1] =  -1.0;
    144:   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]);
    145:   MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
    146:   VecRestoreArrayRead(U,&u);
    147:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    148:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    149:   if (A != B) {
    150:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
    151:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
    152:   }
    153:   return 0;
    154: }

    156: /* Monitor timesteps and use interpolation to output at integer multiples of 0.1 */
    157: static PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal t,Vec U,void *ctx)
    158: {
    159:   const PetscScalar *u;
    160:   PetscReal         tfinal, dt;
    161:   User              user = (User)ctx;
    162:   Vec               interpolatedU;

    165:   TSGetTimeStep(ts,&dt);
    166:   TSGetMaxTime(ts,&tfinal);

    168:   while (user->next_output <= t && user->next_output <= tfinal) {
    169:     VecDuplicate(U,&interpolatedU);
    170:     TSInterpolate(ts,user->next_output,interpolatedU);
    171:     VecGetArrayRead(interpolatedU,&u);
    172:     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"[%g] %D TS %g (dt = %g) X %g %g\n",
    173:                         (double)user->next_output,step,(double)t,(double)dt,(double)PetscRealPart(u[0]),
    174:                         (double)PetscRealPart(u[1])));
    175:     VecRestoreArrayRead(interpolatedU,&u);
    176:     VecDestroy(&interpolatedU);
    177:     user->next_output += 0.1;
    178:   }
    179:   return 0;
    180: }

    182: static PetscErrorCode IHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
    183: {
    184:   const PetscScalar *vl,*vr,*u;
    185:   PetscScalar       *vhv;
    186:   PetscScalar       dJdU[2][2][2]={{{0}}};
    187:   PetscInt          i,j,k;
    188:   User              user = (User)ctx;

    191:   VecGetArrayRead(U,&u);
    192:   VecGetArrayRead(Vl[0],&vl);
    193:   VecGetArrayRead(Vr,&vr);
    194:   VecGetArray(VHV[0],&vhv);
    195:   dJdU[1][0][0] = 2.*user->mu*u[1];
    196:   dJdU[1][1][0] = 2.*user->mu*u[0];
    197:   dJdU[1][0][1] = 2.*user->mu*u[0];
    198:   for (j=0;j<2;j++) {
    199:     vhv[j] = 0;
    200:     for (k=0;k<2;k++)
    201:       for (i=0;i<2;i++)
    202:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
    203:   }
    204:   VecRestoreArrayRead(U,&u);
    205:   VecRestoreArrayRead(Vl[0],&vl);
    206:   VecRestoreArrayRead(Vr,&vr);
    207:   VecRestoreArray(VHV[0],&vhv);
    208:   return 0;
    209: }

    211: /* ------------------ User-defined routines for TAO -------------------------- */

    213: static PetscErrorCode FormFunctionGradient(Tao tao,Vec IC,PetscReal *f,Vec G,void *ctx)
    214: {
    215:   User              user_ptr = (User)ctx;
    216:   TS                ts = user_ptr->ts;
    217:   const PetscScalar *x_ptr;
    218:   PetscScalar       *y_ptr;

    221:   VecCopy(IC,user_ptr->U); /* set up the initial condition */

    223:   TSSetTime(ts,0.0);
    224:   TSSetStepNumber(ts,0);
    225:   TSSetTimeStep(ts,0.001); /* can be overwritten by command line options */
    226:   TSSetFromOptions(ts);
    227:   TSSolve(ts,user_ptr->U);

    229:   VecGetArrayRead(user_ptr->U,&x_ptr);
    230:   VecGetArray(user_ptr->Lambda[0],&y_ptr);
    231:   *f       = (x_ptr[0]-user_ptr->ob[0])*(x_ptr[0]-user_ptr->ob[0])+(x_ptr[1]-user_ptr->ob[1])*(x_ptr[1]-user_ptr->ob[1]);
    232:   y_ptr[0] = 2.*(x_ptr[0]-user_ptr->ob[0]);
    233:   y_ptr[1] = 2.*(x_ptr[1]-user_ptr->ob[1]);
    234:   VecRestoreArray(user_ptr->Lambda[0],&y_ptr);
    235:   VecRestoreArrayRead(user_ptr->U,&x_ptr);

    237:   TSSetCostGradients(ts,1,user_ptr->Lambda,NULL);
    238:   TSAdjointSolve(ts);
    239:   VecCopy(user_ptr->Lambda[0],G);
    240:   return 0;
    241: }

    243: static PetscErrorCode FormHessian(Tao tao,Vec U,Mat H,Mat Hpre,void *ctx)
    244: {
    245:   User           user_ptr = (User)ctx;
    246:   PetscScalar    harr[2];
    247:   PetscScalar    *x_ptr;
    248:   const PetscInt rows[2] = {0,1};
    249:   PetscInt       col;

    252:   VecCopy(U,user_ptr->U);
    253:   VecGetArray(user_ptr->Dir,&x_ptr);
    254:   x_ptr[0] = 1.;
    255:   x_ptr[1] = 0.;
    256:   VecRestoreArray(user_ptr->Dir,&x_ptr);
    257:   Adjoint2(user_ptr->U,harr,user_ptr);
    258:   col      = 0;
    259:   MatSetValues(H,2,rows,1,&col,harr,INSERT_VALUES);

    261:   VecCopy(U,user_ptr->U);
    262:   VecGetArray(user_ptr->Dir,&x_ptr);
    263:   x_ptr[0] = 0.;
    264:   x_ptr[1] = 1.;
    265:   VecRestoreArray(user_ptr->Dir,&x_ptr);
    266:   Adjoint2(user_ptr->U,harr,user_ptr);
    267:   col      = 1;
    268:   MatSetValues(H,2,rows,1,&col,harr,INSERT_VALUES);

    270:   MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);
    271:   MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);
    272:   if (H != Hpre) {
    273:     MatAssemblyBegin(Hpre,MAT_FINAL_ASSEMBLY);
    274:     MatAssemblyEnd(Hpre,MAT_FINAL_ASSEMBLY);
    275:   }
    276:   return 0;
    277: }

    279: static PetscErrorCode MatrixFreeHessian(Tao tao,Vec U,Mat H,Mat Hpre,void *ctx)
    280: {
    281:   User           user_ptr = (User)ctx;

    284:   VecCopy(U,user_ptr->U);
    285:   return 0;
    286: }

    288: /* ------------ Routines calculating second-order derivatives -------------- */

    290: /*
    291:   Compute the Hessian-vector product for the cost function using Second-order adjoint
    292: */
    293: PetscErrorCode Adjoint2(Vec U,PetscScalar arr[],User ctx)
    294: {
    295:   TS             ts = ctx->ts;
    296:   PetscScalar    *x_ptr,*y_ptr;
    297:   Mat            tlmsen;

    300:   TSAdjointReset(ts);

    302:   TSSetTime(ts,0.0);
    303:   TSSetStepNumber(ts,0);
    304:   TSSetTimeStep(ts,0.001);
    305:   TSSetFromOptions(ts);
    306:   TSSetCostHessianProducts(ts,1,ctx->Lambda2,NULL,ctx->Dir);
    307:   TSAdjointSetForward(ts,NULL);
    308:   TSSolve(ts,U);

    310:   /* Set terminal conditions for first- and second-order adjonts */
    311:   VecGetArray(U,&x_ptr);
    312:   VecGetArray(ctx->Lambda[0],&y_ptr);
    313:   y_ptr[0] = 2.*(x_ptr[0]-ctx->ob[0]);
    314:   y_ptr[1] = 2.*(x_ptr[1]-ctx->ob[1]);
    315:   VecRestoreArray(ctx->Lambda[0],&y_ptr);
    316:   VecRestoreArray(U,&x_ptr);
    317:   TSForwardGetSensitivities(ts,NULL,&tlmsen);
    318:   MatDenseGetColumn(tlmsen,0,&x_ptr);
    319:   VecGetArray(ctx->Lambda2[0],&y_ptr);
    320:   y_ptr[0] = 2.*x_ptr[0];
    321:   y_ptr[1] = 2.*x_ptr[1];
    322:   VecRestoreArray(ctx->Lambda2[0],&y_ptr);
    323:   MatDenseRestoreColumn(tlmsen,&x_ptr);

    325:   TSSetCostGradients(ts,1,ctx->Lambda,NULL);
    326:   if (ctx->implicitform) {
    327:     TSSetIHessianProduct(ts,ctx->Ihp1,IHessianProductUU,NULL,NULL,NULL,NULL,NULL,NULL,ctx);
    328:   } else {
    329:     TSSetRHSHessianProduct(ts,ctx->Ihp1,RHSHessianProductUU,NULL,NULL,NULL,NULL,NULL,NULL,ctx);
    330:   }
    331:   TSAdjointSolve(ts);

    333:   VecGetArray(ctx->Lambda2[0],&x_ptr);
    334:   arr[0] = x_ptr[0];
    335:   arr[1] = x_ptr[1];
    336:   VecRestoreArray(ctx->Lambda2[0],&x_ptr);

    338:   TSAdjointReset(ts);
    339:   TSAdjointResetForward(ts);
    340:   return 0;
    341: }

    343: PetscErrorCode FiniteDiff(Vec U,PetscScalar arr[],User ctx)
    344: {
    345:   Vec               Up,G,Gp;
    346:   const PetscScalar eps = PetscRealConstant(1e-7);
    347:   PetscScalar       *u;
    348:   Tao               tao = NULL;
    349:   PetscReal         f;

    352:   VecDuplicate(U,&Up);
    353:   VecDuplicate(U,&G);
    354:   VecDuplicate(U,&Gp);

    356:   FormFunctionGradient(tao,U,&f,G,ctx);

    358:   VecCopy(U,Up);
    359:   VecGetArray(Up,&u);
    360:   u[0] += eps;
    361:   VecRestoreArray(Up,&u);
    362:   FormFunctionGradient(tao,Up,&f,Gp,ctx);
    363:   VecAXPY(Gp,-1,G);
    364:   VecScale(Gp,1./eps);
    365:   VecGetArray(Gp,&u);
    366:   arr[0] = u[0];
    367:   arr[1] = u[1];
    368:   VecRestoreArray(Gp,&u);

    370:   VecCopy(U,Up);
    371:   VecGetArray(Up,&u);
    372:   u[1] += eps;
    373:   VecRestoreArray(Up,&u);
    374:   FormFunctionGradient(tao,Up,&f,Gp,ctx);
    375:   VecAXPY(Gp,-1,G);
    376:   VecScale(Gp,1./eps);
    377:   VecGetArray(Gp,&u);
    378:   arr[2] = u[0];
    379:   arr[3] = u[1];
    380:   VecRestoreArray(Gp,&u);

    382:   VecDestroy(&G);
    383:   VecDestroy(&Gp);
    384:   VecDestroy(&Up);
    385:   return 0;
    386: }

    388: static PetscErrorCode HessianProductMat(Mat mat,Vec svec,Vec y)
    389: {
    390:   User           user_ptr;
    391:   PetscScalar    *y_ptr;

    394:   MatShellGetContext(mat,&user_ptr);
    395:   VecCopy(svec,user_ptr->Dir);
    396:   VecGetArray(y,&y_ptr);
    397:   Adjoint2(user_ptr->U,y_ptr,user_ptr);
    398:   VecRestoreArray(y,&y_ptr);
    399:   return 0;
    400: }

    402: int main(int argc,char **argv)
    403: {
    404:   PetscBool      monitor = PETSC_FALSE,mf = PETSC_TRUE;
    405:   PetscInt       mode = 0;
    406:   PetscMPIInt    size;
    407:   struct _n_User user;
    408:   Vec            x; /* working vector for TAO */
    409:   PetscScalar    *x_ptr,arr[4];
    410:   PetscScalar    ic1 = 2.2,ic2 = -0.7; /* initial guess for TAO */
    411:   Tao            tao;
    412:   KSP            ksp;
    413:   PC             pc;

    415:   /* Initialize program */
    416:   PetscInitialize(&argc,&argv,NULL,help);
    417:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

    420:   /* Set runtime options */
    421:   user.next_output  = 0.0;
    422:   user.mu           = 1.0e3;
    423:   user.steps        = 0;
    424:   user.ftime        = 0.5;
    425:   user.implicitform = PETSC_TRUE;

    427:   PetscOptionsGetBool(NULL,NULL,"-monitor",&monitor,NULL);
    428:   PetscOptionsGetReal(NULL,NULL,"-mu",&user.mu,NULL);
    429:   PetscOptionsGetInt(NULL,NULL,"-mode",&mode,NULL);
    430:   PetscOptionsGetReal(NULL,NULL,"-ic1",&ic1,NULL);
    431:   PetscOptionsGetReal(NULL,NULL,"-ic2",&ic2,NULL);
    432:   PetscOptionsGetBool(NULL,NULL,"-my_tao_mf",&mf,NULL); /* matrix-free hessian for optimization */
    433:   PetscOptionsGetBool(NULL,NULL,"-implicitform",&user.implicitform,NULL);

    435:   /* Create necessary matrix and vectors, solve same ODE on every process */
    436:   MatCreate(PETSC_COMM_WORLD,&user.A);
    437:   MatSetSizes(user.A,PETSC_DECIDE,PETSC_DECIDE,2,2);
    438:   MatSetFromOptions(user.A);
    439:   MatSetUp(user.A);
    440:   MatCreateVecs(user.A,&user.U,NULL);
    441:   MatCreateVecs(user.A,&user.Dir,NULL);
    442:   MatCreateVecs(user.A,&user.Lambda[0],NULL);
    443:   MatCreateVecs(user.A,&user.Lambda2[0],NULL);
    444:   MatCreateVecs(user.A,&user.Ihp1[0],NULL);

    446:   /* Create timestepping solver context */
    447:   TSCreate(PETSC_COMM_WORLD,&user.ts);
    448:   TSSetEquationType(user.ts,TS_EQ_ODE_EXPLICIT); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
    449:   if (user.implicitform) {
    450:     TSSetIFunction(user.ts,NULL,IFunction,&user);
    451:     TSSetIJacobian(user.ts,user.A,user.A,IJacobian,&user);
    452:     TSSetType(user.ts,TSCN);
    453:   } else {
    454:     TSSetRHSFunction(user.ts,NULL,RHSFunction,&user);
    455:     TSSetRHSJacobian(user.ts,user.A,user.A,RHSJacobian,&user);
    456:     TSSetType(user.ts,TSRK);
    457:   }
    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);

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

    474:   /* Obtain the observation */
    475:   TSSolve(user.ts,user.U);
    476:   VecGetArray(user.U,&x_ptr);
    477:   user.ob[0] = x_ptr[0];
    478:   user.ob[1] = x_ptr[1];
    479:   VecRestoreArray(user.U,&x_ptr);

    481:   VecDuplicate(user.U,&x);
    482:   VecGetArray(x,&x_ptr);
    483:   x_ptr[0] = ic1;
    484:   x_ptr[1] = ic2;
    485:   VecRestoreArray(x,&x_ptr);

    487:   /* Save trajectory of solution so that TSAdjointSolve() may be used */
    488:   TSSetSaveTrajectory(user.ts);

    490:   /* Compare finite difference and second-order adjoint. */
    491:   switch (mode) {
    492:     case 2 :
    493:       FiniteDiff(x,arr,&user);
    494:       PetscPrintf(PETSC_COMM_WORLD,"\n Finite difference approximation of the Hessian\n");
    495:       PetscPrintf(PETSC_COMM_WORLD,"%g %g\n%g %g\n",(double)arr[0],(double)arr[1],(double)arr[2],(double)arr[3]);
    496:       break;
    497:     case 1 : /* Compute the Hessian column by column */
    498:       VecCopy(x,user.U);
    499:       VecGetArray(user.Dir,&x_ptr);
    500:       x_ptr[0] = 1.;
    501:       x_ptr[1] = 0.;
    502:       VecRestoreArray(user.Dir,&x_ptr);
    503:       Adjoint2(user.U,arr,&user);
    504:       PetscPrintf(PETSC_COMM_WORLD,"\nFirst column of the Hessian\n");
    505:       PetscPrintf(PETSC_COMM_WORLD,"%g\n%g\n",(double)arr[0],(double)arr[1]);
    506:       VecCopy(x,user.U);
    507:       VecGetArray(user.Dir,&x_ptr);
    508:       x_ptr[0] = 0.;
    509:       x_ptr[1] = 1.;
    510:       VecRestoreArray(user.Dir,&x_ptr);
    511:       Adjoint2(user.U,arr,&user);
    512:       PetscPrintf(PETSC_COMM_WORLD,"\nSecond column of the Hessian\n");
    513:       PetscPrintf(PETSC_COMM_WORLD,"%g\n%g\n",(double)arr[0],(double)arr[1]);
    514:       break;
    515:     case 0 :
    516:       /* Create optimization context and set up */
    517:       TaoCreate(PETSC_COMM_WORLD,&tao);
    518:       TaoSetType(tao,TAOBLMVM);
    519:       TaoSetObjectiveAndGradient(tao,NULL,FormFunctionGradient,(void *)&user);

    521:       if (mf) {
    522:         MatCreateShell(PETSC_COMM_SELF,2,2,2,2,(void*)&user,&user.H);
    523:         MatShellSetOperation(user.H,MATOP_MULT,(void(*)(void))HessianProductMat);
    524:         MatSetOption(user.H,MAT_SYMMETRIC,PETSC_TRUE);
    525:         TaoSetHessian(tao,user.H,user.H,MatrixFreeHessian,(void *)&user);
    526:       } else { /* Create Hessian matrix */
    527:         MatCreate(PETSC_COMM_WORLD,&user.H);
    528:         MatSetSizes(user.H,PETSC_DECIDE,PETSC_DECIDE,2,2);
    529:         MatSetUp(user.H);
    530:         TaoSetHessian(tao,user.H,user.H,FormHessian,(void *)&user);
    531:       }

    533:       /* Not use any preconditioner */
    534:       TaoGetKSP(tao,&ksp);
    535:       if (ksp) {
    536:         KSPGetPC(ksp,&pc);
    537:         PCSetType(pc,PCNONE);
    538:       }

    540:       /* Set initial solution guess */
    541:       TaoSetSolution(tao,x);
    542:       TaoSetFromOptions(tao);
    543:       TaoSolve(tao);
    544:       TaoDestroy(&tao);
    545:       MatDestroy(&user.H);
    546:       break;
    547:     default:
    548:       break;
    549:   }

    551:   /* Free work space.  All PETSc objects should be destroyed when they are no longer needed. */
    552:   MatDestroy(&user.A);
    553:   VecDestroy(&user.U);
    554:   VecDestroy(&user.Lambda[0]);
    555:   VecDestroy(&user.Lambda2[0]);
    556:   VecDestroy(&user.Ihp1[0]);
    557:   VecDestroy(&user.Dir);
    558:   TSDestroy(&user.ts);
    559:   VecDestroy(&x);
    560:   PetscFinalize();
    561:   return 0;
    562: }

    564: /*TEST
    565:     build:
    566:       requires: !complex !single

    568:     test:
    569:       args:  -ts_type cn -viewer_binary_skip_info -tao_monitor -tao_view -mu 1000 -ts_dt 0.03125
    570:       output_file: output/ex20opt_ic_1.out

    572:     test:
    573:       suffix: 2
    574:       args:  -ts_type beuler -viewer_binary_skip_info -tao_monitor -tao_view -mu 100 -ts_dt 0.01 -tao_type bntr -tao_bnk_pc_type none
    575:       output_file: output/ex20opt_ic_2.out

    577:     test:
    578:       suffix: 3
    579:       args:  -ts_type cn -viewer_binary_skip_info -tao_monitor -tao_view -mu 100 -ts_dt 0.01 -tao_type bntr -tao_bnk_pc_type none
    580:       output_file: output/ex20opt_ic_3.out

    582:     test:
    583:       suffix: 4
    584:       args: -implicitform 0 -ts_dt 0.01 -ts_max_steps 2 -ts_rhs_jacobian_test_mult_transpose -mat_shell_test_mult_transpose_view -ts_rhs_jacobian_test_mult -mat_shell_test_mult_view -mode 1 -my_tao_mf
    585: TEST*/