xref: /petsc/src/ts/tutorials/ex44.c (revision 8fb5bd83c3955fefcf33a54e3bb66920a9fa884b)
1 static char help[] = "Parallel bouncing ball example formulated as a second-order system to test TS event feature.\n";
2 
3 /*
4   The dynamics of the bouncing ball with drag coefficient Cd is described by the ODE
5 
6       u_tt = -9.8 - 1/2 Cd (u_t)^2 sign(u_t)
7 
8   There are two events set in this example. The first one checks for the ball hitting the
9   ground (u = 0). Every time the ball hits the ground, its velocity u_t is attenuated by
10   a restitution coefficient Cr. The second event sets a limit on the number of ball bounces.
11 */
12 
13 #include <petscts.h>
14 
15 typedef struct {
16   PetscReal Cd;      /* drag coefficient */
17   PetscReal Cr;      /* restitution coefficient */
18   PetscInt  bounces;
19   PetscInt  maxbounces;
20 } AppCtx;
21 
22 static PetscErrorCode Event(TS ts,PetscReal t,Vec U,PetscScalar *fvalue,void *ctx)
23 {
24   AppCtx            *app = (AppCtx*)ctx;
25   Vec               V;
26   const PetscScalar *u,*v;
27 
28   PetscFunctionBegin;
29   /* Event for ball height */
30   PetscCall(TS2GetSolution(ts,&U,&V));
31   PetscCall(VecGetArrayRead(U,&u));
32   PetscCall(VecGetArrayRead(V,&v));
33   fvalue[0] = u[0];
34   /* Event for number of bounces */
35   fvalue[1] = app->maxbounces - app->bounces;
36   PetscCall(VecRestoreArrayRead(U,&u));
37   PetscCall(VecRestoreArrayRead(V,&v));
38   PetscFunctionReturn(0);
39 }
40 
41 static PetscErrorCode PostEvent(TS ts,PetscInt nevents,PetscInt event_list[],PetscReal t,Vec U,PetscBool forwardsolve,void* ctx)
42 {
43   AppCtx         *app = (AppCtx*)ctx;
44   Vec            V;
45   PetscScalar    *u,*v;
46   PetscMPIInt    rank;
47 
48   PetscFunctionBegin;
49   if (!nevents) PetscFunctionReturn(0);
50   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
51   if (event_list[0] == 0) {
52     PetscCall(PetscPrintf(PETSC_COMM_SELF,"Processor [%d]: Ball hit the ground at t = %5.2f seconds\n",rank,(double)t));
53     /* Set new initial conditions with .9 attenuation */
54     PetscCall(TS2GetSolution(ts,&U,&V));
55     PetscCall(VecGetArray(U,&u));
56     PetscCall(VecGetArray(V,&v));
57     u[0] = 0.0; v[0] = -app->Cr*v[0];
58     PetscCall(VecRestoreArray(U,&u));
59     PetscCall(VecRestoreArray(V,&v));
60     app->bounces++;
61   } else if (event_list[0] == 1) {
62     PetscCall(PetscPrintf(PETSC_COMM_SELF,"Processor [%d]: Ball bounced %" PetscInt_FMT " times\n",rank,app->bounces));
63   }
64   PetscFunctionReturn(0);
65 }
66 
67 static PetscErrorCode I2Function(TS ts,PetscReal t,Vec U,Vec V,Vec A,Vec F,void *ctx)
68 {
69   AppCtx            *app = (AppCtx*)ctx;
70   const PetscScalar *u,*v,*a;
71   PetscScalar       Res,*f;
72 
73   PetscFunctionBegin;
74   PetscCall(VecGetArrayRead(U,&u));
75   PetscCall(VecGetArrayRead(V,&v));
76   PetscCall(VecGetArrayRead(A,&a));
77   Res = a[0] + 9.8 + 0.5 * app->Cd * v[0]*v[0] * PetscSignReal(PetscRealPart(v[0]));
78   PetscCall(VecRestoreArrayRead(U,&u));
79   PetscCall(VecRestoreArrayRead(V,&v));
80   PetscCall(VecRestoreArrayRead(A,&a));
81 
82   PetscCall(VecGetArray(F,&f));
83   f[0] = Res;
84   PetscCall(VecRestoreArray(F,&f));
85   PetscFunctionReturn(0);
86 }
87 
88 static PetscErrorCode I2Jacobian(TS ts,PetscReal t,Vec U,Vec V,Vec A,PetscReal shiftV,PetscReal shiftA,Mat J,Mat P,void *ctx)
89 {
90   AppCtx            *app = (AppCtx*)ctx;
91   const PetscScalar *u,*v,*a;
92   PetscInt          i;
93   PetscScalar       Jac;
94 
95   PetscFunctionBegin;
96   PetscCall(VecGetArrayRead(U,&u));
97   PetscCall(VecGetArrayRead(V,&v));
98   PetscCall(VecGetArrayRead(A,&a));
99   Jac  = shiftA + shiftV * app->Cd * v[0];
100   PetscCall(VecRestoreArrayRead(U,&u));
101   PetscCall(VecRestoreArrayRead(V,&v));
102   PetscCall(VecRestoreArrayRead(A,&a));
103 
104   PetscCall(MatGetOwnershipRange(P,&i,NULL));
105   PetscCall(MatSetValue(P,i,i,Jac,INSERT_VALUES));
106   PetscCall(MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY));
107   PetscCall(MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY));
108   if (J != P) {
109     PetscCall(MatAssemblyBegin(P,MAT_FINAL_ASSEMBLY));
110     PetscCall(MatAssemblyEnd(P,MAT_FINAL_ASSEMBLY));
111   }
112   PetscFunctionReturn(0);
113 }
114 
115 int main(int argc,char **argv)
116 {
117   TS             ts;            /* ODE integrator */
118   Vec            U,V;           /* solution will be stored here */
119   Vec            F;             /* residual vector */
120   Mat            J;             /* Jacobian matrix */
121   PetscMPIInt    rank;
122   PetscScalar    *u,*v;
123   AppCtx         app;
124   PetscInt       direction[2];
125   PetscBool      terminate[2];
126   TSAdapt        adapt;
127 
128   PetscCall(PetscInitialize(&argc,&argv,NULL,help));
129   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
130 
131   app.Cd = 0.0;
132   app.Cr = 0.9;
133   app.bounces = 0;
134   app.maxbounces = 10;
135   PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"ex44 options","");
136   PetscCall(PetscOptionsReal("-Cd","Drag coefficient","",app.Cd,&app.Cd,NULL));
137   PetscCall(PetscOptionsReal("-Cr","Restitution coefficient","",app.Cr,&app.Cr,NULL));
138   PetscCall(PetscOptionsInt("-maxbounces","Maximum number of bounces","",app.maxbounces,&app.maxbounces,NULL));
139   PetscOptionsEnd();
140 
141   PetscCall(TSCreate(PETSC_COMM_WORLD,&ts));
142   /*PetscCall(TSSetSaveTrajectory(ts));*/
143   PetscCall(TSSetProblemType(ts,TS_NONLINEAR));
144   PetscCall(TSSetType(ts,TSALPHA2));
145 
146   PetscCall(TSSetMaxTime(ts,PETSC_INFINITY));
147   PetscCall(TSSetTimeStep(ts,0.1));
148   PetscCall(TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER));
149   PetscCall(TSGetAdapt(ts,&adapt));
150   PetscCall(TSAdaptSetStepLimits(adapt,0.0,0.5));
151 
152   direction[0] = -1; terminate[0] = PETSC_FALSE;
153   direction[1] = -1; terminate[1] = PETSC_TRUE;
154   PetscCall(TSSetEventHandler(ts,2,direction,terminate,Event,PostEvent,&app));
155 
156   PetscCall(MatCreateAIJ(PETSC_COMM_WORLD,1,1,PETSC_DECIDE,PETSC_DECIDE,1,NULL,0,NULL,&J));
157   PetscCall(MatSetFromOptions(J));
158   PetscCall(MatSetUp(J));
159   PetscCall(MatCreateVecs(J,NULL,&F));
160   PetscCall(TSSetI2Function(ts,F,I2Function,&app));
161   PetscCall(TSSetI2Jacobian(ts,J,J,I2Jacobian,&app));
162   PetscCall(VecDestroy(&F));
163   PetscCall(MatDestroy(&J));
164 
165   PetscCall(TSGetI2Jacobian(ts,&J,NULL,NULL,NULL));
166   PetscCall(MatCreateVecs(J,&U,NULL));
167   PetscCall(MatCreateVecs(J,&V,NULL));
168   PetscCall(VecGetArray(U,&u));
169   PetscCall(VecGetArray(V,&v));
170   u[0] = 5.0*rank; v[0] = 20.0;
171   PetscCall(VecRestoreArray(U,&u));
172   PetscCall(VecRestoreArray(V,&v));
173 
174   PetscCall(TS2SetSolution(ts,U,V));
175   PetscCall(TSSetFromOptions(ts));
176   PetscCall(TSSolve(ts,NULL));
177 
178   PetscCall(VecDestroy(&U));
179   PetscCall(VecDestroy(&V));
180   PetscCall(TSDestroy(&ts));
181 
182   PetscCall(PetscFinalize());
183   return 0;
184 }
185 
186 /*TEST
187 
188     test:
189       suffix: a
190       args: -ts_alpha_radius {{1.0 0.5}}
191       output_file: output/ex44.out
192 
193     test:
194       suffix: b
195       args: -ts_rtol 0 -ts_atol 1e-1 -ts_adapt_type basic
196       output_file: output/ex44.out
197 
198     test:
199       suffix: 2
200       nsize: 2
201       args: -ts_rtol 0 -ts_atol 1e-1 -ts_adapt_type basic
202       output_file: output/ex44_2.out
203       filter: sort -b
204       filter_output: sort -b
205 
206     test:
207       requires: !single
208       args: -ts_dt 0.25 -ts_adapt_type basic -ts_adapt_wnormtype INFINITY -ts_adapt_monitor
209       args: -ts_max_steps 1 -ts_max_reject {{0 1 2}separate_output} -ts_error_if_step_fails false
210 
211 TEST*/
212