Actual source code: ex20opt_ic.c
petsc-3.12.5 2020-03-29
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: Optimization using adjoint sensitivities
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: PetscErrorCode ierr;
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: PetscErrorCode ierr;
63: User user = (User)ctx;
64: PetscReal mu = user->mu;
65: PetscInt rowcol[] = {0,1};
66: PetscScalar J[2][2];
67: const PetscScalar *u;
70: 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 (A != B) {
79: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
80: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
81: }
82: VecRestoreArrayRead(U,&u);
83: return(0);
84: }
86: static PetscErrorCode RHSHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
87: {
88: const PetscScalar *vl,*vr,*u;
89: PetscScalar *vhv;
90: PetscScalar dJdU[2][2][2]={{{0}}};
91: PetscInt i,j,k;
92: User user = (User)ctx;
93: PetscErrorCode ierr;
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: }
110: VecRestoreArrayRead(U,&u);
111: VecRestoreArrayRead(Vl[0],&vl);
112: VecRestoreArrayRead(Vr,&vr);
113: VecRestoreArray(VHV[0],&vhv);
114: return(0);
115: }
117: /* ----------------------- Implicit form of the ODE -------------------- */
119: static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,void *ctx)
120: {
121: PetscErrorCode ierr;
122: User user = (User)ctx;
123: const PetscScalar *u,*udot;
124: PetscScalar *f;
127: VecGetArrayRead(U,&u);
128: VecGetArrayRead(Udot,&udot);
129: VecGetArray(F,&f);
130: f[0] = udot[0] - u[1];
131: f[1] = udot[1] - user->mu*((1.0-u[0]*u[0])*u[1] - u[0]) ;
132: VecRestoreArrayRead(U,&u);
133: VecRestoreArrayRead(Udot,&udot);
134: VecRestoreArray(F,&f);
135: return(0);
136: }
138: static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,void *ctx)
139: {
140: PetscErrorCode ierr;
141: User user = (User)ctx;
142: PetscInt rowcol[] = {0,1};
143: PetscScalar J[2][2];
144: const PetscScalar *u;
147: VecGetArrayRead(U,&u);
148: J[0][0] = a; J[0][1] = -1.0;
149: 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]);
150: MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
151: VecRestoreArrayRead(U,&u);
152: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
153: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
154: if (A != B) {
155: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
156: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
157: }
158: return(0);
159: }
161: /* Monitor timesteps and use interpolation to output at integer multiples of 0.1 */
162: static PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal t,Vec U,void *ctx)
163: {
164: PetscErrorCode ierr;
165: const PetscScalar *u;
166: PetscReal tfinal, dt;
167: User user = (User)ctx;
168: Vec interpolatedU;
171: TSGetTimeStep(ts,&dt);
172: TSGetMaxTime(ts,&tfinal);
174: while (user->next_output <= t && user->next_output <= tfinal) {
175: VecDuplicate(U,&interpolatedU);
176: TSInterpolate(ts,user->next_output,interpolatedU);
177: VecGetArrayRead(interpolatedU,&u);
178: PetscPrintf(PETSC_COMM_WORLD,"[%g] %D TS %g (dt = %g) X %g %g\n",
179: (double)user->next_output,step,(double)t,(double)dt,(double)PetscRealPart(u[0]),
180: (double)PetscRealPart(u[1]));
181: VecRestoreArrayRead(interpolatedU,&u);
182: VecDestroy(&interpolatedU);
183: user->next_output += 0.1;
184: }
185: return(0);
186: }
188: static PetscErrorCode IHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx)
189: {
190: const PetscScalar *vl,*vr,*u;
191: PetscScalar *vhv;
192: PetscScalar dJdU[2][2][2]={{{0}}};
193: PetscInt i,j,k;
194: User user = (User)ctx;
195: PetscErrorCode ierr;
198: VecGetArrayRead(U,&u);
199: VecGetArrayRead(Vl[0],&vl);
200: VecGetArrayRead(Vr,&vr);
201: VecGetArray(VHV[0],&vhv);
202: dJdU[1][0][0] = 2.*user->mu*u[1];
203: dJdU[1][1][0] = 2.*user->mu*u[0];
204: dJdU[1][0][1] = 2.*user->mu*u[0];
205: for (j=0;j<2;j++) {
206: vhv[j] = 0;
207: for (k=0;k<2;k++)
208: for (i=0;i<2;i++ )
209: vhv[j] += vl[i]*dJdU[i][j][k]*vr[k];
210: }
211: VecRestoreArrayRead(U,&u);
212: VecRestoreArrayRead(Vl[0],&vl);
213: VecRestoreArrayRead(Vr,&vr);
214: VecRestoreArray(VHV[0],&vhv);
215: return(0);
216: }
218: /* ------------------ User-defined routines for TAO -------------------------- */
220: static PetscErrorCode FormFunctionGradient(Tao tao,Vec IC,PetscReal *f,Vec G,void *ctx)
221: {
222: User user_ptr = (User)ctx;
223: TS ts = user_ptr->ts;
224: const PetscScalar *x_ptr;
225: PetscScalar *y_ptr;
229: VecCopy(IC,user_ptr->U); /* set up the initial condition */
231: TSSetTime(ts,0.0);
232: TSSetStepNumber(ts,0);
233: TSSetTimeStep(ts,0.001); /* can be overwritten by command line options */
234: TSSetFromOptions(ts);
235: TSSolve(ts,user_ptr->U);
237: VecGetArrayRead(user_ptr->U,&x_ptr);
238: VecGetArray(user_ptr->Lambda[0],&y_ptr);
239: *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]);
240: y_ptr[0] = 2.*(x_ptr[0]-user_ptr->ob[0]);
241: y_ptr[1] = 2.*(x_ptr[1]-user_ptr->ob[1]);
242: VecRestoreArray(user_ptr->Lambda[0],&y_ptr);
243: VecRestoreArrayRead(user_ptr->U,&x_ptr);
245: TSSetCostGradients(ts,1,user_ptr->Lambda,NULL);
246: TSAdjointSolve(ts);
247: VecCopy(user_ptr->Lambda[0],G);
248: return(0);
249: }
251: static PetscErrorCode FormHessian(Tao tao,Vec U,Mat H,Mat Hpre,void *ctx)
252: {
253: User user_ptr = (User)ctx;
254: PetscScalar harr[2];
255: PetscScalar *x_ptr;
256: const PetscInt rows[2] = {0,1};
257: PetscInt col;
261: VecCopy(U,user_ptr->U);
262: VecGetArray(user_ptr->Dir,&x_ptr);
263: x_ptr[0] = 1.;
264: x_ptr[1] = 0.;
265: VecRestoreArray(user_ptr->Dir,&x_ptr);
266: Adjoint2(user_ptr->U,harr,user_ptr);
267: col = 0;
268: MatSetValues(H,2,rows,1,&col,harr,INSERT_VALUES);
270: VecCopy(U,user_ptr->U);
271: VecGetArray(user_ptr->Dir,&x_ptr);
272: x_ptr[0] = 0.;
273: x_ptr[1] = 1.;
274: VecRestoreArray(user_ptr->Dir,&x_ptr);
275: Adjoint2(user_ptr->U,harr,user_ptr);
276: col = 1;
277: MatSetValues(H,2,rows,1,&col,harr,INSERT_VALUES);
279: MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);
280: MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);
281: if (H != Hpre) {
282: MatAssemblyBegin(Hpre,MAT_FINAL_ASSEMBLY);
283: MatAssemblyEnd(Hpre,MAT_FINAL_ASSEMBLY);
284: }
285: return(0);
286: }
288: static PetscErrorCode MatrixFreeHessian(Tao tao,Vec U,Mat H,Mat Hpre,void *ctx)
289: {
290: User user_ptr = (User)ctx;
294: VecCopy(U,user_ptr->U);
295: return(0);
296: }
298: /* ------------ Routines calculating second-order derivatives -------------- */
300: /**
301: Compute the Hessian-vector product for the cost function using Second-order adjoint
302: */
303: PetscErrorCode Adjoint2(Vec U,PetscScalar arr[],User ctx)
304: {
305: TS ts = ctx->ts;
306: PetscScalar *x_ptr,*y_ptr;
307: Mat tlmsen;
311: TSAdjointReset(ts);
313: TSSetTime(ts,0.0);
314: TSSetStepNumber(ts,0);
315: TSSetTimeStep(ts,0.001);
316: TSSetFromOptions(ts);
317: TSSetCostHessianProducts(ts,1,ctx->Lambda2,NULL,ctx->Dir);
318: TSAdjointSetForward(ts,NULL);
319: TSSolve(ts,U);
321: /* Set terminal conditions for first- and second-order adjonts */
322: VecGetArray(U,&x_ptr);
323: VecGetArray(ctx->Lambda[0],&y_ptr);
324: y_ptr[0] = 2.*(x_ptr[0]-ctx->ob[0]);
325: y_ptr[1] = 2.*(x_ptr[1]-ctx->ob[1]);
326: VecRestoreArray(ctx->Lambda[0],&y_ptr);
327: VecRestoreArray(U,&x_ptr);
328: TSForwardGetSensitivities(ts,NULL,&tlmsen);
329: MatDenseGetColumn(tlmsen,0,&x_ptr);
330: VecGetArray(ctx->Lambda2[0],&y_ptr);
331: y_ptr[0] = 2.*x_ptr[0];
332: y_ptr[1] = 2.*x_ptr[1];
333: VecRestoreArray(ctx->Lambda2[0],&y_ptr);
334: MatDenseRestoreColumn(tlmsen,&x_ptr);
336: TSSetCostGradients(ts,1,ctx->Lambda,NULL);
337: if (ctx->implicitform) {
338: TSSetIHessianProduct(ts,ctx->Ihp1,IHessianProductUU,NULL,NULL,NULL,NULL,NULL,NULL,ctx);
339: } else {
340: TSSetRHSHessianProduct(ts,ctx->Ihp1,RHSHessianProductUU,NULL,NULL,NULL,NULL,NULL,NULL,ctx);
341: }
342: TSAdjointSolve(ts);
344: VecGetArray(ctx->Lambda2[0],&x_ptr);
345: arr[0] = x_ptr[0];
346: arr[1] = x_ptr[1];
347: VecRestoreArray(ctx->Lambda2[0],&x_ptr);
349: TSAdjointReset(ts);
350: TSAdjointResetForward(ts);
351: return(0);
352: }
354: PetscErrorCode FiniteDiff(Vec U,PetscScalar arr[],User ctx)
355: {
356: Vec Up,G,Gp;
357: const PetscScalar eps = PetscRealConstant(1e-7);
358: PetscScalar *u;
359: Tao tao = NULL;
360: PetscReal f;
361: PetscErrorCode ierr;
364: VecDuplicate(U,&Up);
365: VecDuplicate(U,&G);
366: VecDuplicate(U,&Gp);
368: FormFunctionGradient(tao,U,&f,G,ctx);
370: VecCopy(U,Up);
371: VecGetArray(Up,&u);
372: u[0] += 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[0] = u[0];
379: arr[1] = u[1];
380: VecRestoreArray(Gp,&u);
382: VecCopy(U,Up);
383: VecGetArray(Up,&u);
384: u[1] += eps;
385: VecRestoreArray(Up,&u);
386: FormFunctionGradient(tao,Up,&f,Gp,ctx);
387: VecAXPY(Gp,-1,G);
388: VecScale(Gp,1./eps);
389: VecGetArray(Gp,&u);
390: arr[2] = u[0];
391: arr[3] = u[1];
392: VecRestoreArray(Gp,&u);
394: VecDestroy(&G);
395: VecDestroy(&Gp);
396: VecDestroy(&Up);
397: return(0);
398: }
400: static PetscErrorCode HessianProductMat(Mat mat,Vec svec,Vec y)
401: {
402: User user_ptr;
403: PetscScalar *y_ptr;
407: MatShellGetContext(mat,(void*)&user_ptr);
408: VecCopy(svec,user_ptr->Dir);
409: VecGetArray(y,&y_ptr);
410: Adjoint2(user_ptr->U,y_ptr,user_ptr);
411: VecRestoreArray(y,&y_ptr);
412: return(0);
413: }
415: int main(int argc,char **argv)
416: {
417: PetscBool monitor = PETSC_FALSE,mf = PETSC_TRUE;
418: PetscInt mode = 0;
419: PetscMPIInt size;
420: struct _n_User user;
421: Vec x; /* working vector for TAO */
422: PetscScalar *x_ptr,arr[4];
423: PetscScalar ic1 = 2.2,ic2 = -0.7; /* initial guess for TAO */
424: Tao tao;
425: KSP ksp;
426: PC pc;
429: /* Initialize program */
430: PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr;
431: MPI_Comm_size(PETSC_COMM_WORLD,&size);
432: if (size != 1) SETERRQ(PETSC_COMM_SELF,1,"This is a uniprocessor example only!");
434: /* Set runtime options */
435: user.next_output = 0.0;
436: user.mu = 1.0e3;
437: user.steps = 0;
438: user.ftime = 0.5;
439: user.implicitform = PETSC_TRUE;
441: PetscOptionsGetBool(NULL,NULL,"-monitor",&monitor,NULL);
442: PetscOptionsGetReal(NULL,NULL,"-mu",&user.mu,NULL);
443: PetscOptionsGetInt(NULL,NULL,"-mode",&mode,NULL);
444: PetscOptionsGetReal(NULL,NULL,"-ic1",&ic1,NULL);
445: PetscOptionsGetReal(NULL,NULL,"-ic2",&ic2,NULL);
446: PetscOptionsGetBool(NULL,NULL,"-my_tao_mf",&mf,NULL); /* matrix-free hessian for optimization */
447: PetscOptionsGetBool(NULL,NULL,"-implicitform",&user.implicitform,NULL);
449: /* Create necessary matrix and vectors, solve same ODE on every process */
450: MatCreate(PETSC_COMM_WORLD,&user.A);
451: MatSetSizes(user.A,PETSC_DECIDE,PETSC_DECIDE,2,2);
452: MatSetFromOptions(user.A);
453: MatSetUp(user.A);
454: MatCreateVecs(user.A,&user.U,NULL);
455: MatCreateVecs(user.A,&user.Dir,NULL);
456: MatCreateVecs(user.A,&user.Lambda[0],NULL);
457: MatCreateVecs(user.A,&user.Lambda2[0],NULL);
458: MatCreateVecs(user.A,&user.Ihp1[0],NULL);
460: /* Create timestepping solver context */
461: TSCreate(PETSC_COMM_WORLD,&user.ts);
462: TSSetEquationType(user.ts,TS_EQ_ODE_EXPLICIT); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
463: if (user.implicitform) {
464: TSSetIFunction(user.ts,NULL,IFunction,&user);
465: TSSetIJacobian(user.ts,user.A,user.A,IJacobian,&user);
466: TSSetType(user.ts,TSCN);
467: } else {
468: TSSetRHSFunction(user.ts,NULL,RHSFunction,&user);
469: TSSetRHSJacobian(user.ts,user.A,user.A,RHSJacobian,&user);
470: TSSetType(user.ts,TSRK);
471: }
472: TSSetMaxTime(user.ts,user.ftime);
473: TSSetExactFinalTime(user.ts,TS_EXACTFINALTIME_MATCHSTEP);
475: if (monitor) {
476: TSMonitorSet(user.ts,Monitor,&user,NULL);
477: }
479: /* Set ODE initial conditions */
480: VecGetArray(user.U,&x_ptr);
481: x_ptr[0] = 2.0;
482: x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user.mu) - 292.0/(2187.0*user.mu*user.mu);
483: VecRestoreArray(user.U,&x_ptr);
485: /* Set runtime options */
486: TSSetFromOptions(user.ts);
488: /* Obtain the observation */
489: TSSolve(user.ts,user.U);
490: VecGetArray(user.U,&x_ptr);
491: user.ob[0] = x_ptr[0];
492: user.ob[1] = x_ptr[1];
493: VecRestoreArray(user.U,&x_ptr);
495: VecDuplicate(user.U,&x);
496: VecGetArray(x,&x_ptr);
497: x_ptr[0] = ic1;
498: x_ptr[1] = ic2;
499: VecRestoreArray(x,&x_ptr);
501: /* Save trajectory of solution so that TSAdjointSolve() may be used */
502: TSSetSaveTrajectory(user.ts);
504: /* Compare finite difference and second-order adjoint. */
505: switch (mode) {
506: case 2 :
507: FiniteDiff(x,arr,&user);
508: PetscPrintf(PETSC_COMM_WORLD,"\n Finite difference approximation of the Hessian\n");
509: PetscPrintf(PETSC_COMM_WORLD,"%g %g\n%g %g\n",(double)arr[0],(double)arr[1],(double)arr[2],(double)arr[3]);
510: break;
511: case 1 : /* Compute the Hessian column by column */
512: VecCopy(x,user.U);
513: VecGetArray(user.Dir,&x_ptr);
514: x_ptr[0] = 1.;
515: x_ptr[1] = 0.;
516: VecRestoreArray(user.Dir,&x_ptr);
517: Adjoint2(user.U,arr,&user);
518: PetscPrintf(PETSC_COMM_WORLD,"\nFirst column of the Hessian\n");
519: PetscPrintf(PETSC_COMM_WORLD,"%g\n%g\n",(double)arr[0],(double)arr[1]);
520: VecCopy(x,user.U);
521: VecGetArray(user.Dir,&x_ptr);
522: x_ptr[0] = 0.;
523: x_ptr[1] = 1.;
524: VecRestoreArray(user.Dir,&x_ptr);
525: Adjoint2(user.U,arr,&user);
526: PetscPrintf(PETSC_COMM_WORLD,"\nSecond column of the Hessian\n");
527: PetscPrintf(PETSC_COMM_WORLD,"%g\n%g\n",(double)arr[0],(double)arr[1]);
528: break;
529: case 0 :
530: /* Create optimization context and set up */
531: TaoCreate(PETSC_COMM_WORLD,&tao);
532: TaoSetType(tao,TAOBLMVM);
533: TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&user);
535: if (mf) {
536: MatCreateShell(PETSC_COMM_SELF,2,2,2,2,(void*)&user,&user.H);
537: MatShellSetOperation(user.H,MATOP_MULT,(void(*)(void))HessianProductMat);
538: MatSetOption(user.H,MAT_SYMMETRIC,PETSC_TRUE);
539: TaoSetHessianRoutine(tao,user.H,user.H,MatrixFreeHessian,(void *)&user);
540: } else { /* Create Hessian matrix */
541: MatCreate(PETSC_COMM_WORLD,&user.H);
542: MatSetSizes(user.H,PETSC_DECIDE,PETSC_DECIDE,2,2);
543: MatSetUp(user.H);
544: TaoSetHessianRoutine(tao,user.H,user.H,FormHessian,(void *)&user);
545: }
547: /* Not use any preconditioner */
548: TaoGetKSP(tao,&ksp);
549: if (ksp) {
550: KSPGetPC(ksp,&pc);
551: PCSetType(pc,PCNONE);
552: }
554: /* Set initial solution guess */
555: TaoSetInitialVector(tao,x);
556: TaoSetFromOptions(tao);
557: TaoSolve(tao);
558: TaoDestroy(&tao);
559: MatDestroy(&user.H);
560: break;
561: default:
562: break;
563: }
565: /* Free work space. All PETSc objects should be destroyed when they are no longer needed. */
566: MatDestroy(&user.A);
567: VecDestroy(&user.U);
568: VecDestroy(&user.Lambda[0]);
569: VecDestroy(&user.Lambda2[0]);
570: VecDestroy(&user.Ihp1[0]);
571: VecDestroy(&user.Dir);
572: TSDestroy(&user.ts);
573: VecDestroy(&x);
574: PetscFinalize();
575: return(ierr);
576: }
578: /*TEST
579: build:
580: requires: !complex !single
582: test:
583: args: -ts_type cn -viewer_binary_skip_info -tao_monitor -tao_view -mu 1000 -ts_dt 0.03125
584: output_file: output/ex20opt_ic_1.out
586: test:
587: suffix: 2
588: 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
589: output_file: output/ex20opt_ic_2.out
591: test:
592: suffix: 3
593: 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
594: output_file: output/ex20opt_ic_3.out
596: test:
597: suffix: 4
598: 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
599: TEST*/