8.2 Résolution d'un système d'équations différentielles ordinaires

La fonction odeint permet de résoudre numériquement un système d'équations différentielles ordinaires (EDO) du premier ordre de la forme : \[ \left\{ \begin{array}{rcl} \dot{\vec y} (t) &=& \vec f(\vec y(t), t) \,, \\ \vec y(t_0) &=& \vec y_0 \,, \end{array} \right. \] et d'obtenir une approximation \(\vec y(t)\) de l'évolution du système pour des temps \(t\) supérieurs à \(t_0\). Ainsi, il est par exemple possible de résoudre l'équation (vectorielle) du pendule simple que nous étudions dans la série 24 en considérant le système: \[ \left\{ \begin{array}{rcl} \begin{pmatrix} \dot\theta \\ \dot v \end{pmatrix} &=& \begin{pmatrix} v \\ -\omega_{0}^{\,2}\sin\theta \end{pmatrix} \,, \\ \\ \begin{pmatrix} \theta (0) \\ v(0) \end{pmatrix} &=& \begin{pmatrix} \theta_0 \\ v_0 \end{pmatrix}\,. \end{array} \right. \] Les constantes \(\theta_0\) et \(v_0\) correspondent aux deux conditions initiales et \(\omega_{0}^{\,2} = g/L\) (où \(L\) est la longueur du fil). La fonction odeint retourne alors un vecteur solution : \[ \vec y(t) = \begin{pmatrix} \theta (t) \\ v(t) \end{pmatrix}\,. \] Ainsi, le code permettant de résoudre l'EDO du pendule simple pourrait débuter de la manière suivante :

import numpy as np import matplotlib.pyplot as plt from scipy.integrate import odeint g = 9.81 ; L = 2 ; omegazerocarre = g/L # constantes y_0 = np.array([np.pi/6, 0.0]) # vecteur conditions initiales # ou : y_0 = [np.pi/6, 0.0]

On définit ensuite le membre de droite de l'EDO, f(t,y), sous forme vectorielle :

def f(t, y): theta, v = y return [v, -omegazerocarre*np.sin(theta)]

Cette fonction retourne un tableau de la même forme (shape) que y.

Il est également nécessaire de construire un vecteur temps dont les éléments correspondent aux instants \(t_n\) pour lesquels nous souhaitons obtenir une valeur approchée de la solution \(y\) (la première entrée de ce tableau devant être la valeur initiale \(t_0\)) :

t_0 = 0 ; T = 10 ; N = 200 # N est le nombre de sous-intervalles t = np.linspace(t_0, T, N+1) # vecteur contenant N+1 elements t_n

Il convient de noter que la partition choisie au moment de la construction de t ne sera pas prise en compte par odeint pour la résolution numérique du problème. En effet, odeint va adapter le pas \(h\) utilisé en fonction de deux valeurs (qui correspondent à des tolérances relative et absolue) fournissant une majoration de l'erreur locale. Ces valeurs rtol et atol sont des keyword arguments valant par défaut environ \(1.5\cdot 10^{-8}\). La solution approchée aux instants donnés par t est ensuite obtenue par interpolation.

La ligne suivante fournit un tableau solution de dimension \(2\) de forme (N+1,2) (à savoir ici (201,2)) :

sol = odeint(f, y_0, t, tfirst=True)

Le paramètre optionnel tfirst permet de préciser la position de la variable t dans la fonction f : f(y,t) ou f(t,y).

Les solutions peuvent alors être ''décompactées'' :

angle = sol[:,0] vitesse_angulaire = sol[:,1]

\dots\,et visualisées de manière habituelle :

plt.figure(figsize=(12,8)) plt.plot(t, angle, label=r"angle ${\theta(t)}$") plt.plot(t, vitesse_angulaire, label=r"vitesse angulaire "\ r"$\dot\theta(t)$") plt.grid() plt.title("Solutions pour le pendule simple "\ r"(avec $\theta_0 = {\pi/6}$ et $\dot\theta_0 = {0}$)") plt.xlabel('t') plt.legend(loc='best') plt.show()

Figure générée :

Le mouvement d'un pendule simple peut également être illustré en représentant la solution dans un espace particulier, appelé espace de phase avec \(\theta\) en abscisse et \(\dot\theta\) en ordonnée :

plt.figure(figsize=(12,8)) plt.plot([min(angle),max(angle)],[0, 0],c='k') plt.plot([0,0],[min(vitesse_angulaire),max(vitesse_angulaire)],c='k') plt.plot(angle,vitesse_angulaire) plt.plot([y_0[0]],[y_0[1]],'or') plt.grid() plt.title(r"Représentation dans l'espace de phase "\ rf"($\theta$,$\dot\theta$) de la solution correspondant "\ rf"à $\theta_0 = {y_0[0]:.4f}$ et $\dot\theta_0 = {y_0[1]}$") plt.xlabel(r'$\theta$') plt.ylabel(r'$\dot\theta$') plt.show()

Figure générée :

Trois couples différents de conditions initiales (points rouges) fournissent trois courbes différentes :

Trajectoires et champ de directions :