Des méthodes numériques (Euler implicite) - Partie 3

Nous apprenons comment et quand utiliser des méthodes numériques implicites.

Keywords: les force newtoniennes, des méthodes numériques, maths, les simulations physiques

By Carmen Cincotti  

Cette semaine était chargée en maths ! J’ai continué à lire comme d’habitude Pixar Physics Simulation Animation Course, en particulier l’article sur des méthodes numériques implicites.

Il s’agit de résoudre des EDOs (équations différentielles ordinaires), considérées comme ‘raide’. On va voir pourquoi nous qualifions ces ODEs de ‘raide’ et comment nous devrions aborder la résolution de ces types d’ODE en utilisant des méthodes numériques implicites telles que la méthode Euler implicite.

⚠️ La ressource de Pixar nous conseille d’éviter une EDO raide en reformulant notre problème dynamique. Nous nous concentrerons sur les cas où cela n’est pas possible.

EDOs raides

Après avoir cherché une définition de ‘équation différentielle ordinaire raide’ sur Internet, j’ai fini par utiliser celle de Wikipédia qui, certes pour moi, n’est pas très suffisante, mais je vais quand même vous la donne :

Une équation différentielle raide est une équation différentielle dont la sensibilité aux paramètres va rendre difficile la résolution par des méthodes numériques explicites.

Bref : des EDOs raides sont difficiles à résoudre avec des méthodes numériques explicites (nous avons parlé des méthodes numériques explicites il y a quelques semaines).

Moi, je trouve que Pixar Physics Simulation Animation Course nous donne un exemple amusant sur lequel on va travailler pour mieux visualiser la définition Wikipédia. Imaginons que l’on veut simuler la dynamique d’une particule dont le changement de position se décrit par l’équation différentielle suivante :

X˙(t)=ddt(x(t)y(t))=(x(t)ky(t)) \dot X(t) = \frac{d}{dt} \begin{pmatrix} x(t) \\ y(t) \end{pmatrix} = \begin{pmatrix} -x(t) \\ -ky(t) \end{pmatrix}

k est une grande constante positive. Si k est suffisamment grande, la particule ne bougera jamais trop loin de y(t)=0y(t) = 0 car ky(t)-ky(t) fera la revenir y(t)y(t) à l’origine. On voit également que l’abscisse de la particule est plus libre de se déplacer, comme décrit par l’absence de cette grande constante positive k.

Dans cet exemple, cette EDO serait donc ‘raide’ si la variable k est si grande que la particule reste proche de la droite y=0y = 0. Comme nous le verrons dans la partie suivante, les méthodes explicites auront du mal à simuler ce comportement attendu.

Le problème avec des méthodes explicites

Rappelons que l’équation de la méthode d’Euler explicite se décrit comme suit :

Xnew=X0+hX˙(t0) X_{new} = X_0 + h\dot X(t_0)

et dans cet exemple, X0=(x0y0)X_0 = \begin{pmatrix} x_0 \\ y_0 \end{pmatrix} et X˙(t)=ddt(x(t0)y(t0))=(x0ky0)\dot X(t) = \frac{d}{dt} \begin{pmatrix} x(t_0) \\ y(t_0) \end{pmatrix} = \begin{pmatrix} -x_0 \\ -ky_0 \end{pmatrix}. Alors, après la substitution :

Xnew=(x0y0)+h(x0ky0) X_{new} = \begin{pmatrix} x_0 \\ y_0 \end{pmatrix} + h\begin{pmatrix} -x_0 \\ -ky_0 \end{pmatrix}

Ce qui produit la suivante :

Xnew=((1h)x0(1hk)y0) X_{new} = \begin{pmatrix} (1 - h)x_0 \\ (1-hk)y_0 \end{pmatrix}

Nous avons appris dans la discussion Partie 1 des méthodes numériques que pour trouver une solution, on doit prendre des petits pas dans le temps afin de s’approcher de la solution, car des pas trop grands pourront rendre le système instable. En réarrangeant les termes dans l’équation, on s’aperçoit rapidement que ces conditions doivent être remplies pour que la position de la particule décrite dans notre exemple se converge vers (0,0) :

xstep:1h<1ystep:1kh<1 x_{step}: | 1 - h | < 1 \\ y_{step}: | 1 - kh | < 1

🚨 Si nous prenons k égal à 1000 : le pas maximum permis est calculé comme suit : 11000h=1=>h=0,002  1 - 1000h = -1 => h = 0,002 . Si on dépasse cette limite, l’ordonnée de la particule ne pourra jamais converger vers 0 !

Résolvez pour y en utilisant la méthode d’Euler explicite les paramètres h=0.0015 et k=1000.0 dans un solveur Euler explicite que j’ai écrit, nous pouvons visualiser l’ordonnée de la particule lorsqu’elle oscille et s’approche autour de zéro :

Euler Explit Graphic h = 0.0015

Voici comment l’ordonnée se converge, ou plutôt se diverge, qu’on utilise une valeur h > 0.002 (h = 0.003 et k = 1000.0): Euler Explit Graphic h = 0.003

OK, nous pourrions donc utiliser un très petit pas comme h = 0.0015 n’est-ce pas ? Peut-être… cependant, on se rendrait vite compte que la valeur d’abscisse bouge trop lentement, ce qui rendra notre simulation trop lente !

x0y0100.000000100.00000099.84999850.00000099.70022625.00000099.55067412.50000099.4013526.25000099.2522513.12500099.1033711.56250098.9547120.78125098.8062820.39062598.6580730.195312\begin{array}{cc} x_0 & y_0 \\ \hline \\ 100.000000 & 100.000000 \\ 99.849998 & -50.000000 \\ 99.700226 & 25.000000 \\ 99.550674 & -12.500000 \\ 99.401352 & 6.250000 \\ 99.252251 & -3.125000 \\ 99.103371 & 1.562500 \\ 98.954712 & -0.781250 \\ 98.806282 & 0.390625 \\ 98.658073 & -0.195312 \\ \end {array}

Pouvons-nous faire mieux ? Pourrions-nous utiliser une méthode plus stable pour se converger plus rapidement ? Oui - avec la méthode d’Euler implicite !

Euler implicite

La méthode d’Euler implicite est la plus simple des méthodes implicites à comprendre et c’est pourquoi je vais me concentrer dessus.

Voici l’équation d’Euler implicite :

Xnew=X0+hX˙new X_{new} = X_0 + h\dot X_{new}

Si vous aviez été quelqu’un d’observateur, vous auriez vu que la différence entre l’équation d’Euler implicite et celle d’Euler explicite est que le changement d’X se définit comme hX˙newh\dot X*{new} dans l’équation d’Euler implicite. Il faut donc résoudre ce changement en calculant X˙new\dot X*{new}… pour calculer enfin X_newX\_{new}.

En fait, c’est comme marcher à reculons.

X0=XnewhX˙new X_0 = X_{new} - h\dot X_{new}

Autrement dit, c’est comme si on était à la position X_newX\_{new} et nous aimerions reculer pour arriver à la position X0X_0. Il faut dire qu’en anglais, Euler implicite s’appelle aussi ‘Backwards Euler’ pour cette raison.

C’est trop de résoudre XnewX*{new}, d’autant plus que nous devons aussi résoudre X˙new\dot X*{new}… qui nous est aussi inconnue. Voyons s’il est possible de réécrire cela dans une équation résoluble.

On commence par fournir l’équation de la méthode d’Euler implicite :

X0+ΔX=X0+hf(X0+ΔX) X_0 + \Delta X = X_0 + hf(X_0 + \Delta X)

ΔX=X_newX0\Delta X = X\_{new} - X_0. Nous pouvons l’écrire comme suit :

ΔX=hf(X0+ΔX) \Delta X = hf(X_0 + \Delta X)

💡 f(X0+ΔX)f(X*0 + \Delta X) est inconnue, et aussi ΔX\Delta X (parce que ΔX=XnewX0\Delta X = X*{new} - X*0 contien XnewX*{new} qui est inconnue). Donc on doit faire une approximation de f(X0+ΔX)f(X_0 + \Delta X) en utilisant la série de Taylor comme suit :

f(X0+ΔX)=f(X0)+ΔXf(X0) f(X_0 + \Delta X) = f(X_0) + \Delta X f'(X_0)

Voyez cette ressource pour en savoir plus sur la série de Taylor et cette dérivation exacte.

En utilisant la dernière équation, on peut réécrire notre équation pour ΔX\Delta X :

ΔX=h(f(X0)+ΔXf(X0))1hΔXΔXf(X0))=f(X0) \Delta X = h(f(X_0) + \Delta X f'(X_0)) \\ \frac{1}{h}\Delta X - \Delta X f'(X_0)) = f(X_0)

💡 Pour continuer, il faut rappeler que f(X0)f(X_0) est un vecteur et f(X0)f'(X_0) est une matrice. Cela est le cas grâce au calcul vectoriel :

[f1(x,y)f2(x,y)]=[f1xf1yf2xf2y] \begin{bmatrix} f_1(x,y) \\ f_2(x,y) \end{bmatrix} = \begin{bmatrix} \dfrac{\partial f_1}{\partial x} & \dfrac{\partial f_1}{\partial y} \\ \dfrac{\partial f_2}{\partial x} & \dfrac{\partial f_2}{\partial y} \end{bmatrix}

La dérivation est appelée la matrice jacobienne. On y reviendra plus en détail dans une partie ultérieure

Nous pouvons tout multiplier par une matrice identité pour isoler notre variable ΔX\Delta X .

1hΔXIΔXf(X0))I=f(X0)IΔX(1hIf(X0))=f(X0)ΔX=(1hIf(X0))1f(X0) \frac{1}{h}\Delta XI - \Delta X f'(X_0))I = f(X_0)I \\ \Delta X(\frac{1}{h}I - f'(X_0)) = f(X_0) \\ \Delta X = (\frac{1}{h}I - f'(X_0))^{-1} f(X_0)

Après avoir isolé ΔX\Delta X, il est dorénavant possible de résoudre X_new=X0+ΔXX\_{new} = X_0 + \Delta X. On va voir comment le faire avec du code en C dans la partie suivante.

Enfin, une solution et du code

Voici le code auquel je vais faire référence dans cette section.

Pour rappel, on veut faire converger cette EDO raide :

X˙(t)=ddt(x(t)y(t))=(x(t)ky(t)) \dot X(t) = \frac{d}{dt} \begin{pmatrix} x(t) \\ y(t) \end{pmatrix} = \begin{pmatrix} -x(t) \\ -ky(t) \end{pmatrix}

Et nous savons que Xf(X(t))\frac{\partial}{\partial X}f(X(t)) est la matrice jacobienne :

Xf(X(t))=[100k] \frac{\partial}{\partial X}f(X(t)) = \begin{bmatrix} -1 & 0 \\ 0 & -k \end{bmatrix}

Revenons à l’équation ΔX=(1hIf(X0))1f(X0)\Delta X = (\frac{1}{h}I - f'(X_0))^{-1} f(X_0). On calcule ΔX\Delta X comme suit :

ΔX=(1hIf(X0))1f(X0)=(1hI[100k])1(x0ky0)=[1+hh001+khh]1(x0ky0)=[h1+h00h1+kh](x0ky0)=(h1+hx0h1+khky0)\Delta X = (\frac{1}{h}I - f'(X_0))^{-1} f(X_0) \\[0.5em] = (\frac{1}{h}I - \begin{bmatrix} -1 & 0 \\ 0 & -k \end{bmatrix} )^{-1} \begin{pmatrix} -x_0 \\ -ky_0 \end{pmatrix} \\[0.5em] = \begin{bmatrix} \frac{1+h}{h} & 0 \\ 0 & \frac{1+kh}{h} \end{bmatrix} ^{-1} \begin{pmatrix} -x_0 \\ -ky_0 \end{pmatrix} \\[0.5em] = \begin{bmatrix} \frac{h}{1+h} & 0 \\ 0 & \frac{h}{1+kh} \end{bmatrix} \begin{pmatrix} -x_0 \\ -ky_0 \end{pmatrix} \\[0.5em] = -\begin{pmatrix} \frac{h}{1+h}x_0 \\[0.5em] \frac{h}{1+kh}ky_0 \end{pmatrix} \\

Ce qui est intéressant, c’est qu’on peut faire un pas avec n’importe quelle amplitude ! Si l’on calcule la limite de ΔX\Delta X lorsque h s’approche d’infini, on verrait que :

limxΔX=limx(h1+hx0h1+khky0)=(x01kky0)=(x0y0)\lim_{x \to \infty} \Delta X = \lim_{x \to \infty} -\begin{pmatrix} \frac{h}{1+h}x_0 \\[0.5em] \frac{h}{1+kh}ky_0 \end{pmatrix} = -\begin{pmatrix} x_0 \\[0.5em] \frac{1}{k}ky_0 \end{pmatrix} \\[0.5em] = -\begin{pmatrix} x_0 \\[0.5em] y_0 \end{pmatrix} \\[0.5em]

Donc Xnew=X0+(X0)=(00)X*{new} = X_0 + -(X_0) = \begin{pmatrix} 0 \\ 0 \end{pmatrix} lorsque _h* s’approche de l’infini !

Maintenant, nous pouvons utiliser le programme que j’ai écrit pour voir cet exemple. Après avoir navigué jusqu’au dossier où vous avez téléchargé le code, exécute la commande suivante :

make ./out 0.2 1000.0 100.0 100.0

h=0.2, k=1000.0, x0=100.0 et y0=100.0. Vous devriez voir deux fichiers implicit.txt et explicit.txt qui viennent s’ajouter au dossier. Dans implicit.txt, on voit que y se converge vers 0 !

x0y0100.000000100.00000083.3333280.49750569.4444430.00247557.8703690.00001248.2253070.00000040.1877560.00000033.4897960.00000027.9081630.00000023.2568020.00000019.3806690.000000\begin{array}{cc} x_0 & y_0 \\ \hline \\ 100.000000 & 100.000000 \\ 83.333328 & 0.497505 \\ 69.444443 & 0.002475 \\ 57.870369 & 0.000012 \\ 48.225307 & 0.000000 \\ 40.187756 & 0.000000 \\ 33.489796 & 0.000000 \\ 27.908163 & 0.000000 \\ 23.256802 & 0.000000 \\ 19.380669 & 0.000000 \\ \end {array}

Mais dans explicit.txt, c’est une histoire complètement différente :

x0y0100.000000100.00000080.00000019900.00000064.0000003960100.00000051.200001788059904.00000040.959999156823928832.00000032.76799831207964278784.00000026.2143976210385271062528.00000020.9715181235866737660919808.00000016.777214245937476671354437632.00000013.42177148941558402957300465664.000000\begin{array}{cc} x_0 & y_0 \\ \hline \\ 100.000000 & 100.000000 \\ 80.000000 & -19900.000000 \\ 64.000000 & 3960100.000000 \\ 51.200001 & -788059904.000000 \\ 40.959999 & 156823928832.000000 \\ 32.767998 & -31207964278784.000000 \\ 26.214397 & 6210385271062528.000000 \\ 20.971518 & -1235866737660919808.000000 \\ 16.777214 & 245937476671354437632.000000 \\ 13.421771 & -48941558402957300465664.000000 \\ \end {array}

La suite

On verra comment résoudre des équations différentielles raides du second ordre ! À la prochaine !

Des ressources (en français et anglais)


Comments for Des méthodes numériques (Euler implicite) - Partie 3



Written by Carmen Cincotti, computer graphics enthusiast, language learner, and improv actor currently living in San Francisco, CA.  Follow @CarmenCincotti

Contribute

Interested in contributing to Carmen's Graphics Blog? Click here for details!