PETSc - Portable, Extensible Toolkit for Scientific Computation#
PETSc, pronounced PET-see (the S is silent), is a suite of data structures and routines for the scalable (parallel) solution of scientific applications modeled by partial differential equations.
Lorenz equations#
We would like to solve the Lorenz equations, a classical chaotic system given by:
with parameter \(\sigma=10\), \(\rho = 28\) and \(\beta = \frac{8}{3}\), and the initial state \((x_0, y_0, z_0) = (1,1,1)\). We solve it with a classical Runge-Kutta method of order 4, given by TSRK4 method.
To solve a problem with PETSc we first write our equation as a ODE of the form:
and the user provide the function \(f\) as:
PetscErrorCode f(TS ts, double t, Vec u, Vec du, void* params);
where u the current state of the function, t the current time and output du \(f(t,u)\), and ts the time stepper.
3PetscErrorCode lorenz(TS ts, double t, Vec vec_y, Vec vec_ydot, void* params)
4{
5 double sigma = ((double *)params)[0];
6 double rho = ((double *)params)[1];
7 double beta = ((double *)params)[2];
8
9 const double* y;
10 double* ydot;
11
12 VecGetArrayRead(vec_y, &y);
13 VecGetArray(vec_ydot, &ydot);
14
15 ydot[0] = sigma*( y[1] - y[0] );
16 ydot[1] = rho*y[0] - y[1] - y[0]*y[2];
17 ydot[2] = y[0]*y[1] - beta*y[2];
18
19 VecRestoreArray(vec_ydot, &ydot);
20 VecRestoreArrayRead(vec_y, &y);
21
22 return PETSC_SUCCESS;
23}
Next we need to define a time stepper and set all parameters, and give it the \(f\) function
43 TS ts;
44 TSCreate(PETSC_COMM_SELF, &ts);
45 TSSetType(ts, TSRK);
46 TSRKSetType(ts, TSRK4);
47
48 TSSetTime(ts, 0.);
49 TSSetMaxTime(ts, tf);
50 TSSetTimeStep(ts, dt);
51
52 TSSetRHSFunction(ts, NULL, lorenz, params);
now we can call the time stepper by:
TSStep(ts);
and get current state and time with TSGetSolution TSGetTime functions. The complet time loop is
66 while( tn < tf )
67 {
68 TSGetStepNumber(ts, &n_step);
69 TSGetSolution(ts, &vec_yn);
70 VecGetArray(vec_yn, &yn);
71
72 sol[n_step][0] = tn;
73 sol[n_step][1] = yn[0];
74 sol[n_step][2] = yn[1];
75 sol[n_step][3] = yn[2];
76
77 VecRestoreArray(vec_yn, &yn);
78
79 TSStep(ts);
80
81 TSGetTime(ts, &tn);
82 }
where sol is an array to store all states.
For the complet example, see lorenz.c source file.
Transport equation#
In this example we would like to solve the following PDE:
with \(t>0\), on the torus \(x\in[0, 1)\), a velocity \(a=1\) and the initial condition given by a hat function:
We choose a first order up-wind scheme to estimate the \(x\) derivative and a forward Euler method for the time discretization given by TSRK1FE method.
We define the up-wind scheme as:
3PetscErrorCode
4transport( TS ts, double t, Vec vec_y, Vec vec_dy, void* params )
5{
6 double a = ( (double*)params )[0];
7 double dx = ( (double*)params )[1];
8 int n_x = ( (double*)params )[2];
9
10 double const* y;
11 double* dy;
12
13 VecGetArrayRead( vec_y, &y );
14 VecGetArray( vec_dy, &dy );
15
16 dy[0] = -( fmax( a, 0. ) * ( y[0] - y[n_x - 1] ) + fmin( a, 0. ) * ( y[1] - y[0] ) ) / dx;
17
18 for ( int i = 1; i < n_x - 1; ++i )
19 {
20 dy[i] = -( fmax( a, 0. ) * ( y[i] - y[i - 1] ) + fmin( a, 0. ) * ( y[i + 1] - y[i] ) ) / dx;
21 }
22
23 dy[n_x - 1] = -( fmax( a, 0. ) * ( y[n_x - 1] - y[n_x - 2] ) + fmin( a, 0. ) * ( y[0] - y[n_x - 1] ) ) / dx;
24
25 VecRestoreArray( vec_dy, &dy );
26 VecRestoreArrayRead( vec_y, &y );
27
28 return PETSC_SUCCESS;
29}
The time loop is the same as for Lorenz equation.
For the complet example, see transport.c source file.
Arenstorf orbit#
The Arenstorf orbit problem is a classical problem to test adaptive time step methods:
with initial condition \((x,\dot{x},y,\dot{y})=(0.994, 0, 0, -2.001585106)\), \(r_1\) and \(r_2\) given by
and with parameter \(\mu = 0.012277471\).
First of all, we need to rewrite this problem into a first order derivative equation in time
We define this system as:
3PetscErrorCode arenstorf(TS ts, double t, Vec vec_y, Vec vec_ydot, void* params)
4{
5 double mu = *(double *)params;
6
7 const double* y;
8 double* ydot;
9
10 VecGetArrayRead(vec_y, &y);
11 VecGetArray(vec_ydot, &ydot);
12
13 double const y1 = y[0];
14 double const y2 = y[1];
15 double const y3 = y[2];
16 double const y4 = y[3];
17
18 double const r1 = sqrt( ( y1 + mu ) * ( y1 + mu ) + y2 * y2 );
19 double const r2 = sqrt( ( y1 - 1. + mu ) * ( y1 - 1. + mu ) + y2 * y2 );
20
21 ydot[0] = y3;
22 ydot[1] = y4;
23 ydot[2] = y1 + 2. * y4 - ( 1. - mu ) * ( y1 + mu ) / ( r1 * r1 * r1 ) - mu * ( y1 - 1. + mu ) / ( r2 * r2 * r2 );
24 ydot[3] = y2 - 2. * y3 - ( 1. - mu ) * y2 / ( r1 * r1 * r1 ) - mu * y2 / ( r2 * r2 * r2 );
25
26 VecRestoreArray(vec_ydot, &ydot);
27 VecRestoreArrayRead(vec_y, &y);
28
29 return PETSC_SUCCESS;
30}
We solve this example with given method TSRK5DP which is the method RK8(7) 13M in [PD81] (mainly call DOPRI8). For this we need to set the integrator and settings for adaptive time step method
50 TS ts;
51 TSCreate(PETSC_COMM_SELF, &ts);
52 TSSetType(ts, TSRK);
53 TSRKSetType(ts, TSRK5DP);
54 TSSetTolerances(ts, 1e-5, NULL, 1e-5, NULL);
55
56 TSSetTime(ts, 0.);
57 TSSetMaxTime(ts, tf);
58 TSSetTimeStep(ts, dt);
59
60 TSSetRHSFunction(ts, NULL, arenstorf, &mu);
then the time loop becomes
74 while( tn < tf )
75 {
76 TSGetStepNumber(ts, &n_step);
77 TSGetTimeStep(ts, &dt);
78 TSGetSolution(ts, &vec_yn);
79 VecGetArray(vec_yn, &yn);
80
81 sol[n_step][0] = tn;
82 sol[n_step][1] = yn[0];
83 sol[n_step][2] = yn[1];
84 sol[n_step][3] = yn[2];
85 sol[n_step][4] = yn[3];
86 sol[n_step][5] = dt;
87
88 VecRestoreArray(vec_yn, &yn);
89
90 TSStep(ts);
91
92 TSGetTime(ts, &tn);
93 }
For the complet example, see arenstorf.c source file.