Actual source code: ex20opt_p.c


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

  5: /* ------------------------------------------------------------------------

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

 16: typedef struct _n_User *User;
 17: struct _n_User {
 18:   TS        ts;
 19:   PetscReal mu;
 20:   PetscReal next_output;

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

 38: PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*);
 39: PetscErrorCode FormHessian(Tao,Vec,Mat,Mat,void*);
 40: PetscErrorCode Adjoint2(Vec,PetscScalar[],User);

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

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

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

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

 69:   VecGetArrayRead(U,&u);

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

 83:   VecRestoreArrayRead(U,&u);
 84:   return 0;
 85: }

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

 96:   VecGetArrayRead(U,&u);
 97:   VecGetArrayRead(Vl[0],&vl);
 98:   VecGetArrayRead(Vr,&vr);
 99:   VecGetArray(VHV[0],&vhv);

101:   dJdU[1][0][0] = -2.*user->mu*u[1];
102:   dJdU[1][1][0] = -2.*user->mu*u[0];
103:   dJdU[1][0][1] = -2.*user->mu*u[0];
104:   for (j=0; j<2; j++) {
105:     vhv[j] = 0;
106:     for (k=0; k<2; k++)
107:       for (i=0; i<2; i++)
108:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
109:   }

111:   VecRestoreArrayRead(U,&u);
112:   VecRestoreArrayRead(Vl[0],&vl);
113:   VecRestoreArrayRead(Vr,&vr);
114:   VecRestoreArray(VHV[0],&vhv);
115:   return 0;
116: }

118: static PetscErrorCode RHSHessianProductUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
119: {
120:   const PetscScalar *vl,*vr,*u;
121:   PetscScalar       *vhv;
122:   PetscScalar       dJdP[2][2][1]={{{0}}};
123:   PetscInt          i,j,k;

126:   VecGetArrayRead(U,&u);
127:   VecGetArrayRead(Vl[0],&vl);
128:   VecGetArrayRead(Vr,&vr);
129:   VecGetArray(VHV[0],&vhv);

131:   dJdP[1][0][0] = -(1.+2.*u[0]*u[1]);
132:   dJdP[1][1][0] = 1.-u[0]*u[0];
133:   for (j=0; j<2; j++) {
134:     vhv[j] = 0;
135:     for (k=0; k<1; k++)
136:       for (i=0; i<2; i++)
137:         vhv[j] += vl[i]*dJdP[i][j][k]*vr[k];
138:   }

140:   VecRestoreArrayRead(U,&u);
141:   VecRestoreArrayRead(Vl[0],&vl);
142:   VecRestoreArrayRead(Vr,&vr);
143:   VecRestoreArray(VHV[0],&vhv);
144:   return 0;
145: }

147: static PetscErrorCode RHSHessianProductPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
148: {
149:   const PetscScalar *vl,*vr,*u;
150:   PetscScalar       *vhv;
151:   PetscScalar       dJdU[2][1][2]={{{0}}};
152:   PetscInt          i,j,k;

155:   VecGetArrayRead(U,&u);
156:   VecGetArrayRead(Vl[0],&vl);
157:   VecGetArrayRead(Vr,&vr);
158:   VecGetArray(VHV[0],&vhv);

160:   dJdU[1][0][0] = -1.-2.*u[1]*u[0];
161:   dJdU[1][0][1] = 1.-u[0]*u[0];
162:   for (j=0; j<1; j++) {
163:     vhv[j] = 0;
164:     for (k=0; k<2; k++)
165:       for (i=0; i<2; i++)
166:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
167:   }

169:   VecRestoreArrayRead(U,&u);
170:   VecRestoreArrayRead(Vl[0],&vl);
171:   VecRestoreArrayRead(Vr,&vr);
172:   VecRestoreArray(VHV[0],&vhv);
173:   return 0;
174: }

176: static PetscErrorCode RHSHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
177: {
179:   return 0;
180: }

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

184: static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,void *ctx)
185: {
186:   User              user = (User)ctx;
187:   PetscScalar       *f;
188:   const PetscScalar *u,*udot;

191:   VecGetArrayRead(U,&u);
192:   VecGetArrayRead(Udot,&udot);
193:   VecGetArray(F,&f);

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

198:   VecRestoreArrayRead(U,&u);
199:   VecRestoreArrayRead(Udot,&udot);
200:   VecRestoreArray(F,&f);
201:   return 0;
202: }

204: static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,void *ctx)
205: {
206:   User              user     = (User)ctx;
207:   PetscInt          rowcol[] = {0,1};
208:   PetscScalar       J[2][2];
209:   const PetscScalar *u;

212:   VecGetArrayRead(U,&u);

214:   J[0][0] = a;     J[0][1] =  -1.0;
215:   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]);
216:   MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
217:   VecRestoreArrayRead(U,&u);
218:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
219:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
220:   if (A != B) {
221:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
222:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
223:   }

225:   VecRestoreArrayRead(U,&u);
226:   return 0;
227: }

229: static PetscErrorCode RHSJacobianP(TS ts,PetscReal t,Vec U,Mat A,void *ctx)
230: {
231:   PetscInt          row[] = {0,1},col[]={0};
232:   PetscScalar       J[2][1];
233:   const PetscScalar *u;

236:   VecGetArrayRead(U,&u);

238:   J[0][0] = 0;
239:   J[1][0] = (1.-u[0]*u[0])*u[1]-u[0];
240:   MatSetValues(A,2,row,1,col,&J[0][0],INSERT_VALUES);
241:   VecRestoreArrayRead(U,&u);
242:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
243:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);

245:   VecRestoreArrayRead(U,&u);
246:   return 0;
247: }

249: static PetscErrorCode IHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
250: {
251:   const PetscScalar *vl,*vr,*u;
252:   PetscScalar       *vhv;
253:   PetscScalar       dJdU[2][2][2]={{{0}}};
254:   PetscInt          i,j,k;
255:   User              user = (User)ctx;

258:   VecGetArrayRead(U,&u);
259:   VecGetArrayRead(Vl[0],&vl);
260:   VecGetArrayRead(Vr,&vr);
261:   VecGetArray(VHV[0],&vhv);

263:   dJdU[1][0][0] = 2.*user->mu*u[1];
264:   dJdU[1][1][0] = 2.*user->mu*u[0];
265:   dJdU[1][0][1] = 2.*user->mu*u[0];
266:   for (j=0; j<2; j++) {
267:     vhv[j] = 0;
268:     for (k=0; k<2; k++)
269:       for (i=0; i<2; i++)
270:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
271:   }

273:   VecRestoreArrayRead(U,&u);
274:   VecRestoreArrayRead(Vl[0],&vl);
275:   VecRestoreArrayRead(Vr,&vr);
276:   VecRestoreArray(VHV[0],&vhv);
277:   return 0;
278: }

280: static PetscErrorCode IHessianProductUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
281: {
282:   const PetscScalar *vl,*vr,*u;
283:   PetscScalar       *vhv;
284:   PetscScalar       dJdP[2][2][1]={{{0}}};
285:   PetscInt          i,j,k;

288:   VecGetArrayRead(U,&u);
289:   VecGetArrayRead(Vl[0],&vl);
290:   VecGetArrayRead(Vr,&vr);
291:   VecGetArray(VHV[0],&vhv);

293:   dJdP[1][0][0] = 1.+2.*u[0]*u[1];
294:   dJdP[1][1][0] = u[0]*u[0]-1.;
295:   for (j=0; j<2; j++) {
296:     vhv[j] = 0;
297:     for (k=0; k<1; k++)
298:       for (i=0; i<2; i++)
299:         vhv[j] += vl[i]*dJdP[i][j][k]*vr[k];
300:   }

302:   VecRestoreArrayRead(U,&u);
303:   VecRestoreArrayRead(Vl[0],&vl);
304:   VecRestoreArrayRead(Vr,&vr);
305:   VecRestoreArray(VHV[0],&vhv);
306:   return 0;
307: }

309: static PetscErrorCode IHessianProductPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
310: {
311:   const PetscScalar *vl,*vr,*u;
312:   PetscScalar       *vhv;
313:   PetscScalar       dJdU[2][1][2]={{{0}}};
314:   PetscInt          i,j,k;

317:   VecGetArrayRead(U,&u);
318:   VecGetArrayRead(Vl[0],&vl);
319:   VecGetArrayRead(Vr,&vr);
320:   VecGetArray(VHV[0],&vhv);

322:   dJdU[1][0][0] = 1.+2.*u[1]*u[0];
323:   dJdU[1][0][1] = u[0]*u[0]-1.;
324:   for (j=0; j<1; j++) {
325:     vhv[j] = 0;
326:     for (k=0; k<2; k++)
327:       for (i=0; i<2; i++)
328:         vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
329:   }

331:   VecRestoreArrayRead(U,&u);
332:   VecRestoreArrayRead(Vl[0],&vl);
333:   VecRestoreArrayRead(Vr,&vr);
334:   VecRestoreArray(VHV[0],&vhv);
335:   return 0;
336: }

338: static PetscErrorCode IHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
339: {
341:   return 0;
342: }

344: /* Monitor timesteps and use interpolation to output at integer multiples of 0.1 */
345: static PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal t,Vec X,void *ctx)
346: {
347:   PetscErrorCode    ierr;
348:   const PetscScalar *x;
349:   PetscReal         tfinal, dt;
350:   User              user = (User)ctx;
351:   Vec               interpolatedX;

354:   TSGetTimeStep(ts,&dt);
355:   TSGetMaxTime(ts,&tfinal);

357:   while (user->next_output <= t && user->next_output <= tfinal) {
358:     VecDuplicate(X,&interpolatedX);
359:     TSInterpolate(ts,user->next_output,interpolatedX);
360:     VecGetArrayRead(interpolatedX,&x);
361:     PetscPrintf(PETSC_COMM_WORLD,"[%g] %D TS %g (dt = %g) X %g %g\n",
362:                        (double)user->next_output,step,(double)t,(double)dt,(double)PetscRealPart(x[0]),
363:                        (double)PetscRealPart(x[1]));
364:     VecRestoreArrayRead(interpolatedX,&x);
365:     VecDestroy(&interpolatedX);
366:     user->next_output += PetscRealConstant(0.1);
367:   }
368:   return 0;
369: }

371: int main(int argc,char **argv)
372: {
373:   Vec                P;
374:   PetscBool          monitor = PETSC_FALSE;
375:   PetscScalar        *x_ptr;
376:   const PetscScalar  *y_ptr;
377:   PetscMPIInt        size;
378:   struct _n_User     user;
379:   Tao                tao;
380:   KSP                ksp;
381:   PC                 pc;

383:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
384:      Initialize program
385:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
386:   PetscInitialize(&argc,&argv,NULL,help);
387:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

390:   /* Create TAO solver and set desired solution method */
391:   TaoCreate(PETSC_COMM_WORLD,&tao);
392:   TaoSetType(tao,TAOBQNLS);

394:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
395:     Set runtime options
396:     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
397:   user.next_output  = 0.0;
398:   user.mu           = PetscRealConstant(1.0e3);
399:   user.ftime        = PetscRealConstant(0.5);
400:   user.implicitform = PETSC_TRUE;

402:   PetscOptionsGetBool(NULL,NULL,"-monitor",&monitor,NULL);
403:   PetscOptionsGetReal(NULL,NULL,"-mu",&user.mu,NULL);
404:   PetscOptionsGetBool(NULL,NULL,"-implicitform",&user.implicitform,NULL);

406:   /* Create necessary matrix and vectors, solve same ODE on every process */
407:   MatCreate(PETSC_COMM_WORLD,&user.A);
408:   MatSetSizes(user.A,PETSC_DECIDE,PETSC_DECIDE,2,2);
409:   MatSetFromOptions(user.A);
410:   MatSetUp(user.A);
411:   MatCreateVecs(user.A,&user.U,NULL);
412:   MatCreateVecs(user.A,&user.Lambda[0],NULL);
413:   MatCreateVecs(user.A,&user.Lambda2[0],NULL);
414:   MatCreateVecs(user.A,&user.Ihp1[0],NULL);
415:   MatCreateVecs(user.A,&user.Ihp2[0],NULL);

417:   MatCreate(PETSC_COMM_WORLD,&user.Jacp);
418:   MatSetSizes(user.Jacp,PETSC_DECIDE,PETSC_DECIDE,2,1);
419:   MatSetFromOptions(user.Jacp);
420:   MatSetUp(user.Jacp);
421:   MatCreateVecs(user.Jacp,&user.Dir,NULL);
422:   MatCreateVecs(user.Jacp,&user.Mup[0],NULL);
423:   MatCreateVecs(user.Jacp,&user.Mup2[0],NULL);
424:   MatCreateVecs(user.Jacp,&user.Ihp3[0],NULL);
425:   MatCreateVecs(user.Jacp,&user.Ihp4[0],NULL);

427:   /* Create timestepping solver context */
428:   TSCreate(PETSC_COMM_WORLD,&user.ts);
429:   TSSetEquationType(user.ts,TS_EQ_ODE_EXPLICIT); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
430:   if (user.implicitform) {
431:     TSSetIFunction(user.ts,NULL,IFunction,&user);
432:     TSSetIJacobian(user.ts,user.A,user.A,IJacobian,&user);
433:     TSSetType(user.ts,TSCN);
434:   } else {
435:     TSSetRHSFunction(user.ts,NULL,RHSFunction,&user);
436:     TSSetRHSJacobian(user.ts,user.A,user.A,RHSJacobian,&user);
437:     TSSetType(user.ts,TSRK);
438:   }
439:   TSSetRHSJacobianP(user.ts,user.Jacp,RHSJacobianP,&user);
440:   TSSetMaxTime(user.ts,user.ftime);
441:   TSSetExactFinalTime(user.ts,TS_EXACTFINALTIME_MATCHSTEP);

443:   if (monitor) {
444:     TSMonitorSet(user.ts,Monitor,&user,NULL);
445:   }

447:   /* Set ODE initial conditions */
448:   VecGetArray(user.U,&x_ptr);
449:   x_ptr[0] = 2.0;
450:   x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user.mu) - 292.0/(2187.0*user.mu*user.mu);
451:   VecRestoreArray(user.U,&x_ptr);
452:   TSSetTimeStep(user.ts,PetscRealConstant(0.001));

454:   /* Set runtime options */
455:   TSSetFromOptions(user.ts);

457:   TSSolve(user.ts,user.U);
458:   VecGetArrayRead(user.U,&y_ptr);
459:   user.ob[0] = y_ptr[0];
460:   user.ob[1] = y_ptr[1];
461:   VecRestoreArrayRead(user.U,&y_ptr);

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

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

473:   /* Set initial solution guess */
474:   MatCreateVecs(user.Jacp,&P,NULL);
475:   VecGetArray(P,&x_ptr);
476:   x_ptr[0] = PetscRealConstant(1.2);
477:   VecRestoreArray(P,&x_ptr);
478:   TaoSetSolution(tao,P);

480:   /* Set routine for function and gradient evaluation */
481:   TaoSetObjectiveAndGradient(tao,NULL,FormFunctionGradient,(void *)&user);
482:   TaoSetHessian(tao,user.H,user.H,FormHessian,(void *)&user);

484:   /* Check for any TAO command line options */
485:   TaoGetKSP(tao,&ksp);
486:   if (ksp) {
487:     KSPGetPC(ksp,&pc);
488:     PCSetType(pc,PCNONE);
489:   }
490:   TaoSetFromOptions(tao);

492:   TaoSolve(tao);

494:   VecView(P,PETSC_VIEWER_STDOUT_WORLD);
495:   /* Free TAO data structures */
496:   TaoDestroy(&tao);

498:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
499:      Free work space.  All PETSc objects should be destroyed when they
500:      are no longer needed.
501:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
502:   MatDestroy(&user.H);
503:   MatDestroy(&user.A);
504:   VecDestroy(&user.U);
505:   MatDestroy(&user.Jacp);
506:   VecDestroy(&user.Lambda[0]);
507:   VecDestroy(&user.Mup[0]);
508:   VecDestroy(&user.Lambda2[0]);
509:   VecDestroy(&user.Mup2[0]);
510:   VecDestroy(&user.Ihp1[0]);
511:   VecDestroy(&user.Ihp2[0]);
512:   VecDestroy(&user.Ihp3[0]);
513:   VecDestroy(&user.Ihp4[0]);
514:   VecDestroy(&user.Dir);
515:   TSDestroy(&user.ts);
516:   VecDestroy(&P);
517:   PetscFinalize();
518:   return 0;
519: }

521: /* ------------------------------------------------------------------ */
522: /*
523:    FormFunctionGradient - Evaluates the function and corresponding gradient.

525:    Input Parameters:
526:    tao - the Tao context
527:    X   - the input vector
528:    ptr - optional user-defined context, as set by TaoSetObjectiveAndGradient()

530:    Output Parameters:
531:    f   - the newly evaluated function
532:    G   - the newly evaluated gradient
533: */
534: PetscErrorCode FormFunctionGradient(Tao tao,Vec P,PetscReal *f,Vec G,void *ctx)
535: {
536:   User              user_ptr = (User)ctx;
537:   TS                ts = user_ptr->ts;
538:   PetscScalar       *x_ptr,*g;
539:   const PetscScalar *y_ptr;

542:   VecGetArrayRead(P,&y_ptr);
543:   user_ptr->mu = y_ptr[0];
544:   VecRestoreArrayRead(P,&y_ptr);

546:   TSSetTime(ts,0.0);
547:   TSSetStepNumber(ts,0);
548:   TSSetTimeStep(ts,PetscRealConstant(0.001)); /* can be overwritten by command line options */
549:   TSSetFromOptions(ts);
550:   VecGetArray(user_ptr->U,&x_ptr);
551:   x_ptr[0] = 2.0;
552:   x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user_ptr->mu) - 292.0/(2187.0*user_ptr->mu*user_ptr->mu);
553:   VecRestoreArray(user_ptr->U,&x_ptr);

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

557:   VecGetArrayRead(user_ptr->U,&y_ptr);
558:   *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]);

560:   /*   Reset initial conditions for the adjoint integration */
561:   VecGetArray(user_ptr->Lambda[0],&x_ptr);
562:   x_ptr[0] = 2.*(y_ptr[0]-user_ptr->ob[0]);
563:   x_ptr[1] = 2.*(y_ptr[1]-user_ptr->ob[1]);
564:   VecRestoreArrayRead(user_ptr->U,&y_ptr);
565:   VecRestoreArray(user_ptr->Lambda[0],&x_ptr);

567:   VecGetArray(user_ptr->Mup[0],&x_ptr);
568:   x_ptr[0] = 0.0;
569:   VecRestoreArray(user_ptr->Mup[0],&x_ptr);
570:   TSSetCostGradients(ts,1,user_ptr->Lambda,user_ptr->Mup);

572:   TSAdjointSolve(ts);

574:   VecGetArray(user_ptr->Mup[0],&x_ptr);
575:   VecGetArrayRead(user_ptr->Lambda[0],&y_ptr);
576:   VecGetArray(G,&g);
577:   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];
578:   VecRestoreArray(user_ptr->Mup[0],&x_ptr);
579:   VecRestoreArrayRead(user_ptr->Lambda[0],&y_ptr);
580:   VecRestoreArray(G,&g);
581:   return 0;
582: }

584: PetscErrorCode FormHessian(Tao tao,Vec P,Mat H,Mat Hpre,void *ctx)
585: {
586:   User           user_ptr = (User)ctx;
587:   PetscScalar    harr[1];
588:   const PetscInt rows[1] = {0};
589:   PetscInt       col = 0;

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

595:   MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);
596:   MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);
597:   if (H != Hpre) {
598:     MatAssemblyBegin(Hpre,MAT_FINAL_ASSEMBLY);
599:     MatAssemblyEnd(Hpre,MAT_FINAL_ASSEMBLY);
600:   }
601:   return 0;
602: }

604: PetscErrorCode Adjoint2(Vec P,PetscScalar arr[],User ctx)
605: {
606:   TS                ts = ctx->ts;
607:   const PetscScalar *z_ptr;
608:   PetscScalar       *x_ptr,*y_ptr,dzdp,dzdp2;
609:   Mat               tlmsen;

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

615:   /* The directional vector should be 1 since it is one-dimensional */
616:   VecGetArray(ctx->Dir,&x_ptr);
617:   x_ptr[0] = 1.;
618:   VecRestoreArray(ctx->Dir,&x_ptr);

620:   VecGetArrayRead(P,&z_ptr);
621:   ctx->mu = z_ptr[0];
622:   VecRestoreArrayRead(P,&z_ptr);

624:   dzdp  = -10.0/(81.0*ctx->mu*ctx->mu) + 2.0*292.0/(2187.0*ctx->mu*ctx->mu*ctx->mu);
625:   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);

627:   TSSetTime(ts,0.0);
628:   TSSetStepNumber(ts,0);
629:   TSSetTimeStep(ts,PetscRealConstant(0.001)); /* can be overwritten by command line options */
630:   TSSetFromOptions(ts);
631:   TSSetCostHessianProducts(ts,1,ctx->Lambda2,ctx->Mup2,ctx->Dir);

633:   MatZeroEntries(ctx->Jacp);
634:   MatSetValue(ctx->Jacp,1,0,dzdp,INSERT_VALUES);
635:   MatAssemblyBegin(ctx->Jacp,MAT_FINAL_ASSEMBLY);
636:   MatAssemblyEnd(ctx->Jacp,MAT_FINAL_ASSEMBLY);

638:   TSAdjointSetForward(ts,ctx->Jacp);
639:   VecGetArray(ctx->U,&y_ptr);
640:   y_ptr[0] = 2.0;
641:   y_ptr[1] = -2.0/3.0 + 10.0/(81.0*ctx->mu) - 292.0/(2187.0*ctx->mu*ctx->mu);
642:   VecRestoreArray(ctx->U,&y_ptr);
643:   TSSolve(ts,ctx->U);

645:   /* Set terminal conditions for first- and second-order adjonts */
646:   VecGetArrayRead(ctx->U,&z_ptr);
647:   VecGetArray(ctx->Lambda[0],&y_ptr);
648:   y_ptr[0] = 2.*(z_ptr[0]-ctx->ob[0]);
649:   y_ptr[1] = 2.*(z_ptr[1]-ctx->ob[1]);
650:   VecRestoreArray(ctx->Lambda[0],&y_ptr);
651:   VecRestoreArrayRead(ctx->U,&z_ptr);
652:   VecGetArray(ctx->Mup[0],&y_ptr);
653:   y_ptr[0] = 0.0;
654:   VecRestoreArray(ctx->Mup[0],&y_ptr);
655:   TSForwardGetSensitivities(ts,NULL,&tlmsen);
656:   MatDenseGetColumn(tlmsen,0,&x_ptr);
657:   VecGetArray(ctx->Lambda2[0],&y_ptr);
658:   y_ptr[0] = 2.*x_ptr[0];
659:   y_ptr[1] = 2.*x_ptr[1];
660:   VecRestoreArray(ctx->Lambda2[0],&y_ptr);
661:   VecGetArray(ctx->Mup2[0],&y_ptr);
662:   y_ptr[0] = 0.0;
663:   VecRestoreArray(ctx->Mup2[0],&y_ptr);
664:   MatDenseRestoreColumn(tlmsen,&x_ptr);
665:   TSSetCostGradients(ts,1,ctx->Lambda,ctx->Mup);
666:   if (ctx->implicitform) {
667:     TSSetIHessianProduct(ts,ctx->Ihp1,IHessianProductUU,ctx->Ihp2,IHessianProductUP,ctx->Ihp3,IHessianProductPU,ctx->Ihp4,IHessianProductPP,ctx);
668:   } else {
669:     TSSetRHSHessianProduct(ts,ctx->Ihp1,RHSHessianProductUU,ctx->Ihp2,RHSHessianProductUP,ctx->Ihp3,RHSHessianProductPU,ctx->Ihp4,RHSHessianProductPP,ctx);
670:   }
671:   TSAdjointSolve(ts);

673:   VecGetArray(ctx->Lambda[0],&x_ptr);
674:   VecGetArray(ctx->Lambda2[0],&y_ptr);
675:   VecGetArrayRead(ctx->Mup2[0],&z_ptr);

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

679:   VecRestoreArray(ctx->Lambda2[0],&x_ptr);
680:   VecRestoreArray(ctx->Lambda2[0],&y_ptr);
681:   VecRestoreArrayRead(ctx->Mup2[0],&z_ptr);

683:   /* Disable second-order adjoint mode */
684:   TSAdjointReset(ts);
685:   TSAdjointResetForward(ts);
686:   return 0;
687: }

689: /*TEST
690:     build:
691:       requires: !complex !single
692:     test:
693:       args:  -implicitform 0 -ts_type rk -ts_adapt_type none -mu 10 -ts_dt 0.1 -viewer_binary_skip_info -tao_monitor -tao_view
694:       output_file: output/ex20opt_p_1.out

696:     test:
697:       suffix: 2
698:       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
699:       output_file: output/ex20opt_p_2.out

701:     test:
702:       suffix: 3
703:       args:  -ts_type cn -ts_adapt_type none -mu 100 -ts_dt 0.01 -viewer_binary_skip_info -tao_monitor -tao_view
704:       output_file: output/ex20opt_p_3.out

706:     test:
707:       suffix: 4
708:       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
709:       output_file: output/ex20opt_p_4.out

711: TEST*/