Actual source code: ex20adj.c

  1: static char help[] = "Performs adjoint sensitivity analysis for the van der Pol equation.\n";

  3: /* ------------------------------------------------------------------------

  5:    This program solves the van der Pol DAE ODE equivalent
  6:       [ u_1' ] = [          u_2                ]  (2)
  7:       [ u_2' ]   [ \mu ((1 - u_1^2) u_2 - u_1) ]
  8:    on the domain 0 <= x <= 1, with the boundary conditions
  9:        u_1(0) = 2, u_2(0) = - 2/3 +10/(81*\mu) - 292/(2187*\mu^2),
 10:    and
 11:        \mu = 10^6 ( y'(0) ~ -0.6666665432100101).,
 12:    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.

 14:    Notes:
 15:    This code demonstrates the TSAdjoint interface to a DAE system.

 17:    The user provides the implicit right-hand-side function
 18:    [ F(u',u,t) ] = [u' - f(u,t)] = [ u_1'] - [        u_2             ]
 19:                                    [ u_2']   [ \mu ((1-u_1^2)u_2-u_1) ]

 21:    and the Jacobian of F (from the PETSc user manual)

 23:               dF   dF
 24:    J(F) = a * -- + --
 25:               du'  du

 27:    and the JacobianP of the explicit right-hand side of (2) f(u,t) ( which is equivalent to -F(0,u,t)).
 28:    df   [       0               ]
 29:    -- = [                       ]
 30:    dp   [ (1 - u_1^2) u_2 - u_1 ].

 32:    See ex20.c for more details on the Jacobian.

 34:   ------------------------------------------------------------------------- */
 35: #include <petscts.h>
 36: #include <petsctao.h>

 38: typedef struct _n_User *User;
 39: struct _n_User {
 40:   PetscReal mu;
 41:   PetscReal next_output;

 43:   /* Sensitivity analysis support */
 44:   PetscInt  steps;
 45:   PetscReal ftime;
 46:   Mat       A;                    /* Jacobian matrix */
 47:   Mat       Jacp;                 /* JacobianP matrix */
 48:   Vec       U, lambda[2], mup[2]; /* adjoint variables */
 49: };

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

 53: static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec F, void *ctx)
 54: {
 55:   User               user = (User)ctx;
 56:   PetscScalar       *f;
 57:   const PetscScalar *u;

 60:   VecGetArrayRead(U, &u);
 61:   VecGetArray(F, &f);
 62:   f[0] = u[1];
 63:   f[1] = user->mu * ((1. - u[0] * u[0]) * u[1] - u[0]);
 64:   VecRestoreArrayRead(U, &u);
 65:   VecRestoreArray(F, &f);
 66:   return 0;
 67: }

 69: static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat A, Mat B, void *ctx)
 70: {
 71:   User               user     = (User)ctx;
 72:   PetscReal          mu       = user->mu;
 73:   PetscInt           rowcol[] = {0, 1};
 74:   PetscScalar        J[2][2];
 75:   const PetscScalar *u;

 78:   VecGetArrayRead(U, &u);
 79:   J[0][0] = 0;
 80:   J[1][0] = -mu * (2.0 * u[1] * u[0] + 1.);
 81:   J[0][1] = 1.0;
 82:   J[1][1] = mu * (1.0 - u[0] * u[0]);
 83:   MatSetValues(A, 2, rowcol, 2, rowcol, &J[0][0], INSERT_VALUES);
 84:   MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
 85:   MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
 86:   if (A != B) {
 87:     MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY);
 88:     MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY);
 89:   }
 90:   VecRestoreArrayRead(U, &u);
 91:   return 0;
 92: }

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

 96: static PetscErrorCode IFunction(TS ts, PetscReal t, Vec U, Vec Udot, Vec F, void *ctx)
 97: {
 98:   User               user = (User)ctx;
 99:   const PetscScalar *u, *udot;
100:   PetscScalar       *f;

103:   VecGetArrayRead(U, &u);
104:   VecGetArrayRead(Udot, &udot);
105:   VecGetArray(F, &f);
106:   f[0] = udot[0] - u[1];
107:   f[1] = udot[1] - user->mu * ((1.0 - u[0] * u[0]) * u[1] - u[0]);
108:   VecRestoreArrayRead(U, &u);
109:   VecRestoreArrayRead(Udot, &udot);
110:   VecRestoreArray(F, &f);
111:   return 0;
112: }

114: static PetscErrorCode IJacobian(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal a, Mat A, Mat B, void *ctx)
115: {
116:   User               user     = (User)ctx;
117:   PetscInt           rowcol[] = {0, 1};
118:   PetscScalar        J[2][2];
119:   const PetscScalar *u;

122:   VecGetArrayRead(U, &u);

124:   J[0][0] = a;
125:   J[0][1] = -1.0;
126:   J[1][0] = user->mu * (2.0 * u[0] * u[1] + 1.0);
127:   J[1][1] = a - user->mu * (1.0 - u[0] * u[0]);

129:   MatSetValues(B, 2, rowcol, 2, rowcol, &J[0][0], INSERT_VALUES);
130:   VecRestoreArrayRead(U, &u);

132:   MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
133:   MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
134:   if (B && A != B) {
135:     MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY);
136:     MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY);
137:   }
138:   return 0;
139: }

141: static PetscErrorCode RHSJacobianP(TS ts, PetscReal t, Vec U, Mat A, void *ctx)
142: {
143:   PetscInt           row[] = {0, 1}, col[] = {0};
144:   PetscScalar        J[2][1];
145:   const PetscScalar *u;

148:   VecGetArrayRead(U, &u);
149:   J[0][0] = 0;
150:   J[1][0] = (1. - u[0] * u[0]) * u[1] - u[0];
151:   MatSetValues(A, 2, row, 1, col, &J[0][0], INSERT_VALUES);
152:   MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
153:   MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
154:   VecRestoreArrayRead(U, &u);
155:   return 0;
156: }

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

167:   TSGetTimeStep(ts, &dt);
168:   TSGetMaxTime(ts, &tfinal);

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

182: int main(int argc, char **argv)
183: {
184:   TS             ts;
185:   PetscBool      monitor = PETSC_FALSE, implicitform = PETSC_TRUE;
186:   PetscScalar   *x_ptr, *y_ptr, derp;
187:   PetscMPIInt    size;
188:   struct _n_User user;

190:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191:      Initialize program
192:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
194:   PetscInitialize(&argc, &argv, NULL, help);
195:   MPI_Comm_size(PETSC_COMM_WORLD, &size);

198:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
199:     Set runtime options
200:     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
201:   user.next_output = 0.0;
202:   user.mu          = 1.0e3;
203:   user.steps       = 0;
204:   user.ftime       = 0.5;
205:   PetscOptionsGetBool(NULL, NULL, "-monitor", &monitor, NULL);
206:   PetscOptionsGetReal(NULL, NULL, "-mu", &user.mu, NULL);
207:   PetscOptionsGetBool(NULL, NULL, "-implicitform", &implicitform, NULL);

209:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
210:     Create necessary matrix and vectors, solve same ODE on every process
211:     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
212:   MatCreate(PETSC_COMM_WORLD, &user.A);
213:   MatSetSizes(user.A, PETSC_DECIDE, PETSC_DECIDE, 2, 2);
214:   MatSetFromOptions(user.A);
215:   MatSetUp(user.A);
216:   MatCreateVecs(user.A, &user.U, NULL);

218:   MatCreate(PETSC_COMM_WORLD, &user.Jacp);
219:   MatSetSizes(user.Jacp, PETSC_DECIDE, PETSC_DECIDE, 2, 1);
220:   MatSetFromOptions(user.Jacp);
221:   MatSetUp(user.Jacp);

223:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
224:      Create timestepping solver context
225:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
226:   TSCreate(PETSC_COMM_WORLD, &ts);
227:   TSSetEquationType(ts, TS_EQ_ODE_EXPLICIT); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
228:   if (implicitform) {
229:     TSSetIFunction(ts, NULL, IFunction, &user);
230:     TSSetIJacobian(ts, user.A, user.A, IJacobian, &user);
231:     TSSetType(ts, TSCN);
232:   } else {
233:     TSSetRHSFunction(ts, NULL, RHSFunction, &user);
234:     TSSetRHSJacobian(ts, user.A, user.A, RHSJacobian, &user);
235:     TSSetType(ts, TSRK);
236:   }
237:   TSSetRHSJacobianP(ts, user.Jacp, RHSJacobianP, &user);
238:   TSSetMaxTime(ts, user.ftime);
239:   TSSetTimeStep(ts, 0.001);
240:   TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);
241:   if (monitor) TSMonitorSet(ts, Monitor, &user, NULL);

243:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
244:      Set initial conditions
245:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
246:   VecGetArray(user.U, &x_ptr);
247:   x_ptr[0] = 2.0;
248:   x_ptr[1] = -2.0 / 3.0 + 10.0 / (81.0 * user.mu) - 292.0 / (2187.0 * user.mu * user.mu);
249:   VecRestoreArray(user.U, &x_ptr);
250:   TSSetTimeStep(ts, 0.001);

252:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
253:     Save trajectory of solution so that TSAdjointSolve() may be used
254:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
255:   TSSetSaveTrajectory(ts);

257:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
258:      Set runtime options
259:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
260:   TSSetFromOptions(ts);

262:   TSSolve(ts, user.U);
263:   TSGetSolveTime(ts, &user.ftime);
264:   TSGetStepNumber(ts, &user.steps);

266:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
267:      Adjoint model starts here
268:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
269:   MatCreateVecs(user.A, &user.lambda[0], NULL);
270:   /* Set initial conditions for the adjoint integration */
271:   VecGetArray(user.lambda[0], &y_ptr);
272:   y_ptr[0] = 1.0;
273:   y_ptr[1] = 0.0;
274:   VecRestoreArray(user.lambda[0], &y_ptr);
275:   MatCreateVecs(user.A, &user.lambda[1], NULL);
276:   VecGetArray(user.lambda[1], &y_ptr);
277:   y_ptr[0] = 0.0;
278:   y_ptr[1] = 1.0;
279:   VecRestoreArray(user.lambda[1], &y_ptr);

281:   MatCreateVecs(user.Jacp, &user.mup[0], NULL);
282:   VecGetArray(user.mup[0], &x_ptr);
283:   x_ptr[0] = 0.0;
284:   VecRestoreArray(user.mup[0], &x_ptr);
285:   MatCreateVecs(user.Jacp, &user.mup[1], NULL);
286:   VecGetArray(user.mup[1], &x_ptr);
287:   x_ptr[0] = 0.0;
288:   VecRestoreArray(user.mup[1], &x_ptr);

290:   TSSetCostGradients(ts, 2, user.lambda, user.mup);

292:   TSAdjointSolve(ts);

294:   PetscPrintf(PETSC_COMM_WORLD, "\n sensitivity wrt initial conditions: d[y(tf)]/d[y0]  d[y(tf)]/d[z0]\n");
295:   VecView(user.lambda[0], PETSC_VIEWER_STDOUT_WORLD);
296:   PetscPrintf(PETSC_COMM_WORLD, "\n sensitivity wrt initial conditions: d[z(tf)]/d[y0]  d[z(tf)]/d[z0]\n");
297:   VecView(user.lambda[1], PETSC_VIEWER_STDOUT_WORLD);

299:   VecGetArray(user.mup[0], &x_ptr);
300:   VecGetArray(user.lambda[0], &y_ptr);
301:   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];
302:   VecRestoreArray(user.mup[0], &x_ptr);
303:   VecRestoreArray(user.lambda[0], &y_ptr);
304:   PetscPrintf(PETSC_COMM_WORLD, "\n sensitivity wrt parameters: d[y(tf)]/d[mu]\n%g\n", (double)PetscRealPart(derp));

306:   VecGetArray(user.mup[1], &x_ptr);
307:   VecGetArray(user.lambda[1], &y_ptr);
308:   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];
309:   VecRestoreArray(user.mup[1], &x_ptr);
310:   VecRestoreArray(user.lambda[1], &y_ptr);
311:   PetscPrintf(PETSC_COMM_WORLD, "\n sensivitity wrt parameters: d[z(tf)]/d[mu]\n%g\n", (double)PetscRealPart(derp));

313:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
314:      Free work space.  All PETSc objects should be destroyed when they
315:      are no longer needed.
316:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
317:   MatDestroy(&user.A);
318:   MatDestroy(&user.Jacp);
319:   VecDestroy(&user.U);
320:   VecDestroy(&user.lambda[0]);
321:   VecDestroy(&user.lambda[1]);
322:   VecDestroy(&user.mup[0]);
323:   VecDestroy(&user.mup[1]);
324:   TSDestroy(&ts);

326:   PetscFinalize();
327:   return 0;
328: }

330: /*TEST

332:     test:
333:       requires: revolve
334:       args: -monitor 0 -ts_type theta -ts_theta_endpoint -ts_theta_theta 0.5 -viewer_binary_skip_info -ts_dt 0.001 -mu 100000

336:     test:
337:       suffix: 2
338:       args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_solution_only

340:     test:
341:       suffix: 3
342:       args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_solution_only 0
343:       output_file: output/ex20adj_2.out

345:     test:
346:       suffix: 4
347:       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
348:       output_file: output/ex20adj_2.out

350:     test:
351:       suffix: 5
352:       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
353:       output_file: output/ex20adj_2.out

355:     test:
356:       suffix: 6
357:       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
358:       output_file: output/ex20adj_2.out

360:     test:
361:       suffix: 7
362:       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
363:       output_file: output/ex20adj_2.out

365:     test:
366:       suffix: 8
367:       requires: revolve !cams
368:       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
369:       output_file: output/ex20adj_3.out

371:     test:
372:       suffix: 9
373:       requires: revolve !cams
374:       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
375:       output_file: output/ex20adj_4.out

377:     test:
378:       requires: revolve
379:       suffix: 10
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_revolve_online -ts_trajectory_solution_only
381:       output_file: output/ex20adj_2.out

383:     test:
384:       requires: revolve
385:       suffix: 11
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_revolve_online -ts_trajectory_solution_only 0
387:       output_file: output/ex20adj_2.out

389:     test:
390:       suffix: 12
391:       requires: revolve
392:       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
393:       output_file: output/ex20adj_2.out

395:     test:
396:       suffix: 13
397:       requires: revolve
398:       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
399:       output_file: output/ex20adj_2.out

401:     test:
402:       suffix: 14
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_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack
405:       output_file: output/ex20adj_2.out

407:     test:
408:       suffix: 15
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_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack 0
411:       output_file: output/ex20adj_2.out

413:     test:
414:       suffix: 16
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 0 -ts_trajectory_save_stack
417:       output_file: output/ex20adj_2.out

419:     test:
420:       suffix: 17
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 0 -ts_trajectory_save_stack 0
423:       output_file: output/ex20adj_2.out

425:     test:
426:       suffix: 18
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_max_cps_disk 8 -ts_trajectory_stride 5 -ts_trajectory_solution_only -ts_trajectory_save_stack
429:       output_file: output/ex20adj_2.out

431:     test:
432:       suffix: 19
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_max_cps_disk 8 -ts_trajectory_stride 5 -ts_trajectory_solution_only 0 -ts_trajectory_save_stack
435:       output_file: output/ex20adj_2.out

437:     test:
438:       suffix: 20
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_solution_only 0
441:       output_file: output/ex20adj_2.out

443:     test:
444:       suffix: 21
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 0
447:       output_file: output/ex20adj_2.out

449:     test:
450:       suffix: 22
451:       args: -ts_type beuler -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_solution_only
452:       output_file: output/ex20adj_2.out

454:     test:
455:       suffix: 23
456:       requires: cams
457:       args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_units_ram 5 -ts_trajectory_solution_only -ts_trajectory_monitor -ts_trajectory_memory_type cams
458:       output_file: output/ex20adj_5.out

460:     test:
461:       suffix: 24
462:       requires: cams
463:       args: -ts_type cn -ts_dt 0.001 -mu 100000 -ts_max_steps 15 -ts_trajectory_type memory -ts_trajectory_max_units_ram 5 -ts_trajectory_solution_only 0 -ts_trajectory_monitor -ts_trajectory_memory_type cams
464:       output_file: output/ex20adj_6.out

466: TEST*/