xref: /petsc/src/ts/tutorials/ex41.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
1 static char help[] = "Parallel bouncing ball example to test TS event feature.\n";
2 
3 /*
4   The dynamics of the bouncing ball is described by the ODE
5                   u1_t = u2
6                   u2_t = -9.8
7 
8   Each processor is assigned one ball.
9 
10   The event function routine checks for the ball hitting the
11   ground (u1 = 0). Every time the ball hits the ground, its velocity u2 is attenuated by
12   a factor of 0.9 and its height set to 1.0*rank.
13 */
14 
15 #include <petscts.h>
16 
17 PetscErrorCode EventFunction(TS ts, PetscReal t, Vec U, PetscScalar *fvalue, void *ctx) {
18   const PetscScalar *u;
19 
20   PetscFunctionBeginUser;
21   /* Event for ball height */
22   PetscCall(VecGetArrayRead(U, &u));
23   fvalue[0] = u[0];
24   PetscCall(VecRestoreArrayRead(U, &u));
25   PetscFunctionReturn(0);
26 }
27 
28 PetscErrorCode PostEventFunction(TS ts, PetscInt nevents, PetscInt event_list[], PetscReal t, Vec U, PetscBool forwardsolve, void *ctx) {
29   PetscScalar *u;
30   PetscMPIInt  rank;
31 
32   PetscFunctionBeginUser;
33   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
34   if (nevents) {
35     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Ball hit the ground at t = %5.2f seconds -> Processor[%d]\n", (double)t, rank));
36     /* Set new initial conditions with .9 attenuation */
37     PetscCall(VecGetArray(U, &u));
38     u[0] = 1.0 * rank;
39     u[1] = -0.9 * u[1];
40     PetscCall(VecRestoreArray(U, &u));
41   }
42   PetscFunctionReturn(0);
43 }
44 
45 /*
46      Defines the ODE passed to the ODE solver in explicit form: U_t = F(U)
47 */
48 static PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec F, void *ctx) {
49   PetscScalar       *f;
50   const PetscScalar *u;
51 
52   PetscFunctionBeginUser;
53   /*  The next three lines allow us to access the entries of the vectors directly */
54   PetscCall(VecGetArrayRead(U, &u));
55   PetscCall(VecGetArray(F, &f));
56 
57   f[0] = u[1];
58   f[1] = -9.8;
59 
60   PetscCall(VecRestoreArrayRead(U, &u));
61   PetscCall(VecRestoreArray(F, &f));
62   PetscFunctionReturn(0);
63 }
64 
65 /*
66      Defines the Jacobian of the ODE passed to the ODE solver. See TSSetRHSJacobian() for the meaning the Jacobian.
67 */
68 static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat A, Mat B, void *ctx) {
69   PetscInt           rowcol[2], rstart;
70   PetscScalar        J[2][2];
71   const PetscScalar *u;
72 
73   PetscFunctionBeginUser;
74   PetscCall(VecGetArrayRead(U, &u));
75 
76   PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
77   rowcol[0] = rstart;
78   rowcol[1] = rstart + 1;
79 
80   J[0][0] = 0.0;
81   J[0][1] = 1.0;
82   J[1][0] = 0.0;
83   J[1][1] = 0.0;
84   PetscCall(MatSetValues(B, 2, rowcol, 2, rowcol, &J[0][0], INSERT_VALUES));
85 
86   PetscCall(VecRestoreArrayRead(U, &u));
87   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
88   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
89   if (A != B) {
90     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
91     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
92   }
93   PetscFunctionReturn(0);
94 }
95 
96 /*
97      Defines the ODE passed to the ODE solver in implicit form: F(U_t,U) = 0
98 */
99 static PetscErrorCode IFunction(TS ts, PetscReal t, Vec U, Vec Udot, Vec F, void *ctx) {
100   PetscScalar       *f;
101   const PetscScalar *u, *udot;
102 
103   PetscFunctionBeginUser;
104   /*  The next three lines allow us to access the entries of the vectors directly */
105   PetscCall(VecGetArrayRead(U, &u));
106   PetscCall(VecGetArrayRead(Udot, &udot));
107   PetscCall(VecGetArray(F, &f));
108 
109   f[0] = udot[0] - u[1];
110   f[1] = udot[1] + 9.8;
111 
112   PetscCall(VecRestoreArrayRead(U, &u));
113   PetscCall(VecRestoreArrayRead(Udot, &udot));
114   PetscCall(VecRestoreArray(F, &f));
115   PetscFunctionReturn(0);
116 }
117 
118 /*
119      Defines the Jacobian of the ODE passed to the ODE solver. See TSSetIJacobian() for the meaning of a and the Jacobian.
120 */
121 static PetscErrorCode IJacobian(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal a, Mat A, Mat B, void *ctx) {
122   PetscInt           rowcol[2], rstart;
123   PetscScalar        J[2][2];
124   const PetscScalar *u, *udot;
125 
126   PetscFunctionBeginUser;
127   PetscCall(VecGetArrayRead(U, &u));
128   PetscCall(VecGetArrayRead(Udot, &udot));
129 
130   PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
131   rowcol[0] = rstart;
132   rowcol[1] = rstart + 1;
133 
134   J[0][0] = a;
135   J[0][1] = -1.0;
136   J[1][0] = 0.0;
137   J[1][1] = a;
138   PetscCall(MatSetValues(B, 2, rowcol, 2, rowcol, &J[0][0], INSERT_VALUES));
139 
140   PetscCall(VecRestoreArrayRead(U, &u));
141   PetscCall(VecRestoreArrayRead(Udot, &udot));
142 
143   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
144   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
145   if (A != B) {
146     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
147     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
148   }
149   PetscFunctionReturn(0);
150 }
151 
152 int main(int argc, char **argv) {
153   TS           ts; /* ODE integrator */
154   Vec          U;  /* solution will be stored here */
155   PetscMPIInt  rank;
156   PetscInt     n = 2;
157   PetscScalar *u;
158   PetscInt     direction = -1;
159   PetscBool    terminate = PETSC_FALSE;
160   PetscBool    rhs_form = PETSC_FALSE, hist = PETSC_TRUE;
161   TSAdapt      adapt;
162 
163   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
164      Initialize program
165      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
166   PetscFunctionBeginUser;
167   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
168   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
169 
170   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
171      Create timestepping solver context
172      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
173   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
174   PetscCall(TSSetType(ts, TSROSW));
175 
176   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
177      Set ODE routines
178    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
179   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
180   /* Users are advised against the following branching and code duplication.
181      For problems without a mass matrix like the one at hand, the RHSFunction
182      (and companion RHSJacobian) interface is enough to support both explicit
183      and implicit timesteppers. This tutorial example also deals with the
184      IFunction/IJacobian interface for demonstration and testing purposes. */
185   PetscCall(PetscOptionsGetBool(NULL, NULL, "-rhs-form", &rhs_form, NULL));
186   if (rhs_form) {
187     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, NULL));
188     PetscCall(TSSetRHSJacobian(ts, NULL, NULL, RHSJacobian, NULL));
189   } else {
190     PetscCall(TSSetIFunction(ts, NULL, IFunction, NULL));
191     PetscCall(TSSetIJacobian(ts, NULL, NULL, IJacobian, NULL));
192   }
193 
194   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
195      Set initial conditions
196    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
197   PetscCall(VecCreate(PETSC_COMM_WORLD, &U));
198   PetscCall(VecSetSizes(U, n, PETSC_DETERMINE));
199   PetscCall(VecSetUp(U));
200   PetscCall(VecGetArray(U, &u));
201   u[0] = 1.0 * rank;
202   u[1] = 20.0;
203   PetscCall(VecRestoreArray(U, &u));
204   PetscCall(TSSetSolution(ts, U));
205 
206   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
207      Set solver options
208    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
209   PetscCall(TSSetSaveTrajectory(ts));
210   PetscCall(TSSetMaxTime(ts, 30.0));
211   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
212   PetscCall(TSSetTimeStep(ts, 0.1));
213   /* The adaptive time step controller could take very large timesteps resulting in
214      the same event occurring multiple times in the same interval. A maximum step size
215      limit is enforced here to avoid this issue. */
216   PetscCall(TSGetAdapt(ts, &adapt));
217   PetscCall(TSAdaptSetType(adapt, TSADAPTBASIC));
218   PetscCall(TSAdaptSetStepLimits(adapt, 0.0, 0.5));
219 
220   /* Set direction and terminate flag for the event */
221   PetscCall(TSSetEventHandler(ts, 1, &direction, &terminate, EventFunction, PostEventFunction, NULL));
222 
223   PetscCall(TSSetFromOptions(ts));
224 
225   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
226      Run timestepping solver
227      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
228   PetscCall(TSSolve(ts, U));
229 
230   if (hist) { /* replay following history */
231     TSTrajectory tj;
232     PetscReal    tf, t0, dt;
233 
234     PetscCall(TSGetTime(ts, &tf));
235     PetscCall(TSSetMaxTime(ts, tf));
236     PetscCall(TSSetStepNumber(ts, 0));
237     PetscCall(TSRestartStep(ts));
238     PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
239     PetscCall(TSSetFromOptions(ts));
240     PetscCall(TSSetEventHandler(ts, 1, &direction, &terminate, EventFunction, PostEventFunction, NULL));
241     PetscCall(TSGetAdapt(ts, &adapt));
242     PetscCall(TSAdaptSetType(adapt, TSADAPTHISTORY));
243     PetscCall(TSGetTrajectory(ts, &tj));
244     PetscCall(TSAdaptHistorySetTrajectory(adapt, tj, PETSC_FALSE));
245     PetscCall(TSAdaptHistoryGetStep(adapt, 0, &t0, &dt));
246     /* this example fails with single (or smaller) precision */
247 #if defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL__FP16)
248     PetscCall(TSAdaptSetType(adapt, TSADAPTBASIC));
249     PetscCall(TSAdaptSetStepLimits(adapt, 0.0, 0.5));
250     PetscCall(TSSetFromOptions(ts));
251 #endif
252     PetscCall(TSSetTime(ts, t0));
253     PetscCall(TSSetTimeStep(ts, dt));
254     PetscCall(TSResetTrajectory(ts));
255     PetscCall(VecGetArray(U, &u));
256     u[0] = 1.0 * rank;
257     u[1] = 20.0;
258     PetscCall(VecRestoreArray(U, &u));
259     PetscCall(TSSolve(ts, U));
260   }
261   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
262      Free work space.  All PETSc objects should be destroyed when they are no longer needed.
263      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
264   PetscCall(VecDestroy(&U));
265   PetscCall(TSDestroy(&ts));
266 
267   PetscCall(PetscFinalize());
268   return 0;
269 }
270 
271 /*TEST
272 
273    test:
274       suffix: a
275       nsize: 2
276       args: -ts_trajectory_type memory -snes_stol 1e-4
277       filter: sort -b
278 
279    test:
280       suffix: b
281       nsize: 2
282       args: -ts_trajectory_type memory -ts_type arkimex -snes_stol 1e-4
283       filter: sort -b
284 
285    test:
286       suffix: c
287       nsize: 2
288       args: -ts_trajectory_type memory -ts_type theta -ts_adapt_type basic -ts_atol 1e-1 -snes_stol 1e-4
289       filter: sort -b
290 
291    test:
292       suffix: d
293       nsize: 2
294       args: -ts_trajectory_type memory -ts_type alpha -ts_adapt_type basic -ts_atol 1e-1 -snes_stol 1e-4
295       filter: sort -b
296 
297    test:
298       suffix: e
299       nsize: 2
300       args: -ts_trajectory_type memory -ts_type bdf -ts_adapt_dt_max 0.015 -ts_max_steps 3000
301       filter: sort -b
302 
303    test:
304       suffix: f
305       nsize: 2
306       args: -ts_trajectory_type memory -rhs-form -ts_type rk -ts_rk_type 3bs
307       filter: sort -b
308 
309    test:
310       suffix: g
311       nsize: 2
312       args: -ts_trajectory_type memory -rhs-form -ts_type rk -ts_rk_type 5bs
313       filter: sort -b
314 
315    test:
316       suffix: h
317       nsize: 2
318       args: -ts_trajectory_type memory -rhs-form -ts_type rk -ts_rk_type 6vr
319       filter: sort -b
320       output_file: output/ex41_g.out
321 
322    test:
323       suffix: i
324       nsize: 2
325       args: -ts_trajectory_type memory -rhs-form -ts_type rk -ts_rk_type 7vr
326       filter: sort -b
327       output_file: output/ex41_g.out
328 
329    test:
330       suffix: j
331       nsize: 2
332       args: -ts_trajectory_type memory -rhs-form -ts_type rk -ts_rk_type 8vr
333       filter: sort -b
334       output_file: output/ex41_g.out
335 
336 TEST*/
337