Actual source code: ex20adj.c
petsc-3.14.6 2021-03-30
1: static char help[] = "Performs adjoint sensitivity analysis 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^adjoint sensitivity analysis
7: Processors: 1
8: */
9: /* ------------------------------------------------------------------------
11: This program solves the van der Pol DAE ODE equivalent
12: [ u_1' ] = [ u_2 ] (2)
13: [ u_2' ] [ \mu ((1 - u_1^2) u_2 - u_1) ]
14: on the domain 0 <= x <= 1, with the boundary conditions
15: u_1(0) = 2, u_2(0) = - 2/3 +10/(81*\mu) - 292/(2187*\mu^2),
16: and
17: \mu = 10^6 ( y'(0) ~ -0.6666665432100101).,
18: and computes the sensitivities of the final solution w.r.t. initial conditions and parameter \mu with the implicit theta method and its discrete adjoint.
20: Notes:
21: This code demonstrates the TSAdjoint interface to a DAE system.
23: The user provides the implicit right-hand-side function
24: [ F(u',u,t) ] = [u' - f(u,t)] = [ u_1'] - [ u_2 ]
25: [ u_2'] [ \mu ((1-u_1^2)u_2-u_1) ]
27: and the Jacobian of F (from the PETSc user manual)
29: dF dF
30: J(F) = a * -- + --
31: du' du
33: and the JacobianP of the explicit right-hand side of (2) f(u,t) ( which is equivalent to -F(0,u,t)).
34: df [ 0 ]
35: -- = [ ]
36: dp [ (1 - u_1^2) u_2 - u_1 ].
38: See ex20.c for more details on the Jacobian.
40: ------------------------------------------------------------------------- */
41: #include <petscts.h>
42: #include <petsctao.h>
44: typedef struct _n_User *User;
45: struct _n_User {
46: PetscReal mu;
47: PetscReal next_output;
49: /* Sensitivity analysis support */
50: PetscInt steps;
51: PetscReal ftime;
52: Mat A; /* Jacobian matrix */
53: Mat Jacp; /* JacobianP matrix */
54: Vec U,lambda[2],mup[2]; /* adjoint variables */
55: };
57: /* ----------------------- Explicit form of the ODE -------------------- */
59: static PetscErrorCode RHSFunction(TS ts,PetscReal t,Vec U,Vec F,void *ctx)
60: {
61: PetscErrorCode ierr;
62: User user = (User)ctx;
63: PetscScalar *f;
64: const PetscScalar *u;
67: VecGetArrayRead(U,&u);
68: VecGetArray(F,&f);
69: f[0] = u[1];
70: f[1] = user->mu*((1.-u[0]*u[0])*u[1]-u[0]);
71: VecRestoreArrayRead(U,&u);
72: VecRestoreArray(F,&f);
73: return(0);
74: }
76: static PetscErrorCode RHSJacobian(TS ts,PetscReal t,Vec U,Mat A,Mat B,void *ctx)
77: {
78: PetscErrorCode ierr;
79: User user = (User)ctx;
80: PetscReal mu = user->mu;
81: PetscInt rowcol[] = {0,1};
82: PetscScalar J[2][2];
83: const PetscScalar *u;
86: VecGetArrayRead(U,&u);
87: J[0][0] = 0;
88: J[1][0] = -mu*(2.0*u[1]*u[0]+1.);
89: J[0][1] = 1.0;
90: J[1][1] = mu*(1.0-u[0]*u[0]);
91: MatSetValues(A,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
92: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
93: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
94: if (A != B) {
95: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
96: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
97: }
98: VecRestoreArrayRead(U,&u);
99: return(0);
100: }
102: /* ----------------------- Implicit form of the ODE -------------------- */
104: static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,void *ctx)
105: {
106: PetscErrorCode ierr;
107: User user = (User)ctx;
108: const PetscScalar *u,*udot;
109: PetscScalar *f;
112: VecGetArrayRead(U,&u);
113: VecGetArrayRead(Udot,&udot);
114: VecGetArray(F,&f);
115: f[0] = udot[0] - u[1];
116: f[1] = udot[1] - user->mu*((1.0-u[0]*u[0])*u[1] - u[0]);
117: VecRestoreArrayRead(U,&u);
118: VecRestoreArrayRead(Udot,&udot);
119: VecRestoreArray(F,&f);
120: return(0);
121: }
123: static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,void *ctx)
124: {
125: PetscErrorCode ierr;
126: User user = (User)ctx;
127: PetscInt rowcol[] = {0,1};
128: PetscScalar J[2][2];
129: const PetscScalar *u;
132: VecGetArrayRead(U,&u);
134: J[0][0] = a; J[0][1] = -1.0;
135: J[1][0] = user->mu*(2.0*u[0]*u[1] + 1.0); J[1][1] = a - user->mu*(1.0-u[0]*u[0]);
137: MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
138: VecRestoreArrayRead(U,&u);
140: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
141: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
142: if (B && A != B) {
143: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
144: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
145: }
146: return(0);
147: }
149: static PetscErrorCode RHSJacobianP(TS ts,PetscReal t,Vec U,Mat A,void *ctx)
150: {
151: PetscErrorCode ierr;
152: PetscInt row[] = {0,1},col[]={0};
153: PetscScalar J[2][1];
154: const PetscScalar *u;
157: VecGetArrayRead(U,&u);
158: J[0][0] = 0;
159: J[1][0] = (1.-u[0]*u[0])*u[1]-u[0];
160: MatSetValues(A,2,row,1,col,&J[0][0],INSERT_VALUES);
161: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
162: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
163: VecRestoreArrayRead(U,&u);
164: return(0);
165: }
167: /* Monitor timesteps and use interpolation to output at integer multiples of 0.1 */
168: static PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal t,Vec U,void *ctx)
169: {
170: PetscErrorCode ierr;
171: const PetscScalar *u;
172: PetscReal tfinal, dt;
173: User user = (User)ctx;
174: Vec interpolatedU;
177: TSGetTimeStep(ts,&dt);
178: TSGetMaxTime(ts,&tfinal);
180: while (user->next_output <= t && user->next_output <= tfinal) {
181: VecDuplicate(U,&interpolatedU);
182: TSInterpolate(ts,user->next_output,interpolatedU);
183: VecGetArrayRead(interpolatedU,&u);
184: PetscPrintf(PETSC_COMM_WORLD,"[%g] %D TS %g (dt = %g) X %g %g\n",
185: (double)user->next_output,step,(double)t,(double)dt,(double)PetscRealPart(u[0]),
186: (double)PetscRealPart(u[1]));
187: VecRestoreArrayRead(interpolatedU,&u);
188: VecDestroy(&interpolatedU);
189: user->next_output += 0.1;
190: }
191: return(0);
192: }
194: int main(int argc,char **argv)
195: {
196: TS ts;
197: PetscBool monitor = PETSC_FALSE,implicitform = PETSC_TRUE;
198: PetscScalar *x_ptr,*y_ptr,derp;
199: PetscMPIInt size;
200: struct _n_User user;
203: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
204: Initialize program
205: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
206: PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr;
207: MPI_Comm_size(PETSC_COMM_WORLD,&size);
208: if (size != 1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"This is a uniprocessor example only!");
210: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211: Set runtime options
212: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
213: user.next_output = 0.0;
214: user.mu = 1.0e3;
215: user.steps = 0;
216: user.ftime = 0.5;
217: PetscOptionsGetBool(NULL,NULL,"-monitor",&monitor,NULL);
218: PetscOptionsGetReal(NULL,NULL,"-mu",&user.mu,NULL);
219: PetscOptionsGetBool(NULL,NULL,"-implicitform",&implicitform,NULL);
221: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
222: Create necessary matrix and vectors, solve same ODE on every process
223: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
224: MatCreate(PETSC_COMM_WORLD,&user.A);
225: MatSetSizes(user.A,PETSC_DECIDE,PETSC_DECIDE,2,2);
226: MatSetFromOptions(user.A);
227: MatSetUp(user.A);
228: MatCreateVecs(user.A,&user.U,NULL);
230: MatCreate(PETSC_COMM_WORLD,&user.Jacp);
231: MatSetSizes(user.Jacp,PETSC_DECIDE,PETSC_DECIDE,2,1);
232: MatSetFromOptions(user.Jacp);
233: MatSetUp(user.Jacp);
235: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
236: Create timestepping solver context
237: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
238: TSCreate(PETSC_COMM_WORLD,&ts);
239: TSSetEquationType(ts,TS_EQ_ODE_EXPLICIT); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
240: if (implicitform) {
241: TSSetIFunction(ts,NULL,IFunction,&user);
242: TSSetIJacobian(ts,user.A,user.A,IJacobian,&user);
243: TSSetType(ts,TSCN);
244: } else {
245: TSSetRHSFunction(ts,NULL,RHSFunction,&user);
246: TSSetRHSJacobian(ts,user.A,user.A,RHSJacobian,&user);
247: TSSetType(ts,TSRK);
248: }
249: TSSetRHSJacobianP(ts,user.Jacp,RHSJacobianP,&user);
250: TSSetMaxTime(ts,user.ftime);
251: TSSetTimeStep(ts,0.001);
252: TSSetExactFinalTime(ts,TS_EXACTFINALTIME_MATCHSTEP);
253: if (monitor) {
254: TSMonitorSet(ts,Monitor,&user,NULL);
255: }
257: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
258: Set initial conditions
259: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
260: VecGetArray(user.U,&x_ptr);
261: x_ptr[0] = 2.0;
262: x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user.mu) - 292.0/(2187.0*user.mu*user.mu);
263: VecRestoreArray(user.U,&x_ptr);
264: TSSetTimeStep(ts,0.001);
266: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
267: Save trajectory of solution so that TSAdjointSolve() may be used
268: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
269: TSSetSaveTrajectory(ts);
271: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
272: Set runtime options
273: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
274: TSSetFromOptions(ts);
276: TSSolve(ts,user.U);
277: TSGetSolveTime(ts,&user.ftime);
278: TSGetStepNumber(ts,&user.steps);
280: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
281: Adjoint model starts here
282: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
283: MatCreateVecs(user.A,&user.lambda[0],NULL);
284: /* Set initial conditions for the adjoint integration */
285: VecGetArray(user.lambda[0],&y_ptr);
286: y_ptr[0] = 1.0; y_ptr[1] = 0.0;
287: VecRestoreArray(user.lambda[0],&y_ptr);
288: MatCreateVecs(user.A,&user.lambda[1],NULL);
289: VecGetArray(user.lambda[1],&y_ptr);
290: y_ptr[0] = 0.0; y_ptr[1] = 1.0;
291: VecRestoreArray(user.lambda[1],&y_ptr);
293: MatCreateVecs(user.Jacp,&user.mup[0],NULL);
294: VecGetArray(user.mup[0],&x_ptr);
295: x_ptr[0] = 0.0;
296: VecRestoreArray(user.mup[0],&x_ptr);
297: MatCreateVecs(user.Jacp,&user.mup[1],NULL);
298: VecGetArray(user.mup[1],&x_ptr);
299: x_ptr[0] = 0.0;
300: VecRestoreArray(user.mup[1],&x_ptr);
302: TSSetCostGradients(ts,2,user.lambda,user.mup);
304: TSAdjointSolve(ts);
306: PetscPrintf(PETSC_COMM_WORLD,"\n sensitivity wrt initial conditions: d[y(tf)]/d[y0] d[y(tf)]/d[z0]\n");
307: VecView(user.lambda[0],PETSC_VIEWER_STDOUT_WORLD);
308: PetscPrintf(PETSC_COMM_WORLD,"\n sensitivity wrt initial conditions: d[z(tf)]/d[y0] d[z(tf)]/d[z0]\n");
309: VecView(user.lambda[1],PETSC_VIEWER_STDOUT_WORLD);
311: VecGetArray(user.mup[0],&x_ptr);
312: VecGetArray(user.lambda[0],&y_ptr);
313: derp = y_ptr[1]*(-10.0/(81.0*user.mu*user.mu)+2.0*292.0/(2187.0*user.mu*user.mu*user.mu))+x_ptr[0];
314: VecRestoreArray(user.mup[0],&x_ptr);
315: VecRestoreArray(user.lambda[0],&y_ptr);
316: PetscPrintf(PETSC_COMM_WORLD,"\n sensitivity wrt parameters: d[y(tf)]/d[mu]\n%g\n",(double)PetscRealPart(derp));
318: VecGetArray(user.mup[1],&x_ptr);
319: VecGetArray(user.lambda[1],&y_ptr);
320: derp = y_ptr[1]*(-10.0/(81.0*user.mu*user.mu)+2.0*292.0/(2187.0*user.mu*user.mu*user.mu))+x_ptr[0];
321: VecRestoreArray(user.mup[1],&x_ptr);
322: VecRestoreArray(user.lambda[1],&y_ptr);
323: PetscPrintf(PETSC_COMM_WORLD,"\n sensivitity wrt parameters: d[z(tf)]/d[mu]\n%g\n",(double)PetscRealPart(derp));
325: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
326: Free work space. All PETSc objects should be destroyed when they
327: are no longer needed.
328: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
329: MatDestroy(&user.A);
330: MatDestroy(&user.Jacp);
331: VecDestroy(&user.U);
332: VecDestroy(&user.lambda[0]);
333: VecDestroy(&user.lambda[1]);
334: VecDestroy(&user.mup[0]);
335: VecDestroy(&user.mup[1]);
336: TSDestroy(&ts);
338: PetscFinalize();
339: return(ierr);
340: }
342: /*TEST
344: test:
345: requires: revolve
346: args: -monitor 0 -ts_type theta -ts_theta_endpoint -ts_theta_theta 0.5 -viewer_binary_skip_info -ts_dt 0.001 -mu 100000
348: test:
349: suffix: 2
350: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_solution_only
352: test:
353: suffix: 3
354: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_solution_only 0
355: output_file: output/ex20adj_2.out
357: test:
358: suffix: 4
359: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack
360: output_file: output/ex20adj_2.out
362: test:
363: suffix: 5
364: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_stride 5 -ts_trajectory_solution_only 0 -ts_trajectory_save_stack
365: output_file: output/ex20adj_2.out
367: test:
368: suffix: 6
369: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack 0
370: output_file: output/ex20adj_2.out
372: test:
373: suffix: 7
374: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_stride 5 -ts_trajectory_solution_only 0 -ts_trajectory_save_stack 0
375: output_file: output/ex20adj_2.out
377: test:
378: suffix: 8
379: requires: revolve
380: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 5 -ts_trajectory_solution_only -ts_trajectory_monitor
381: output_file: output/ex20adj_3.out
383: test:
384: suffix: 9
385: requires: revolve
386: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 5 -ts_trajectory_solution_only 0 -ts_trajectory_monitor
387: output_file: output/ex20adj_4.out
389: test:
390: requires: revolve
391: suffix: 10
392: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 5 -ts_trajectory_revolve_online -ts_trajectory_solution_only
393: output_file: output/ex20adj_2.out
395: test:
396: requires: revolve
397: suffix: 11
398: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 5 -ts_trajectory_revolve_online -ts_trajectory_solution_only 0
399: output_file: output/ex20adj_2.out
401: test:
402: suffix: 12
403: requires: revolve
404: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_max_cps_disk 8 -ts_trajectory_solution_only
405: output_file: output/ex20adj_2.out
407: test:
408: suffix: 13
409: requires: revolve
410: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_max_cps_disk 8 -ts_trajectory_solution_only 0
411: output_file: output/ex20adj_2.out
413: test:
414: suffix: 14
415: requires: revolve
416: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack
417: output_file: output/ex20adj_2.out
419: test:
420: suffix: 15
421: requires: revolve
422: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack 0
423: output_file: output/ex20adj_2.out
425: test:
426: suffix: 16
427: requires: revolve
428: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_stride 5 -ts_trajectory_solution_only 0 -ts_trajectory_save_stack
429: output_file: output/ex20adj_2.out
431: test:
432: suffix: 17
433: requires: revolve
434: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_stride 5 -ts_trajectory_solution_only 0 -ts_trajectory_save_stack 0
435: output_file: output/ex20adj_2.out
437: test:
438: suffix: 18
439: requires: revolve
440: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_max_cps_disk 8 -ts_trajectory_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack
441: output_file: output/ex20adj_2.out
443: test:
444: suffix: 19
445: requires: revolve
446: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_max_cps_disk 8 -ts_trajectory_stride 5 -ts_trajectory_solution_only 0 -ts_trajectory_save_stack
447: output_file: output/ex20adj_2.out
449: test:
450: suffix: 20
451: requires: revolve
452: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_max_cps_disk 8 -ts_trajectory_solution_only 0
453: output_file: output/ex20adj_2.out
455: test:
456: suffix: 21
457: requires: revolve
458: args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_cps_ram 3 -ts_trajectory_max_cps_disk 8 -ts_trajectory_stride 5 -ts_trajectory_solution_only 0 -ts_trajectory_save_stack 0
459: output_file: output/ex20adj_2.out
461: test:
462: suffix: 22
463: args: -ts_type beuler -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_solution_only
464: output_file: output/ex20adj_2.out
465: TEST*/