xref: /petsc/src/ts/tutorials/ex20opt_p.c (revision b0c0aa2b402794874120526435a0fac3e9105b95)
1 
2 static char help[] = "Solves the van der Pol equation.\n\
3 Input parameters include:\n";
4 
5 /* ------------------------------------------------------------------------
6 
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>
15 
16 typedef struct _n_User *User;
17 struct _n_User {
18   TS        ts;
19   PetscReal mu;
20   PetscReal next_output;
21 
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 };
37 
38 PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*);
39 PetscErrorCode FormHessian(Tao,Vec,Mat,Mat,void*);
40 PetscErrorCode Adjoint2(Vec,PetscScalar[],User);
41 
42 /* ----------------------- Explicit form of the ODE  -------------------- */
43 
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;
49 
50   PetscFunctionBeginUser;
51   PetscCall(VecGetArrayRead(U,&u));
52   PetscCall(VecGetArray(F,&f));
53   f[0] = u[1];
54   f[1] = user->mu*((1.-u[0]*u[0])*u[1]-u[0]);
55   PetscCall(VecRestoreArrayRead(U,&u));
56   PetscCall(VecRestoreArray(F,&f));
57   PetscFunctionReturn(0);
58 }
59 
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;
67 
68   PetscFunctionBeginUser;
69   PetscCall(VecGetArrayRead(U,&u));
70 
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   PetscCall(MatSetValues(A,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES));
76   PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
77   PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
78   if (B && A != B) {
79     PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY));
80     PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY));
81   }
82 
83   PetscCall(VecRestoreArrayRead(U,&u));
84   PetscFunctionReturn(0);
85 }
86 
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;
94 
95   PetscFunctionBeginUser;
96   PetscCall(VecGetArrayRead(U,&u));
97   PetscCall(VecGetArrayRead(Vl[0],&vl));
98   PetscCall(VecGetArrayRead(Vr,&vr));
99   PetscCall(VecGetArray(VHV[0],&vhv));
100 
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   }
110 
111   PetscCall(VecRestoreArrayRead(U,&u));
112   PetscCall(VecRestoreArrayRead(Vl[0],&vl));
113   PetscCall(VecRestoreArrayRead(Vr,&vr));
114   PetscCall(VecRestoreArray(VHV[0],&vhv));
115   PetscFunctionReturn(0);
116 }
117 
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;
124 
125   PetscFunctionBeginUser;
126   PetscCall(VecGetArrayRead(U,&u));
127   PetscCall(VecGetArrayRead(Vl[0],&vl));
128   PetscCall(VecGetArrayRead(Vr,&vr));
129   PetscCall(VecGetArray(VHV[0],&vhv));
130 
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   }
139 
140   PetscCall(VecRestoreArrayRead(U,&u));
141   PetscCall(VecRestoreArrayRead(Vl[0],&vl));
142   PetscCall(VecRestoreArrayRead(Vr,&vr));
143   PetscCall(VecRestoreArray(VHV[0],&vhv));
144   PetscFunctionReturn(0);
145 }
146 
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;
153 
154   PetscFunctionBeginUser;
155   PetscCall(VecGetArrayRead(U,&u));
156   PetscCall(VecGetArrayRead(Vl[0],&vl));
157   PetscCall(VecGetArrayRead(Vr,&vr));
158   PetscCall(VecGetArray(VHV[0],&vhv));
159 
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   }
168 
169   PetscCall(VecRestoreArrayRead(U,&u));
170   PetscCall(VecRestoreArrayRead(Vl[0],&vl));
171   PetscCall(VecRestoreArrayRead(Vr,&vr));
172   PetscCall(VecRestoreArray(VHV[0],&vhv));
173   PetscFunctionReturn(0);
174 }
175 
176 static PetscErrorCode RHSHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
177 {
178   PetscFunctionBeginUser;
179   PetscFunctionReturn(0);
180 }
181 
182 /* ----------------------- Implicit form of the ODE  -------------------- */
183 
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;
189 
190   PetscFunctionBeginUser;
191   PetscCall(VecGetArrayRead(U,&u));
192   PetscCall(VecGetArrayRead(Udot,&udot));
193   PetscCall(VecGetArray(F,&f));
194 
195   f[0] = udot[0] - u[1];
196   f[1] = udot[1] - user->mu*((1.0-u[0]*u[0])*u[1] - u[0]) ;
197 
198   PetscCall(VecRestoreArrayRead(U,&u));
199   PetscCall(VecRestoreArrayRead(Udot,&udot));
200   PetscCall(VecRestoreArray(F,&f));
201   PetscFunctionReturn(0);
202 }
203 
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;
210 
211   PetscFunctionBeginUser;
212   PetscCall(VecGetArrayRead(U,&u));
213 
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   PetscCall(MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES));
217   PetscCall(VecRestoreArrayRead(U,&u));
218   PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
219   PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
220   if (A != B) {
221     PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY));
222     PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY));
223   }
224 
225   PetscCall(VecRestoreArrayRead(U,&u));
226   PetscFunctionReturn(0);
227 }
228 
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;
234 
235   PetscFunctionBeginUser;
236   PetscCall(VecGetArrayRead(U,&u));
237 
238   J[0][0] = 0;
239   J[1][0] = (1.-u[0]*u[0])*u[1]-u[0];
240   PetscCall(MatSetValues(A,2,row,1,col,&J[0][0],INSERT_VALUES));
241   PetscCall(VecRestoreArrayRead(U,&u));
242   PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
243   PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
244 
245   PetscCall(VecRestoreArrayRead(U,&u));
246   PetscFunctionReturn(0);
247 }
248 
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;
256 
257   PetscFunctionBeginUser;
258   PetscCall(VecGetArrayRead(U,&u));
259   PetscCall(VecGetArrayRead(Vl[0],&vl));
260   PetscCall(VecGetArrayRead(Vr,&vr));
261   PetscCall(VecGetArray(VHV[0],&vhv));
262 
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   }
272 
273   PetscCall(VecRestoreArrayRead(U,&u));
274   PetscCall(VecRestoreArrayRead(Vl[0],&vl));
275   PetscCall(VecRestoreArrayRead(Vr,&vr));
276   PetscCall(VecRestoreArray(VHV[0],&vhv));
277   PetscFunctionReturn(0);
278 }
279 
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;
286 
287   PetscFunctionBeginUser;
288   PetscCall(VecGetArrayRead(U,&u));
289   PetscCall(VecGetArrayRead(Vl[0],&vl));
290   PetscCall(VecGetArrayRead(Vr,&vr));
291   PetscCall(VecGetArray(VHV[0],&vhv));
292 
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   }
301 
302   PetscCall(VecRestoreArrayRead(U,&u));
303   PetscCall(VecRestoreArrayRead(Vl[0],&vl));
304   PetscCall(VecRestoreArrayRead(Vr,&vr));
305   PetscCall(VecRestoreArray(VHV[0],&vhv));
306   PetscFunctionReturn(0);
307 }
308 
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;
315 
316   PetscFunctionBeginUser;
317   PetscCall(VecGetArrayRead(U,&u));
318   PetscCall(VecGetArrayRead(Vl[0],&vl));
319   PetscCall(VecGetArrayRead(Vr,&vr));
320   PetscCall(VecGetArray(VHV[0],&vhv));
321 
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   }
330 
331   PetscCall(VecRestoreArrayRead(U,&u));
332   PetscCall(VecRestoreArrayRead(Vl[0],&vl));
333   PetscCall(VecRestoreArrayRead(Vr,&vr));
334   PetscCall(VecRestoreArray(VHV[0],&vhv));
335   PetscFunctionReturn(0);
336 }
337 
338 static PetscErrorCode IHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
339 {
340   PetscFunctionBeginUser;
341   PetscFunctionReturn(0);
342 }
343 
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   const PetscScalar *x;
348   PetscReal         tfinal, dt;
349   User              user = (User)ctx;
350   Vec               interpolatedX;
351 
352   PetscFunctionBeginUser;
353   PetscCall(TSGetTimeStep(ts,&dt));
354   PetscCall(TSGetMaxTime(ts,&tfinal));
355 
356   while (user->next_output <= t && user->next_output <= tfinal) {
357     PetscCall(VecDuplicate(X,&interpolatedX));
358     PetscCall(TSInterpolate(ts,user->next_output,interpolatedX));
359     PetscCall(VecGetArrayRead(interpolatedX,&x));
360     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"[%g] %" PetscInt_FMT " TS %g (dt = %g) X %g %g\n",
361                           (double)user->next_output,step,(double)t,(double)dt,
362                           (double)PetscRealPart(x[0]),(double)PetscRealPart(x[1])));
363     PetscCall(VecRestoreArrayRead(interpolatedX,&x));
364     PetscCall(VecDestroy(&interpolatedX));
365     user->next_output += PetscRealConstant(0.1);
366   }
367   PetscFunctionReturn(0);
368 }
369 
370 int main(int argc,char **argv)
371 {
372   Vec                P;
373   PetscBool          monitor = PETSC_FALSE;
374   PetscScalar        *x_ptr;
375   const PetscScalar  *y_ptr;
376   PetscMPIInt        size;
377   struct _n_User     user;
378   Tao                tao;
379   KSP                ksp;
380   PC                 pc;
381 
382   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
383      Initialize program
384      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
385   PetscFunctionBeginUser;
386   PetscCall(PetscInitialize(&argc,&argv,NULL,help));
387   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
388   PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"This is a uniprocessor example only!");
389 
390   /* Create TAO solver and set desired solution method */
391   PetscCall(TaoCreate(PETSC_COMM_WORLD,&tao));
392   PetscCall(TaoSetType(tao,TAOBQNLS));
393 
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;
401 
402   PetscCall(PetscOptionsGetBool(NULL,NULL,"-monitor",&monitor,NULL));
403   PetscCall(PetscOptionsGetReal(NULL,NULL,"-mu",&user.mu,NULL));
404   PetscCall(PetscOptionsGetBool(NULL,NULL,"-implicitform",&user.implicitform,NULL));
405 
406   /* Create necessary matrix and vectors, solve same ODE on every process */
407   PetscCall(MatCreate(PETSC_COMM_WORLD,&user.A));
408   PetscCall(MatSetSizes(user.A,PETSC_DECIDE,PETSC_DECIDE,2,2));
409   PetscCall(MatSetFromOptions(user.A));
410   PetscCall(MatSetUp(user.A));
411   PetscCall(MatCreateVecs(user.A,&user.U,NULL));
412   PetscCall(MatCreateVecs(user.A,&user.Lambda[0],NULL));
413   PetscCall(MatCreateVecs(user.A,&user.Lambda2[0],NULL));
414   PetscCall(MatCreateVecs(user.A,&user.Ihp1[0],NULL));
415   PetscCall(MatCreateVecs(user.A,&user.Ihp2[0],NULL));
416 
417   PetscCall(MatCreate(PETSC_COMM_WORLD,&user.Jacp));
418   PetscCall(MatSetSizes(user.Jacp,PETSC_DECIDE,PETSC_DECIDE,2,1));
419   PetscCall(MatSetFromOptions(user.Jacp));
420   PetscCall(MatSetUp(user.Jacp));
421   PetscCall(MatCreateVecs(user.Jacp,&user.Dir,NULL));
422   PetscCall(MatCreateVecs(user.Jacp,&user.Mup[0],NULL));
423   PetscCall(MatCreateVecs(user.Jacp,&user.Mup2[0],NULL));
424   PetscCall(MatCreateVecs(user.Jacp,&user.Ihp3[0],NULL));
425   PetscCall(MatCreateVecs(user.Jacp,&user.Ihp4[0],NULL));
426 
427   /* Create timestepping solver context */
428   PetscCall(TSCreate(PETSC_COMM_WORLD,&user.ts));
429   PetscCall(TSSetEquationType(user.ts,TS_EQ_ODE_EXPLICIT)); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
430   if (user.implicitform) {
431     PetscCall(TSSetIFunction(user.ts,NULL,IFunction,&user));
432     PetscCall(TSSetIJacobian(user.ts,user.A,user.A,IJacobian,&user));
433     PetscCall(TSSetType(user.ts,TSCN));
434   } else {
435     PetscCall(TSSetRHSFunction(user.ts,NULL,RHSFunction,&user));
436     PetscCall(TSSetRHSJacobian(user.ts,user.A,user.A,RHSJacobian,&user));
437     PetscCall(TSSetType(user.ts,TSRK));
438   }
439   PetscCall(TSSetRHSJacobianP(user.ts,user.Jacp,RHSJacobianP,&user));
440   PetscCall(TSSetMaxTime(user.ts,user.ftime));
441   PetscCall(TSSetExactFinalTime(user.ts,TS_EXACTFINALTIME_MATCHSTEP));
442 
443   if (monitor) {
444     PetscCall(TSMonitorSet(user.ts,Monitor,&user,NULL));
445   }
446 
447   /* Set ODE initial conditions */
448   PetscCall(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   PetscCall(VecRestoreArray(user.U,&x_ptr));
452   PetscCall(TSSetTimeStep(user.ts,PetscRealConstant(0.001)));
453 
454   /* Set runtime options */
455   PetscCall(TSSetFromOptions(user.ts));
456 
457   PetscCall(TSSolve(user.ts,user.U));
458   PetscCall(VecGetArrayRead(user.U,&y_ptr));
459   user.ob[0] = y_ptr[0];
460   user.ob[1] = y_ptr[1];
461   PetscCall(VecRestoreArrayRead(user.U,&y_ptr));
462 
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   PetscCall(TSSetSaveTrajectory(user.ts));
467 
468   /* Optimization starts */
469   PetscCall(MatCreate(PETSC_COMM_WORLD,&user.H));
470   PetscCall(MatSetSizes(user.H,PETSC_DECIDE,PETSC_DECIDE,1,1));
471   PetscCall(MatSetUp(user.H)); /* Hessian should be symmetric. Do we need to do MatSetOption(user.H,MAT_SYMMETRIC,PETSC_TRUE) ? */
472 
473   /* Set initial solution guess */
474   PetscCall(MatCreateVecs(user.Jacp,&P,NULL));
475   PetscCall(VecGetArray(P,&x_ptr));
476   x_ptr[0] = PetscRealConstant(1.2);
477   PetscCall(VecRestoreArray(P,&x_ptr));
478   PetscCall(TaoSetSolution(tao,P));
479 
480   /* Set routine for function and gradient evaluation */
481   PetscCall(TaoSetObjectiveAndGradient(tao,NULL,FormFunctionGradient,(void *)&user));
482   PetscCall(TaoSetHessian(tao,user.H,user.H,FormHessian,(void *)&user));
483 
484   /* Check for any TAO command line options */
485   PetscCall(TaoGetKSP(tao,&ksp));
486   if (ksp) {
487     PetscCall(KSPGetPC(ksp,&pc));
488     PetscCall(PCSetType(pc,PCNONE));
489   }
490   PetscCall(TaoSetFromOptions(tao));
491 
492   PetscCall(TaoSolve(tao));
493 
494   PetscCall(VecView(P,PETSC_VIEWER_STDOUT_WORLD));
495   /* Free TAO data structures */
496   PetscCall(TaoDestroy(&tao));
497 
498   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
499      Free work space.  All PETSc objects should be destroyed when they
500      are no longer needed.
501    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
502   PetscCall(MatDestroy(&user.H));
503   PetscCall(MatDestroy(&user.A));
504   PetscCall(VecDestroy(&user.U));
505   PetscCall(MatDestroy(&user.Jacp));
506   PetscCall(VecDestroy(&user.Lambda[0]));
507   PetscCall(VecDestroy(&user.Mup[0]));
508   PetscCall(VecDestroy(&user.Lambda2[0]));
509   PetscCall(VecDestroy(&user.Mup2[0]));
510   PetscCall(VecDestroy(&user.Ihp1[0]));
511   PetscCall(VecDestroy(&user.Ihp2[0]));
512   PetscCall(VecDestroy(&user.Ihp3[0]));
513   PetscCall(VecDestroy(&user.Ihp4[0]));
514   PetscCall(VecDestroy(&user.Dir));
515   PetscCall(TSDestroy(&user.ts));
516   PetscCall(VecDestroy(&P));
517   PetscCall(PetscFinalize());
518   return 0;
519 }
520 
521 /* ------------------------------------------------------------------ */
522 /*
523    FormFunctionGradient - Evaluates the function and corresponding gradient.
524 
525    Input Parameters:
526    tao - the Tao context
527    X   - the input vector
528    ptr - optional user-defined context, as set by TaoSetObjectiveAndGradient()
529 
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;
540 
541   PetscFunctionBeginUser;
542   PetscCall(VecGetArrayRead(P,&y_ptr));
543   user_ptr->mu = y_ptr[0];
544   PetscCall(VecRestoreArrayRead(P,&y_ptr));
545 
546   PetscCall(TSSetTime(ts,0.0));
547   PetscCall(TSSetStepNumber(ts,0));
548   PetscCall(TSSetTimeStep(ts,PetscRealConstant(0.001))); /* can be overwritten by command line options */
549   PetscCall(TSSetFromOptions(ts));
550   PetscCall(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   PetscCall(VecRestoreArray(user_ptr->U,&x_ptr));
554 
555   PetscCall(TSSolve(ts,user_ptr->U));
556 
557   PetscCall(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]);
559 
560   /*   Reset initial conditions for the adjoint integration */
561   PetscCall(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   PetscCall(VecRestoreArrayRead(user_ptr->U,&y_ptr));
565   PetscCall(VecRestoreArray(user_ptr->Lambda[0],&x_ptr));
566 
567   PetscCall(VecGetArray(user_ptr->Mup[0],&x_ptr));
568   x_ptr[0] = 0.0;
569   PetscCall(VecRestoreArray(user_ptr->Mup[0],&x_ptr));
570   PetscCall(TSSetCostGradients(ts,1,user_ptr->Lambda,user_ptr->Mup));
571 
572   PetscCall(TSAdjointSolve(ts));
573 
574   PetscCall(VecGetArray(user_ptr->Mup[0],&x_ptr));
575   PetscCall(VecGetArrayRead(user_ptr->Lambda[0],&y_ptr));
576   PetscCall(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   PetscCall(VecRestoreArray(user_ptr->Mup[0],&x_ptr));
579   PetscCall(VecRestoreArrayRead(user_ptr->Lambda[0],&y_ptr));
580   PetscCall(VecRestoreArray(G,&g));
581   PetscFunctionReturn(0);
582 }
583 
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;
590 
591   PetscFunctionBeginUser;
592   PetscCall(Adjoint2(P,harr,user_ptr));
593   PetscCall(MatSetValues(H,1,rows,1,&col,harr,INSERT_VALUES));
594 
595   PetscCall(MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY));
596   PetscCall(MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY));
597   if (H != Hpre) {
598     PetscCall(MatAssemblyBegin(Hpre,MAT_FINAL_ASSEMBLY));
599     PetscCall(MatAssemblyEnd(Hpre,MAT_FINAL_ASSEMBLY));
600   }
601   PetscFunctionReturn(0);
602 }
603 
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;
610 
611   PetscFunctionBeginUser;
612   /* Reset TSAdjoint so that AdjointSetUp will be called again */
613   PetscCall(TSAdjointReset(ts));
614 
615   /* The directional vector should be 1 since it is one-dimensional */
616   PetscCall(VecGetArray(ctx->Dir,&x_ptr));
617   x_ptr[0] = 1.;
618   PetscCall(VecRestoreArray(ctx->Dir,&x_ptr));
619 
620   PetscCall(VecGetArrayRead(P,&z_ptr));
621   ctx->mu = z_ptr[0];
622   PetscCall(VecRestoreArrayRead(P,&z_ptr));
623 
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);
626 
627   PetscCall(TSSetTime(ts,0.0));
628   PetscCall(TSSetStepNumber(ts,0));
629   PetscCall(TSSetTimeStep(ts,PetscRealConstant(0.001))); /* can be overwritten by command line options */
630   PetscCall(TSSetFromOptions(ts));
631   PetscCall(TSSetCostHessianProducts(ts,1,ctx->Lambda2,ctx->Mup2,ctx->Dir));
632 
633   PetscCall(MatZeroEntries(ctx->Jacp));
634   PetscCall(MatSetValue(ctx->Jacp,1,0,dzdp,INSERT_VALUES));
635   PetscCall(MatAssemblyBegin(ctx->Jacp,MAT_FINAL_ASSEMBLY));
636   PetscCall(MatAssemblyEnd(ctx->Jacp,MAT_FINAL_ASSEMBLY));
637 
638   PetscCall(TSAdjointSetForward(ts,ctx->Jacp));
639   PetscCall(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   PetscCall(VecRestoreArray(ctx->U,&y_ptr));
643   PetscCall(TSSolve(ts,ctx->U));
644 
645   /* Set terminal conditions for first- and second-order adjonts */
646   PetscCall(VecGetArrayRead(ctx->U,&z_ptr));
647   PetscCall(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   PetscCall(VecRestoreArray(ctx->Lambda[0],&y_ptr));
651   PetscCall(VecRestoreArrayRead(ctx->U,&z_ptr));
652   PetscCall(VecGetArray(ctx->Mup[0],&y_ptr));
653   y_ptr[0] = 0.0;
654   PetscCall(VecRestoreArray(ctx->Mup[0],&y_ptr));
655   PetscCall(TSForwardGetSensitivities(ts,NULL,&tlmsen));
656   PetscCall(MatDenseGetColumn(tlmsen,0,&x_ptr));
657   PetscCall(VecGetArray(ctx->Lambda2[0],&y_ptr));
658   y_ptr[0] = 2.*x_ptr[0];
659   y_ptr[1] = 2.*x_ptr[1];
660   PetscCall(VecRestoreArray(ctx->Lambda2[0],&y_ptr));
661   PetscCall(VecGetArray(ctx->Mup2[0],&y_ptr));
662   y_ptr[0] = 0.0;
663   PetscCall(VecRestoreArray(ctx->Mup2[0],&y_ptr));
664   PetscCall(MatDenseRestoreColumn(tlmsen,&x_ptr));
665   PetscCall(TSSetCostGradients(ts,1,ctx->Lambda,ctx->Mup));
666   if (ctx->implicitform) {
667     PetscCall(TSSetIHessianProduct(ts,ctx->Ihp1,IHessianProductUU,ctx->Ihp2,IHessianProductUP,ctx->Ihp3,IHessianProductPU,ctx->Ihp4,IHessianProductPP,ctx));
668   } else {
669     PetscCall(TSSetRHSHessianProduct(ts,ctx->Ihp1,RHSHessianProductUU,ctx->Ihp2,RHSHessianProductUP,ctx->Ihp3,RHSHessianProductPU,ctx->Ihp4,RHSHessianProductPP,ctx));
670   }
671   PetscCall(TSAdjointSolve(ts));
672 
673   PetscCall(VecGetArray(ctx->Lambda[0],&x_ptr));
674   PetscCall(VecGetArray(ctx->Lambda2[0],&y_ptr));
675   PetscCall(VecGetArrayRead(ctx->Mup2[0],&z_ptr));
676 
677   arr[0] = x_ptr[1]*dzdp2 + y_ptr[1]*dzdp2 + z_ptr[0];
678 
679   PetscCall(VecRestoreArray(ctx->Lambda2[0],&x_ptr));
680   PetscCall(VecRestoreArray(ctx->Lambda2[0],&y_ptr));
681   PetscCall(VecRestoreArrayRead(ctx->Mup2[0],&z_ptr));
682 
683   /* Disable second-order adjoint mode */
684   PetscCall(TSAdjointReset(ts));
685   PetscCall(TSAdjointResetForward(ts));
686   PetscFunctionReturn(0);
687 }
688 
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
695 
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
700 
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
705 
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
710 
711 TEST*/
712