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.

Link

Web site

Language

C

License

BSD 2-clause license

Repository

GitLab

Lorenz equations#

We would like to solve the Lorenz equations, a classical chaotic system given by:

\[\begin{split} \begin{cases} \dot{x} &= \sigma (y - x) \\ \dot{y} &= \rho x - y - x z \\ \dot{z} &= x y - \beta z \end{cases} \end{split}\]

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:

\[ \dot{u} = f(t, u) \]

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:

\[ \partial_t u + a \partial_x u = 0 \]

with \(t>0\), on the torus \(x\in[0, 1)\), a velocity \(a=1\) and the initial condition given by a hat function:

\[\begin{split} u(0, x) = \begin{cases} x - 0.25 & \text{if } x\in[0.25, 0.5[ \\ -x + 0.75 & \text{if } x\in[0.5, 0.75[ \\ 0 & \text{else} \end{cases} \end{split}\]

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:

\[\begin{split} \begin{cases} \ddot{x} &= x + 2\dot{y} - \frac{1-\mu}{r_1^3}(x+\mu) - \frac{\mu}{r_2^3}(x-1+\mu) \\ \ddot{y} &= y - 2\dot{x} - \frac{}{1-\mu}{r_1^3}y - \frac{\mu}{r_2^3}y \end{cases} \end{split}\]

with initial condition \((x,\dot{x},y,\dot{y})=(0.994, 0, 0, -2.001585106)\), \(r_1\) and \(r_2\) given by

\[ r_1 = \sqrt{(x+\mu)^2 + y^2},\quad r_2 = \sqrt{(x-1+\mu)^2 + y^2} \]

and with parameter \(\mu = 0.012277471\).

First of all, we need to rewrite this problem into a first order derivative equation in time

\[\begin{split} \begin{pmatrix} y_1 \\ y_2 \\ y_3 \\ y_4 \end{pmatrix} = \begin{pmatrix} x \\ y \\ \dot{x} \\ \dot{y} \end{pmatrix}, \qquad \begin{cases} \dot{y}_1 = y_3 \\ \dot{y}_2 = y_4 \\ \dot{y}_3 = y_1 + 2y_4 - \frac{1-\mu}{r_1^3}(y_1 + \mu) - \frac{\mu}{r_2^3}(y_1-1+\mu) \\ \dot{y}_4 = y_2 - 2y_3 - \frac{1-\mu}{r_1^3}y_2 - \frac{\mu}{r_2^3}y_2 \\ \end{cases} \end{split}\]

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.