Considérons une méthode numérique à \(q=p+1\) étapes (=pas) linéaire. Elle s’écrit sous la forme générale \(
u_{n+1}
=
\sum_{j=0}^p a_ju_{n-j}
+
h\sum_{j=0}^p b_j\varphi(t_{n-j},u_{n-j})
+
hb_{-1}\varphi(t_{n+1},u_{n+1}),
\qquad
n=p,p+1,\dots,N-1
\) où les \(\{a_k\}\) et \(\{b_k\}\) sont des coefficients donnés et \(p\ge0\) un entier.
En notant \(\varphi_{n-j}\stackrel{\text{déf}}{=}\varphi(t_{n-j},u_{n-j})\) et en écrivant explicitement les séries, on a \(
u_{n+1}
=
a_0u_{n}+a_1u_{n-1}+\cdots+a_pu_{n-p}
+
h b_0\varphi_{n}+h b_1\varphi_{n-1}+\cdots+h b_{p}\varphi_{n-p}
+
hb_{-1}\varphi_{n+1}.
\)
Pour \(i=0,1,\dots\) introduisons la quantité \(
\xi(i) = \sum_{j=0}^p (-j)^{i}a_j+i\sum_{j=-1}^p (-j)^{i-1}b_j,
\) ayant posé \((-j)^0=1\) même pour \(j=0\).
La méthode est consistante ssi \(\xi(0)=\xi(1)=1\), autrement dit ssi \(
\begin{cases}
\displaystyle\sum_{j=0}^p a_j=1,
\\
\displaystyle-\sum_{j=0}^p ja_j+\sum_{j=-1}^p b_j=1
\end{cases}
\)
La méthode est zéro-stable ssi \(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
r_j\text{ a multiplicité}>1\quad\implies \quad |r_j|<1,
\end{cases}
\) où \(\varrho\) est le premier polynôme caractéristique défini par \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}.
\)
Consistance + zéro-stabilité = convergence
Une méthode convergente est d’ordre\(\omega\) ssi \(\xi(0)=\xi(1)=\dots=\xi(\omega)=1\), autrement dit ssi elle est consistante et, de plus, \(
\sum_{j=0}^p (-j)^{i}a_j+i\sum_{j=-1}^p (-j)^{i-1}b_j=1 \quad i=2,\dots,\omega.
\) Première barrière de Dahlquist : l’ordre \(\omega\) d’une méthode multipas à \(q\) étapes convergente satisfait les inégalités suivantes:
si \(b_{-1}=0\) (la méthode est explicite) alors \(\omega\le q\)
si \(b_{-1}\neq0\) (la méthode est implicite) on doit considérér deux cas
si \(q\) est impair alors \(\omega\le q+1\)
si \(q\) est pair alors \(\omega\le q+2\)
Soit \(\beta>0\) un nombre réel positif et considérons le problème de Cauchy \(\begin{cases}
y'(t)=-\beta y(t), &\text{pour }t>0,\\
y(0)=1
\end{cases}\) Sa solution est \(y(t)=e^{-\beta t}\xrightarrow[t\to+\infty]{}0.\) Si, sous d’éventuelles conditions sur \(h\), on a \(|u_n|\xrightarrow[n\to+\infty]{}0\) alors on dit que le schéma est A-stable.
Code
from sympy import symbols, Symbol, latex, factor, solvefrom IPython.display import display, Math, Markdown, Latexdef xi(i, q):# Définition des symboles aa = symbols(f'a_0:{</span>q<span class="sc">}') bb = symbols(f'b_0:{</span>q<span class="sc">}') bm1 = Symbol('b_{-1}') p =len(aa) sa =sum((-j)**i * aa[j] for j inrange(p)) sb = bm1 +sum((-j)**(i-1) * bb[j] for j inrange(1, p))# ??? si j=0 et i=0, il calcule (-j)**i =1 et on a bien a_0 dans la somme# mais si j=0 et i=1 il ne calcule pas b_0 et il faut l'ajouter à la mainif i ==1: sb += bb[0]return (sa).factor() + (i * sb).factor()# Paramètresp =1# j = 0...p # coeffs du schemaq = p +1omega = q +2if q%2==0else q +1# i = 0, ..., omegadisplay(Markdown(f"Pour une méthode à q={</span>p <span class="op">+</span> <span class="dv">1</span><span class="sc">} pas, on affiche $\\xi(i)$ pour i = 0, ..., {</span>omega<span class="sc">}"))for i inrange(omega +1): display(Markdown(f"$\\xi({</span>i<span class="sc">}) = {</span>latex(xi(i, q))<span class="sc">}$"))# systeme = [xi(i, q) for i in range(omega + 2)]# solve(systeme)
Pour une méthode à q=2 pas, on affiche \(\xi(i)\) pour i = 0, …, 4
1.1 👣 Exercice : consistance d’un schéma à deux pas explicite
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). La méthode multipas suivante est-elle consistante? \(
u_{n+1}=u_{n-1}+ \dfrac{h}{4}(3\varphi_{n}-\varphi_{n-1})
\)
1.1.1 Correction
C’est une méthode à q=2 pas explicite :
\(p=1\)
\(b_{-1}=0\)
\(a_0=0\) et \(a_1=1\)
\(b_0=\frac{3}{4}\) et \(b_1=-\frac{1}{4}\)
La méthode n’est pas consistante car \(
\begin{cases}
\displaystyle\sum_{j=0}^p a_j=1,
\\
\displaystyle-\sum_{j=0}^p ja_j+\sum_{j=-1}^p b_j=-1+\frac{3}{4}-\frac{1}{4}\neq1
\end{cases}
\)
Voyons sur un exemple ce qui se passe lorsqu’on utilise un schéma non consistant. On compare la solution exacte et la solution approchée du problème de Cauchy \(y'(t)=2(y(t)-\cos(t))-\sin(t)\), \(y(0)=1\) sur l’intervalle \([0,2\pi]\) dont la solution exacte est \(y(t) = cos(t)\). Comme visible sur la figure suivante, la solution numérique ne correspond pas à la solution exacte et on peut vérifier qu’un comportement similaire se produit également si on raffine la discrétisation. Il s’agit d’une situation typique de manque de consistance : l’application d’une méthode non consistante produit l’allure d’une autre fonction plutôt que celle reproduisant la solution exacte.
1.2 👣 Exercice : convergence d’un schéma à 2 pas implicite
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). La méthode multipas suivante est-elle convergente? \(
u_{n+1}=-4u_{n}+5u_{n-1}+ h(4\varphi_{n+1}+2\varphi_{n})
\)
1.2.1 Correction
C’est une méthode à 2 pas implicite :
\(p=1\)
\(b_{-1}=4\)
\(a_0=-4\) et \(a_1=5\)
\(b_0=2\) et \(b_1=0\)
La méthode est consistante car \(
\begin{cases}
\displaystyle \xi(0)=\sum_{j=0}^p a_j=-4+5=1,
\\
\displaystyle \xi(1)=-\sum_{j=0}^p ja_j+\sum_{j=-1}^p b_j=-\big(0\times a_0+1\times a_1\big)+\big(b_{-1}+b_0+b_1\big)=-5+4+2+0=1.
\end{cases}
\)
Le premier polynôme caractéristique est \(
\begin{aligned}
\varrho(r) &=r^{p+1}-\sum_{j=0}^p a_jr^{n-j}=r^2-\big(a_0 r^1+a_1r^0\big)
\\
&=r^2-(-4r+5)=r^2+4r-5=(r-1)(r+5)
\end{aligned}
\) dont les racines sont \(r_0=1\) et \(r_1=-5\). La méthode n’est pas zéro-stable car \(|r_1|>1\), donc la méthode ne converge pas.
Voyons sur un exemple ce qui se passe lorsqu’on utilise un schéma consistant mais non zéro-stable. On compare la solution exacte et la solution approchée du problème de Cauchy \(y'(t)=2(y(t)-\cos(t))-\sin(t)\), \(y(0)=1\) sur l’intervalle \([0,2\pi]\) dont la solution exacte est \(y(t) = cos(t)\).
La cosistance est une propriété de précision locale, tandis que la zéro-stabilité et la convergence sont des propriétés de précision globale. La zéro-stabilité assure que la solution numérique ne diverge pas lorsque \(h\) tend vers \(0\).
1.3 👣 Exercice : convergence d’un schéma à 3 pas explicite
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). La méthode multipas suivante est-elle convergente? \(
u_{n+1}=-u_{n}+u_{n-1}+u_{n-2}+ 4h\varphi_{n}
\)
1.3.1 Correction
C’est une méthode à 3 pas explicite :
\(p=2\)
\(b_{-1}=0\)
\(a_0=-1\), \(a_1=1\) et \(a_2=1\)
\(b_0=4\), \(b_1=0\) et \(b_2=0\)
La méthode est consistante car \(
\begin{cases}
\displaystyle\sum_{j=0}^p a_j=-1+1+1=1,
\\
\displaystyle-\sum_{j=0}^p ja_j+\sum_{j=-1}^p b_j=-(0\times(-1)+1\times1+2\times1)+(0+4+0+0)=-3+4=1.
\end{cases}
\)
Le premier polynôme caractéristique est \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{n-j}=r^3-\big(-r^2+r+1\big)=r^3+r^2-r-1=(r-1)(r^2-1)=(r-1)^2(r+1)
\) dont les racines sont \(r_0=1\) de multiplicité \(2\) et \(r_1=-1\). La méthode n’est pas zéro-stable car \(\varrho'(r_0)\neq0\), donc la méthode ne converge pas.
Code
import sympy as symsym.var('r')rho = r**3+r**2-r-1sym.factor(rho)
dont les racines sont \(r_0=1\) et \(r_1=-1\). La méthode est zéro-stable car
\(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
\varrho'(r_j)\neq0 \text{ si } |r_j|=1,
\end{cases}
\)
1.5 👣 Exercice : convergence d’un schéma à 2 pas implicite
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). Soit la méthode multipas \(
u_{n+1}=(1-\gamma)u_{n}+\gamma u_{n-1}+ \frac{h}{4}((\gamma+3)\varphi_{n+1}+(3\gamma+1)\varphi_{n-1}).
\)
Pour quelles valeurs de \(\gamma\) est-elle consistante?
Pour quelles valeurs de \(\gamma\) est-elle zéro-stable?
Pour quelles valeurs de \(\gamma\) est-elle convergente?
Pour quelles valeurs de \(\gamma\) est-elle convergente d’ordre \(2\)? et d’ordre \(3\)?
Pour \(\gamma=\frac{1}{2}\) vérifier empiriquement la convergence sur le problème de Cauchy \(
\begin{cases}
y'(t) = -4y(t)+t^2, &\forall t \in I=[0,1],\\
y(0) = 1
\end{cases}
\)
1.5.1 Correction
C’est une méthode à 2 pas implicite :
\(p=1\)
\(b_{-1}=\frac{\gamma+3}{4}\)
\(a_0=1-\gamma\) et \(a_1=\gamma\)
\(b_0=0\) et \(b_1=\frac{3\gamma+1}{4}\)
Consistance La méthode est consistante pour tout \(\gamma\) car \(
\begin{cases}
\displaystyle\sum_{j=0}^p a_j=1-\gamma+\gamma=1 \text{ pour tout }\gamma,
\\
\displaystyle-\sum_{j=0}^p ja_j+\sum_{j=-1}^p b_j=-\big(0\times(1-\gamma)+1\times \gamma\big)+\big(\frac{\gamma+3}{4}+0+\frac{3\gamma+1}{4}\big)=1 \text{ pour tout }\gamma
\end{cases}
\)
Zéro-stabilité Le premier polynôme caractéristique est \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}=r^2-(1-\gamma)r-\gamma=(r-1)(r+\gamma)
\) dont les racines sont \(r_0=1\) et \(r_1=-\gamma\). La méthode est zéro-stable ssi \(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
\varrho'(r_j)\neq0 \text{ si } |r_j|=1,
\end{cases}
\)
donc ssi \(-1\le -\gamma\le1\) et \(-\gamma\neq1\), i.e. ssi \(-1< \gamma\le 1\).
Convergence La méthode est convergente ssi elle est consistante et zéro-stable donc ssi \(-1< \gamma\le 1\).
Ordre de convergence La méthode est d’ordre au moins 2 pour tout \(\gamma\) car \(
\sum_{j=0}^p (-j)^{2}a_j+2\sum_{j=-1}^p (-j)^{1}b_j
{}=
\big(0^2a_0+1^2a_1\big)-2\big(-1b_{-1}+0b_0+1b_1\big)
{}=
\gamma-2\big(-\frac{\gamma+3}{4}+\frac{3\gamma+1}{4}\big)
{}=1
\)
Pour que la méthode soit d’ordre 3 il faut que \(
1
{}=
\sum_{j=0}^p (-j)^{3}a_j+3\sum_{j=-1}^p (-j)^{2}b_j
{}=
{}-\big(0^3a_0+1^3a_1\big)+3\big((-1)^2b_{-1}+0^2b_0+1^2b_1\big)
{}=
{}-\gamma+3\big(\frac{\gamma+3}{4}+\frac{3\gamma+1}{4}\big)
{}=
2\gamma+3
\)
donc ssi \(\gamma=-1\). Cependant, cette valeur n’appartient pas au domaine de zéro-stabilité.
On conclut que la méthode est convergente d’ordre \(2\) pour \(-1< \gamma\le 1\) et non convergente sinon.
Vérification empirique On définit la solution exacte (calculée en utilisant le module sympy) pour estimer les erreurs, puis on définit le schéma et enfin on calcule les erreurs pour différentes valeurs de \(h\).
import matplotlib.pyplot as pltplt.rcParams.update({<span class="st">'font.size'</span>: <span class="dv">16</span>})H = []err_mp = []N =10gamma =1/2for k inrange(7): N +=20 tt = np.linspace(t0, tfinal, N +1) h = tt[1] - tt[0] yy = sol_exacte(tt) uu_mp = multipas(phi, tt, yy, gamma) H.append(h) err_mp.append( np.linalg.norm(uu_mp-yy, np.inf) )plt.figure(figsize=(8,5))plt.plot(np.log(H), np.log(err_mp), 'r-o')plt.xlabel('$\ln(h)$')plt.ylabel('$\ln(e)$')plt.title(f'Ordre de convergence = pente de la droite = {</span>(np.polyfit(np.log(H),np.log(err_mp), <span class="dv">1</span>)[<span class="dv">0</span>])<span class="sc">}')plt.grid(True)
1.6 👣 Exercice : convergence d’un schéma à 2 pas explicite
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). Soit la méthode multipas \(
u_{n+1}=
\left(\frac{1}{3}\gamma^2+\frac{1}{2}\gamma\right)u_{n}+
\left(\frac{2}{3}\gamma^2+\frac{1}{2}\gamma-1\right)u_{n-1}+
h\left[\left(-\frac{1}{6}\gamma^2-\frac{1}{4}\gamma+2\right)\varphi_{n}+
\left(-\frac{1}{6}\gamma^2-\frac{1}{4}\gamma\right)\varphi_{n-1}\right].
\) 1. Pour quelles valeurs de \(\gamma\) est-elle consistant e? 1. Est-elle convergente pour ces valeurs? 1. Quel ordre de convergente a-t-elle? 1. Pour les valeurs de \(\gamma\) qui donnent la convergence, vérifier empiriquement l’ordre de convergence sur le problème de Cauchy \(
\begin{cases}
y'(t) = -10\big(y(t)-1\big)^2, &\forall t \in I=[0,1],\\
y(0) = 2.
\end{cases}
\)
1.6.1 Correction
C’est une méthode à \(q=2\) pas explicite :
\(p=1\)
\(b_{-1}=0\)
\(a_0=\frac{1}{3}\gamma^2+\frac{1}{2}\gamma\) et \(a_1=\frac{2}{3}\gamma^2+\frac{1}{2}\gamma-1\)
\(b_0=-\frac{1}{6}\gamma^2-\frac{1}{4}\gamma+2\) et \(b_1=-\frac{1}{6}\gamma^2-\frac{1}{4}\gamma\)
Consistance
La méthode est consistante ssi \(
\begin{cases}
\displaystyle\sum_{j=0}^p a_j=\gamma^2+\gamma-1=1,
\\
\displaystyle-\sum_{j=0}^p ja_j+\sum_{j=-1}^p b_j=-\big(0a_0+1a_1\big)+\big(b_{-1}+b_0+b_1\big)=\gamma^2+\gamma-1=1
\end{cases}
\) donc ssi \(\gamma=-2\) ou \(\gamma=1\).
Zéro-stabilité
Le premier polynôme caractéristique est \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}=r^2-a_0r-a_1=
\begin{cases}
r^2-\frac{1}{3}r-\frac{2}{3}&\text{si }\gamma=-2,
\\
r^2-\frac{5}{6}r-\frac{1}{6}&\text{si }\gamma=1,
\end{cases}
\)
dont les racines sont \(
\begin{cases}
r_0=1,\ r_1=-\frac{2}{3}&\text{si }\gamma=-2,
\\
r_0=1,\ r_1=-\frac{1}{6}&\text{si }\gamma=1,
\end{cases}
\) La méthode est zéro-stable ssi \(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
\varrho'(r_j)\neq0 \text{ si } |r_j|=1,
\end{cases}
\)
Cette condition est vérifiée pour les deux cas.
Convergence
La méthode est convergente ssi elle est consistante et zéro-stable donc ssi \(\gamma=-2\) ou \(\gamma=1\).
Ordre
La méthode est d’ordre au moins 2 pour les deux choix de \(\gamma\) car \(
\sum_{j=0}^p (-j)^{2}a_j+2\sum_{j=-1}^p (-j)^{1}b_j
{}=
\begin{cases}
\frac{2}{3}+2\frac{1}{6}=1&\text{si }\gamma=-2,
\\
\frac{1}{6}+2\frac{5}{12}=1&\text{si }\gamma=1,
\end{cases}
\)
La méthode n’est pas d’ordre 3 pour aucun des deux choix de \(\gamma\) car \(
\sum_{j=0}^p (-j)^{3}a_j+3\sum_{j=-1}^p (-j)^{2}b_j
{}=
\begin{cases}
{}-\frac{2}{3}+3\frac{-1}{6}\neq1&\text{si }\gamma=-2,
\\
{}-\frac{1}{6}+3\frac{-5}{12}\neq1&\text{si }\gamma=1,
\end{cases}
\)
Solution exacte
On définit la solution exacte (calculée en utilisant le module sympy) pour estimer les erreurs:
Code
%reset -f%matplotlib inlineimport numpy as npimport matplotlib.pyplot as pltplt.rcParams.update({<span class="st">'font.size'</span>: <span class="dv">16</span>})from scipy.optimize import fsolveimport sympy as symsym.init_printing()from IPython.display import display, Math
1.7 👣 Exercice : convergence d’un schéma à 2 pas explicite
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). Soit la méthode multipas \(
u_{n+1}
=\left(\gamma^2-\frac{9}{2}\gamma+\frac{11}{2}\right)u_{n}
+\left(\gamma^2-\frac{7}{2}\gamma+\frac{3}{2}\right)u_{n-1}
+h\left(\frac{\gamma}{2}(\gamma-2)\varphi_{n}
+\frac{\gamma}{2}\left(\gamma-\frac{10}{3}\right)\varphi_{n-1}\right).
\)
Pour quelles valeurs de \(\gamma\) est-elle consistante?
Est-elle convergente pour ces valeurs?
Quel ordre de convergente a-t-elle?
Pour les valeurs de \(\gamma\) qui donnent la convergence, vérifier empiriquement l’ordre de convergence sur le problème de Cauchy \(
\begin{cases}
y'(t) = y(t)(1-y(t)), &\forall t \in I=[0,1],\\
y(0) = 2.
\end{cases}
\)
1.7.1 Correction
C’est une méthode à \(q=2\) pas explicite :
\(p=1\)
\(b_{-1}=0\)
\(a_0=\gamma^2-\frac{9}{2}\gamma+\frac{11}{2}\) et \(a_1=\gamma^2-\frac{7}{2}\gamma+\frac{3}{2}\)
\(b_0=\frac{\gamma}{2}(\gamma-2)\) et \(b_1=\frac{\gamma}{2}\left(\gamma-\frac{10}{3}\right)\)
La méthode est consistante ssi \(\xi(0)=\xi(1)=1\): \(
\begin{cases}
\xi(0)=\displaystyle\sum_{j=0}^p a_j=2\gamma^2-8\gamma+7=1,
\\
\xi(1)=\displaystyle-\sum_{j=0}^p ja_j+\sum_{j=-1}^p b_j=-\big(0a_0+1a_1\big)+\big(b_{-1}+b_0+b_1\big)=\frac{5}{6}\gamma-\frac{19}{6}=1
\end{cases}
\) donc ssi \(\gamma=3\). Vérifions ces calculs ci-dessous:
Code
%reset -f%matplotlib inlineimport numpy as npimport matplotlib.pyplot as pltplt.rcParams.update({<span class="st">'font.size'</span>: <span class="dv">16</span>})from scipy.optimize import fsolveimport sympy as symsym.init_printing()from IPython.display import display, Math
Le premier polynôme caractéristique est \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}=r^2-a_0r-a_1
\stackrel{\gamma=3}{=}
r^2-r
\) dont les racines sont \(
r_0=1,\ r_1=0
\) La méthode est zéro-stable ssi \(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
\text{multiplicité de $r_j$ supérieur à 1} \implies |r_j|<1,
\end{cases}
\) ce qui est bien vérifié.
La méthode est convergente ssi elle est consistante et zéro-stable donc ssi \(\gamma=3\).
La méthode est d’ordre au moins 2 car \(\xi(2)=1\): \(
\xi(2)=
\sum_{j=0}^p (-j)^{2}a_j+2\sum_{j=-1}^p (-j)^{1}b_j
{}=
\big(0^2a_0+1^2a_1\big)+2\big(-(-1)b_{-1}+0b_0+1b_1\big)
\stackrel{\gamma=3}{=}
1
\)
La méthode n’est pas d’ordre 3 car \(\xi(3)\neq1\): \(
\xi(3)=
\sum_{j=0}^p (-j)^{3}a_j+3\sum_{j=-1}^p (-j)^{2}b_j
{}=
{}-a_1+3\big(b_{-1}+b_1\big)
\stackrel{\gamma=3}{\neq}1
\)
On définit la solution exacte (calculée en utilisant le module sympy) pour estimer les erreurs:
1.8 Exercice : convergence d’un schéma predictor-corrector basé sur deux schémas 👣
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). Soit les méthodes multipas \( \begin{aligned}
u_{n+1}&=u_{n}+\frac{h}{12}\left(23\varphi_{n}-16\varphi_{n-1}+5\varphi_{n-2}\right)&\text{[P]}
\\
u_{n+1}&=u_{n}+\frac{h}{24}\left(9\varphi_{n+1}+19\varphi_{n}-5\varphi_{n-1}+\varphi_{n-2}\right)&\text{[C]}
\end{aligned}
\)
Étudier consistance, ordre et zéro-stabilité de la méthode P
Étudier consistance, ordre et zéro-stabilité de la méthode C
Soit la méthode PC suivante: \(
\begin{cases}
\tilde u=u_{n}+\frac{h}{12}\left(23\varphi_{n}-16\varphi_{n-1}+5\varphi_{n-2}\right)
\\
u_{n+1}=u_{n}+\frac{h}{24}\left(9\varphi(t_{n+1},\tilde u)+19\varphi_{n}-5\varphi_{n-1}+\varphi_{n-2}\right)
\end{cases}
\) Calculer empiriquement l’ordre de convergence de la méthode PC sur le problème de Cauchy \(
\begin{cases}
y'(t) = \frac{1}{1+t^2}-2y^2(t), &\forall t \in I=[0,1],\\
y(0) = 0,
\end{cases}
\) dont la solution exacte est \(y(t)=\frac{t}{1+t^2}\).
1.8.1 Correction schéma P
P est une méthode à \(q=3\) pas explicite : - \(p=2\) - \(b_{-1}=0\) - \(a_0=1\) et \(a_1=a_2=0\) - \(b_0=\frac{23}{12}\), \(b_1=\frac{-16}{12}\) et \(b_2=\frac{5}{12}\) - La méthode est consistante d’ordre \(\omega=3\) car \(
\begin{cases}
\displaystyle\sum_{j=0}^p a_j=1,
\\
\displaystyle\sum_{j=0}^p -ja_j+\sum_{j=-1}^p b_j=-a_1-2a_2+\big(b_{-1}+b_0+b_1+b_2\big)=1
\\
\displaystyle\sum_{j=0}^p (-j)^{2}a_j+2\sum_{j=-1}^p (-j)^{1}b_j=a_1+4a_2-2\big(-b_{-1}+b_1+2b_2\big)=1
\\
\displaystyle\sum_{j=0}^p (-j)^{3}a_j+3\sum_{j=-1}^p (-j)^{2}b_j=-a_1-8a_2+3\big(b_{-1}+b_1+4b_2\big)=1
\\
\displaystyle\sum_{j=0}^p (-j)^{4}a_j+4\sum_{j=-1}^p (-j)^{3}b_j=a_1+16a_2-4\big(-b_{-1}+b_1+8b_2\big)\neq1
\end{cases}
\) Vérifions ces calculs ci-dessous:
Le premier polynôme caractéristique est \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}=r^3-a_0r^2-a_1r-a_2
{}=
r^3-r^2=r^2(r-1)
\) dont les racines sont \(
r_0=1,\ r_1=r_2=0
\) La méthode est zéro-stable ssi \(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
\varrho'(r_j)\neq0 \text{ si } |r_j|=1,
\end{cases}
\) ce qui est bien vérifié.
La méthode est convergente car consistante et zéro-stable.
1.8.2 Correction schéma C
C est une méthode à \(q=3\) pas implicite :
\(p=2\)
\(b_{-1}=\frac{9}{24}\)
\(a_0=1\) et \(a_1=a_2=0\)
\(b_0=\frac{19}{24}\), \(b_1=\frac{-5}{24}\) et \(b_2=\frac{1}{24}\)
La méthode est consistante d’ordre \(\omega=4\) car \(
\begin{cases}
\displaystyle\sum_{j=0}^p a_j=1,
\\
\displaystyle\sum_{j=0}^p -ja_j+\sum_{j=-1}^p b_j=-a_1-2a_2+\big(b_{-1}+b_0+b_1+b_2\big)=1
\\
\displaystyle\sum_{j=0}^p (-j)^{2}a_j+2\sum_{j=-1}^p (-j)^{1}b_j=a_1+4a_2-2\big(-b_{-1}+b_1+2b_2\big)=1
\\
\displaystyle\sum_{j=0}^p (-j)^{3}a_j+3\sum_{j=-1}^p (-j)^{2}b_j=-a_1-8a_2+3\big(b_{-1}+b_1+4b_2\big)=1
\\
\displaystyle\sum_{j=0}^p (-j)^{4}a_j+4\sum_{j=-1}^p (-j)^{3}b_j=a_1+16a_2-4\big(-b_{-1}+b_1+8b_2\big)=1
\\
\displaystyle\sum_{j=0}^p (-j)^{5}a_j+5\sum_{j=-1}^p (-j)^{4}b_j=-a_1+32a_2+5\big(b_{-1}+b_1+16b_2\big)\neq1
\end{cases}
\) Vérifions ces calculs ci-dessous:
Le premier polynôme caractéristique est \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}=r^3-a_0r^2-a_1r-a_2
{}=
r^3-r^2=r^2(r-1)
\) dont les racines sont \(
r_0=1,\ r_1=r_2=0
\) La méthode est zéro-stable ssi \(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
\varrho'(r_j)\neq0 \text{ si } |r_j|=1,
\end{cases}
\) ce qui est bien vérifié.
La méthode est convergente car consistante et zéro-stable.
1.8.3 Correction schéma PC
Il est d’ordre \(4\) car le prédictor est d’ordre \(3\) et le corrector d’ordre \(4\).
On définit la solution exacte pour estimer les erreurs:
Multipas P ordre = 2.99
Multipas C ordre = 3.86
Multipas PC ordre = 4.00
1.9 Exercice : convergence d’un schéma predictor-corrector basé sur deux schémas 👣
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). Soit les méthodes multipas \( \begin{aligned}
u_{n+1}&=\frac{4}{3}u_{n}-\frac{1}{3}u_{n-1}+h\left(b_0\varphi_{n}+b_1\varphi_{n-1}\right)
&\text{[P]}
\\
u_{n+1}&=\frac{4}{3}u_{n}-\frac{1}{3}u_{n-1}+h\frac{2}{3}\varphi_{n+1}
&\text{[C]}
\end{aligned}
\)
Étudier consistance, ordre et zéro-stabilité des deux méthodes.
Écrire et étudier consistance, ordre et zéro-stabilité de la méthode prédictor-corrector associée.
Calculer empiriquement l’ordre de convergence des trois méthodes sur le problème de Cauchy \(
\begin{cases}
y'(t) = \frac{1}{1+t^2}-2y^2(t), &\forall t \in I=[0,1],\\
y(0) = 0,
\end{cases}
\) dont la solution exacte est \(y(t)=\frac{t}{1+t^2}\).
Les deux schémas multipas linéaires à \(q=2\) pas sont de la forme \(
u_{n+1} = a_0 u_n + a_1 u_{n-1} + h \left( b_0 \varphi_n + b_1 \varphi_{n-1} \right) + h b_{-1} \varphi_{n+1}
\) avec \(
\begin{array}{c|cccccc}
& a_0 & a_1 & b_0 & b_1 & b_{-1} \\
\hline
\text{[P]} & \frac{4}{3} & -\frac{1}{3} & b_0 & b_1 & 0 \\
\text{[C]} & \frac{4}{3} & -\frac{1}{3} & 0 & 0 & \frac{2}{3}
\end{array}
\)
Les deux schémas ont le même premier polynôme caractéristique : \(
\varrho(r)=r^2-a_0r-a_1=(r-1)\left(r-\frac{1}{3}\right).
\) Ses racines sont \(r_0=1\) et \(r_1=\frac{1}{3}\). Comme elles appartiennent au disque unité et sont simples, les deux méthodes sont zéro-stables.
D’après la première barrière de Dalquist, un schéma linéaire à \(q=2\) pas consistant et zéro-stable est au mieux
d’ordre \(\omega = q+2 = 4\) s’il est implicite,
d’ordre \(\omega = q = 2\) s’il est explicite.
Étudions l’ordre de convergence en calculant \(\xi(i)\) pour \(i=0,\dots,4\) (les deux méthodes ayant le même nombre de pas, on a la même expression pour \(\xi(i)\)) : \(
\begin{cases}
\xi(0) = a_{0} + a_{1} \\
\xi(1) = - a_{1} + b_{0} + b_{1} + b_{-1} \\
\xi(2) = a_{1} - 2 \left(b_{1} - b_{-1}\right) \\
\xi(3) = - a_{1} + 3 \left(b_{1} + b_{-1}\right) \\
\xi(4) = a_{1} - 4 \left(b_{1} - b_{-1}\right)
\end{cases}
\)
Pour le schéma [C], on a \(\xi(0)=\xi(1)=\xi(2)=1\) et \(\xi(3)\neq1\), donc la méthode est d’ordre 2 : \(
\begin{cases}
\xi(0) = a_{0} + a_{1} = \frac{4}{3} -\frac{1}{3}=1\\
\xi(1) = - a_{1} + b_{0} + b_{1} + b_{-1} = \frac{1}{3}+\frac{2}{3}=1\\
\xi(2) = a_{1} - 2 \left(b_{1} - b_{-1}\right) = -\frac{1}{3}+2\frac{2}{3}=1\\
\xi(3) = - a_{1} + 3 \left(b_{1} + b_{-1}\right) = \frac{1}{3}+3\frac{2}{3}=\frac{7}{3}\neq1
\end{cases}
\)
Pour le schéma [P], nous allons chercher \(b_0\) et \(b_1\) pour obtenir un schéma d’ordre 2. Pour cela on doit résoudre le système linéaire : \(
\begin{cases}
\xi(0) = a_{0} + a_{1} = \frac{4}{3} -\frac{1}{3} = 1 \\
\xi(1) = - a_{1} + b_{0} + b_{1} + b_{-1} = \frac{1}{3}+ b_{0} + b_{1}=1\\
\xi(2) = a_{1} - 2 \left(b_{1} - b_{-1}\right) = -\frac{1}{3}-2b_1=1
\end{cases}
\) On trouve \(b_0=\frac{4}{3}\) et \(b_1=-\frac{2}{3}\).
Le schéma predictor-corrector s’écrit \(
\begin{cases}
u_0 = y_0,\\
u_1 \approx y_1 ,\\
\tilde u = \frac{4}{3}u_{n}-\frac{1}{3}u_{n-1}+h\left(\frac{4}{3}\varphi_{n}-\frac{2}{3}\varphi_{n-1}\right)
&\text{[P]}
\\
u_{n+1}=\frac{4}{3}u_{n}-\frac{1}{3}u_{n-1}+h\frac{2}{3}\varphi(t_{n+1},\tilde u)
\end{cases}
\) Comme le prédictor est d’ordre 2 et le corrector d’ordre 2 aussi, le schéma prédictor-corrector est d’ordre 2 (car \(\min(\omega_{[C]},\omega_{[P]}+1)=2\)).
Une méthode de Runge-Kutta à \(s\ge1\) étages s’écrit : \(\begin{array}{c|c}
\mathbf{c} & \mathbb{A}\\
\hline
&\mathbf{b}^T
\end{array}
\quad\implies\quad
\begin{cases}
u_0=y(t_0)=y_0,\\
u_{n+1}=u_{n}+h \displaystyle\sum_{i=1}^sb_iK_i& n=0,1,\dots N-1\\
K_i=\displaystyle\varphi\left( t_n+hc_i,u_n+h\sum_{j=1}^{s}a_{ij}K_j \right) & i=1,\dots s.
\end{cases}\)
Soit \(\omega\) l’ordre de la méthode.
Barrières de Butcher Soit une méthode RK à \(s\) étapes d’ordre \(\omega\).
Si la méthode est implicite alors \(\color{red}\omega\le 2s\).
Si la méthode est explicite et \(s<5\) alors \(\color{red}\omega\le s\).
Si la méthode est explicite et \(s\ge5\) alors \(\color{red}\omega<s\).
Critères
Si \(\begin{cases}
\displaystyle\sum_{j=1}^s b_{i}=1&
\\
\displaystyle c_i=\sum_{j=1}^s a_{ij}&i=1,\dots,s
\end{cases}\) alors la méthode est consistante (i.e. \(\omega\ge1\))
Si, de plus, \(\displaystyle\sum_{j=1}^s b_j c_j=\frac{1}{2}\) alors \(\omega\ge2\)
Si, de plus, \(\begin{cases}\displaystyle\sum_{j=1}^s b_j c_j^2=\frac{1}{3}\\\displaystyle\sum_{i=1}^s\sum_{j=1}^s b_i a_{ij} c_j=\frac{1}{6}\end{cases}\) alors \(\omega\ge3\)
Si, de plus, \(\begin{cases}\displaystyle\sum_{j=1}^s b_j c_j^3=\frac{1}{4}&\\\displaystyle\sum_{i=1}^s\sum_{j=1}^s b_i c_i a_{ij} c_j=\frac{1}{8}\\\displaystyle\sum_{i=1}^s\sum_{j=1}^s b_i a_{ij} c_j^2=\frac{1}{12}\\\displaystyle\sum_{i=1}^s\sum_{j=1}^s\sum_{k=1}^s b_i a_{ij}a_{jk} c_k=\frac{1}{24}\end{cases}\) alors \(\omega\ge4\)
La méthode est zéro-stable
Consistance + zéro-stabilité = convergence
Soit \(\beta>0\) un nombre réel positif et considérons le problème de Cauchy \( \begin{cases} y'(t)=-\beta y(t), &\text{pour }t>0, \\ y(0)=1 \end{cases} \) Sa solution est \(y(t)=e^{-\beta t}\xrightarrow[t\to+\infty]{}0.\) Si, sous d’éventuelles conditions sur \(h\), on a \(|u_n|\xrightarrow[n\to+\infty]{}0\) alors on dit que le schéma est A-stable. Une méthode de Runge-Kutta à \(s\ge1\) étages pour \(y'(t)=-\beta y(t)\) s’écrit: \( \begin{cases} u_0=y_0, \\ u_{n+1}=u_{n}+h \displaystyle\sum_{i=1}^sb_iK_i& n=0,1,\dots N-1\\ K_i=\displaystyle -\beta \left( u_n+h\sum_{j=1}^{s}a_{ij}K_j \right) & i=1,\dots s. \end{cases} \)
Code
import sympy sympy.init_printing()from IPython.display import display, Math, Markdownprlat =lambda*args : display(Math(''.join( sympy.latex(arg) for arg in args )))def ordre_RK(s, type="implicite", A=None, b=None, c=None): j = sympy.symbols('j')if A isNone:iftype=="implicite": A = sympy.MatrixSymbol('a', s, s)eliftype=="semi-implicite": A = sympy.Matrix(s, s, lambda i,j: sympy.Symbol('a{}{}'.format(i, j)) if i >= j else0)eliftype=="explicite": A = sympy.Matrix(s, s, lambda i,j: sympy.Symbol('a{}{}'.format(i, j)) if i > j else0)else: A = sympy.Matrix(A)if c isNone: c = sympy.symbols(f'c_0:{</span>s<span class="sc">}') if b isNone: b = sympy.symbols(f'b_0:{</span>s<span class="sc">}') display(Markdown("**Matrice de Butcher**")) But = matrice_Butcher(s, A, b, c) Eqs = [] display(Markdown(f"**On a {</span>s<span class="op">+</span><span class="dv">1</span><span class="sc">} conditions pour avoir consistance (= pour être d'ordre 1)**")) Eq_1 = ordre_1(s, A, b, c, j) Eqs.append(Eq_1) display(*Eq_1) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) Eq_2 = ordre_2(s, A, b, c, j) Eqs.append([Eq_2]) display(Eq_2) display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**")) Eq_3 = ordre_3(s, A, b, c, j) Eqs.append(Eq_3) display(*Eq_3) display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**")) Eq_4 = ordre_4(s, A, b, c, j) Eqs.append(Eq_4) display(*Eq_4)return Eqsdef matrice_Butcher(s, A, b, c): But = sympy.Matrix(A) But = But.col_insert(0, sympy.Matrix(c)) last = [sympy.Symbol(" ")] last.extend(b) But = But.row_insert(s,sympy.Matrix(last).T) display(Math(sympy.latex(sympy.Matrix(But))))return Butdef ordre_1(s, A, b, c, j): texte ="\sum_{j=1}^s b_j ="+f"{</span><span class="bu">sum</span>(b)<span class="sc">.</span>simplify()<span class="sc">}" texte +=r"\text{ doit être égale à }1"# display(Math(texte)) Eq_1 = [sympy.Eq( sum(b).simplify(), 1 )]for i inrange(s): somma = sympy.summation(A[i,j],(j,0,s-1)).simplify() texte =r'\sum_{j=1}^s a_{'</span><span class="op">+</span><span class="bu">str</span>(i)<span class="op">+</span><span class="vs">r'j}='+ sympy.latex( somma ) texte +=r"\text{ doit être égale à }"+sympy.latex(c[i])# display(Math( texte )) Eq_1.append(sympy.Eq( somma, c[i] ))return Eq_1 def ordre_2(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j='+sympy.latex(sum([b[i]*c[i] for i inrange(s)]).simplify()) texte +=r"\text{ doit être égale à }\frac{1}{2}"# display(Math(texte)) Eq_2 = sympy.Eq( sum([b[i]*c[i] for i inrange(s)]).simplify(), sympy.Rational(1,2) )return Eq_2def ordre_3(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^2=' texte += sympy.latex( sum([b[i]*c[i]**2for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{3}"# display(Math(texte)) Eq_3_1 = sympy.Eq( sum([b[i]*c[i]**2for i inrange(s)]).simplify(), sympy.Rational(1,3) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j=' somma =sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{6}"# display(Math(texte)) Eq_3_2 = sympy.Eq( sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,6) )return [Eq_3_1, Eq_3_2]def ordre_4(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^3=' texte += sympy.latex( sum([b[i]*c[i]**3for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{4}"# display(Math(texte)) Eq_4_1 = sympy.Eq( sum([b[i]*c[i]**3for i inrange(s)]).simplify(), sympy.Rational(1,4) ) texte =r'\sum_{i,j=1}^s b_i c_i a_{ij} c_j=' somma =sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{8}"# display(Math(texte)) Eq_4_2 = sympy.Eq( sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,8) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j^2=' somma =sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{12}"# display(Math(texte)) Eq_4_3 = sympy.Eq( sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,12) ) texte =r'\sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=' somma =sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{24}"# display(Math(texte)) Eq_4_4 = sympy.Eq( sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,24) )return [Eq_4_1, Eq_4_2, Eq_4_3, Eq_4_4]# Exemple de conditions avec s=2 étagess =2type="semi-implicite"display(Markdown(f"### Conditions pour un schéma {</span><span class="bu">type</span><span class="sc">} avec s = {</span>s<span class="sc">} étages "))Eqs = ordre_RK(s, type)
2.1 Conditions pour un schéma semi-implicite avec s = 2 étages
D’après la barrière de Butcher, un schéma RK à \(s=2\) étages explicite ne peut pas être d’ordre supérieur à \(s=2\).
On peut bien-sûr écrire les formules à la main, mais on peut aussi utiliser sympy comme suit :
Code
def ordre_RK(s, A=None, b=None, c=None): j = sympy.symbols('j')if A isNone: A = sympy.MatrixSymbol('a', s, s)else: A = sympy.Matrix(A)if c isNone: c = sympy.symbols(f'c_0:{</span>s<span class="sc">}') if b isNone: b = sympy.symbols(f'b_0:{</span>s<span class="sc">}') display(Markdown("**Matrice de Butcher**")) But = matrice_Butcher(s, A, b, c) Eqs = [] display(Markdown(f"**On a {</span>s<span class="op">+</span><span class="dv">1</span><span class="sc">} conditions pour avoir consistance = pour être d'ordre 1**")) Eq_1 = ordre_1(s, A, b, c, j) Eqs.append(Eq_1) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) Eq_2 = ordre_2(s, A, b, c, j) Eqs.append([Eq_2])# display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**"))# Eq_3 = ordre_3(s, A, b, c, j) # Eqs.append(Eq_3) # display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**"))# Eq_4 = ordre_4(s, A, b, c, j)# Eqs.append(Eq_4)return Eqsdef matrice_Butcher(s, A, b, c): But = sympy.Matrix(A) But = But.col_insert(0, sympy.Matrix(c)) last = [sympy.Symbol(" ")] last.extend(b) But = But.row_insert(s,sympy.Matrix(last).T) display(Math(sympy.latex(sympy.Matrix(But))))return Butdef ordre_1(s, A, b, c, j): texte ="\sum_{j=1}^s b_j ="+f"{</span><span class="bu">sum</span>(b)<span class="sc">.</span>simplify()<span class="sc">}" texte +=r"\text{ doit être égale à }1" display(Math(texte)) Eq_1 = [sympy.Eq( sum(b).simplify(), 1 )]for i inrange(s): somma = sympy.summation(A[i,j],(j,0,s-1)).simplify() texte =r'\sum_{j=1}^s a_{'</span><span class="op">+</span><span class="bu">str</span>(i)<span class="op">+</span><span class="vs">r'j}='+ sympy.latex( somma ) texte +=r"\text{ doit être égale à }"+sympy.latex(c[i]) display(Math( texte )) Eq_1.append(sympy.Eq( somma, c[i] ))return Eq_1 def ordre_2(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j='+sympy.latex(sum([b[i]*c[i] for i inrange(s)]).simplify()) texte +=r"\text{ doit être égale à }\frac{1}{2}" display(Math(texte)) Eq_2 = sympy.Eq( sum([b[i]*c[i] for i inrange(s)]).simplify(), sympy.Rational(1,2) )return Eq_2def ordre_3(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^2=' texte += sympy.latex( sum([b[i]*c[i]**2for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{3}" display(Math(texte)) Eq_3_1 = sympy.Eq( sum([b[i]*c[i]**2for i inrange(s)]).simplify(), sympy.Rational(1,3) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j=' somma =sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{6}" display(Math(texte)) Eq_3_2 = sympy.Eq( sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,6) )return [Eq_3_1, Eq_3_2]def ordre_4(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^3=' texte += sympy.latex( sum([b[i]*c[i]**3for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{4}" display(Math(texte)) Eq_4_1 = sympy.Eq( sum([b[i]*c[i]**3for i inrange(s)]).simplify(), sympy.Rational(1,4) ) texte =r'\sum_{i,j=1}^s b_i c_i a_{ij} c_j=' somma =sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{8}" display(Math(texte)) Eq_4_2 = sympy.Eq( sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,8) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j^2=' somma =sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{12}" display(Math(texte)) Eq_4_3 = sympy.Eq( sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,12) ) texte =r'\sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=' somma =sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{24}" display(Math(texte)) Eq_4_4 = sympy.Eq( sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,24) )return [Eq_4_1, Eq_4_2, Eq_4_3, Eq_4_4]################################################### Conditions avec s étages##################################################s =2# paramètres dans le cas générale# b_0, b_1 = sympy.symbols('b_0 b_1', real=True)# c_0, c_1 = sympy.symbols('c_0 c_1', real=True)# a_00, a_01, a_10, a_11 = sympy.symbols('a_00 a_01 a_10 a_11', real=True)# matrice dans le cas général# b = [b_0, b_1]# c = [c_0, c_1]# A = [[a_00, a_01], [a_10, a_11]]# matrice dans notre cas particulierb = [ sympy.Rational(1,4), sympy.Rational(3,4) ]c = [ 0, sympy.Rational(2,3) ]A = [ [ 0, 0] , [ sympy.Rational(2,3), 0] ]Eqs = ordre_RK(s, A, b, c)
La suite vérifie \(u_n \xrightarrow[n\to \infty]{} 0\) ssi \(\left|q(x)\right|<1\). En étudiant brièvement la fonction \(q(x)\), on trouve que \(q(x)<1\) ssi \(x<6\) donné ci-dessous:.
Code
sympy.plot(q, (x,0,2.5), ylim=(-1.5,1.5), ylabel='q(x)', xlabel='x', title='q(x) en fonction de x')sympy.solve(abs(q)<1)
\(\displaystyle x < 2\)
Correction point 4 : test de l’ordre
Code
################################################### EDO##################################################t0 =0tfinal =2y0 =1phi =lambda t,y: t*(1-t**2)-y################################################### solution exacte##################################################t = sympy.Symbol('t')y = sympy.Function('y')edo = sympy.Eq( (y(t)).diff() , phi(t,y(t)) )solpar = sympy.dsolve(edo , ics={y(t0):y0})display(solpar)sol_exacte = sympy.lambdify(t,solpar.rhs,'numpy')################################################### schéma ################################################### Paramètres du schéma recuperés depuis la matrice de Butcher obtenue précédemmentcc = np.array(c)bb = np.array(b)AA = np.array(A)s =len(cc)# Schéma de Runge-Kutta implicite à s étagesdef RK(phi, tt, y0): h = tt[1] - tt[0] uu = np.zeros_like(tt) uu[0] = y0 for n inrange(len(tt) -1): k_0 = phi(tt[n], uu[n]) k_1 = phi(tt[n]+cc[1]*h, uu[n]+h*AA[1,0]*k_0) KK = [k_0, k_1] uu[n+1] = uu[n] + h*sum([KK[j]*b[j] for j inrange(s)])return uu################################################### ordre##################################################H = []err = []plt.figure(figsize=(16,5))ax1 = plt.subplot(1,2,1)plt.xlabel('$t$')plt.ylabel('$y$')ax1.grid(True)N =10for k inrange(6): N +=10 tt = np.linspace(t0, tfinal, N +1) H.append( tt[1] - tt[0] ) yy = sol_exacte(tt) uu = RK(phi, tt, y0) err.append( np.linalg.norm(uu-yy,np.inf) ) ax1.plot(tt,uu,label=f'Approchée avec N={</span>N<span class="sc">}')ax1.plot(tt,yy,label='Exacte') # sur la grille la plus fineax1.legend()ax2 = plt.subplot(1,2,2)ax2.plot( np.log(H), np.log(err), 'r-o')plt.xlabel(r'$\ln(h)$')plt.ylabel(r'$\ln(e)$')plt.title(f'Le schéma a ordre {</span>np<span class="sc">.</span>polyfit(np.log(H),np.log(err),<span class="dv">1</span>)[<span class="dv">0</span>]<span class="sc">:1.2f}')ax2.grid(True)
D’après la barrière de Butcher, un schéma RK à \(s=2\) étages implicite ne peut pas être d’ordre supérieur à \(s=4\).
On peut bien-sûr écrire les formules à la main, mais on peut aussi utiliser sympy comme suit :
Code
def ordre_RK(s, A=None, b=None, c=None): j = sympy.symbols('j')if A isNone: A = sympy.MatrixSymbol('a', s, s)else: A = sympy.Matrix(A)if c isNone: c = sympy.symbols(f'c_0:{</span>s<span class="sc">}') if b isNone: b = sympy.symbols(f'b_0:{</span>s<span class="sc">}') display(Markdown("**Matrice de Butcher**")) But = matrice_Butcher(s, A, b, c) Eqs = [] display(Markdown(f"**On a {</span>s<span class="op">+</span><span class="dv">1</span><span class="sc">} conditions pour avoir consistance = pour être d'ordre 1**")) Eq_1 = ordre_1(s, A, b, c, j) Eqs.append(Eq_1) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) Eq_2 = ordre_2(s, A, b, c, j) Eqs.append([Eq_2]) display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**")) Eq_3 = ordre_3(s, A, b, c, j) Eqs.append(Eq_3) display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**")) Eq_4 = ordre_4(s, A, b, c, j) Eqs.append(Eq_4)return Eqsdef matrice_Butcher(s, A, b, c): But = sympy.Matrix(A) But = But.col_insert(0, sympy.Matrix(c)) last = [sympy.Symbol(" ")] last.extend(b) But = But.row_insert(s,sympy.Matrix(last).T) display(Math(sympy.latex(sympy.Matrix(But))))return Butdef ordre_1(s, A, b, c, j): texte ="\sum_{j=1}^s b_j ="+f"{</span><span class="bu">sum</span>(b)<span class="sc">.</span>simplify()<span class="sc">}" texte +=r"\text{ doit être égale à }1" display(Math(texte)) Eq_1 = [sympy.Eq( sum(b).simplify(), 1 )]for i inrange(s): somma = sympy.summation(A[i,j],(j,0,s-1)).simplify() texte =r'\sum_{j=1}^s a_{'</span><span class="op">+</span><span class="bu">str</span>(i)<span class="op">+</span><span class="vs">r'j}='+ sympy.latex( somma ) texte +=r"\text{ doit être égale à }"+sympy.latex(c[i]) display(Math( texte )) Eq_1.append(sympy.Eq( somma, c[i] ))return Eq_1 def ordre_2(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j='+sympy.latex(sum([b[i]*c[i] for i inrange(s)]).simplify()) texte +=r"\text{ doit être égale à }\frac{1}{2}" display(Math(texte)) Eq_2 = sympy.Eq( sum([b[i]*c[i] for i inrange(s)]).simplify(), sympy.Rational(1,2) )return Eq_2def ordre_3(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^2=' texte += sympy.latex( sum([b[i]*c[i]**2for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{3}" display(Math(texte)) Eq_3_1 = sympy.Eq( sum([b[i]*c[i]**2for i inrange(s)]).simplify(), sympy.Rational(1,3) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j=' somma =sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{6}" display(Math(texte)) Eq_3_2 = sympy.Eq( sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,6) )return [Eq_3_1, Eq_3_2]def ordre_4(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^3=' texte += sympy.latex( sum([b[i]*c[i]**3for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{4}" display(Math(texte)) Eq_4_1 = sympy.Eq( sum([b[i]*c[i]**3for i inrange(s)]).simplify(), sympy.Rational(1,4) ) texte =r'\sum_{i,j=1}^s b_i c_i a_{ij} c_j=' somma =sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{8}" display(Math(texte)) Eq_4_2 = sympy.Eq( sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,8) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j^2=' somma =sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{12}" display(Math(texte)) Eq_4_3 = sympy.Eq( sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,12) ) texte =r'\sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=' somma =sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{24}" display(Math(texte)) Eq_4_4 = sympy.Eq( sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,24) )return [Eq_4_1, Eq_4_2, Eq_4_3, Eq_4_4]################################################### Conditions avec s étages##################################################s =2# paramètres dans le cas générale# b_0, b_1 = sympy.symbols('b_0 b_1', real=True)# c_0, c_1 = sympy.symbols('c_0 c_1', real=True)# a_00, a_01, a_10, a_11 = sympy.symbols('a_00 a_01 a_10 a_11', real=True)# matrice dans le cas général# b = [b_0, b_1]# c = [c_0, c_1]# A = [[a_00, a_01], [a_10, a_11]]# matrice dans notre cas particulierb = [ sympy.Rational(1,4), sympy.Rational(3,4) ]c = [ 0, sympy.Rational(2,3) ]A = [ [ sympy.Rational(1,4), -sympy.Rational(1,4)] , [ sympy.Rational(1,4), sympy.Rational(5,12) ] ]Eqs = ordre_RK(s, A, b, c)
La suite vérifie \(u_n \xrightarrow[n\to \infty]{} 0\) ssi \(\left|q(x)\right|<1\). En étudiant brièvement la fonction \(q(x)\), on trouve que \(q(x)<1\) pour tout \(x>0\) :
Code
sympy.plot(q, (x,0,2.5), ylim=(-1.5,1.5), ylabel='q(x)', xlabel='x', title='q(x) en fonction de x')sympy.solve(abs(q)<1)
\(\displaystyle \text{True}\)
Correction point 4 : test de l’ordre
Code
################################################### EDO##################################################t0 =0tfinal =2y0 =1phi =lambda t,y: t*(1-t**2)-y################################################### solution exacte##################################################t = sympy.Symbol('t')y = sympy.Function('y')edo = sympy.Eq( (y(t)).diff() , phi(t,y(t)) )solpar = sympy.dsolve(edo , ics={y(t0):y0})display(solpar)sol_exacte = sympy.lambdify(t,solpar.rhs,'numpy')################################################### schéma ################################################### Paramètres du schéma recuperés depuis la matrice de Butcher obtenue précédemmentcc = np.array(c)bb = np.array(b)AA = np.array(A)s =len(cc)# Schéma de Runge-Kutta implicite à s étagesdef RK(phi, tt, y0): h = tt[1] - tt[0] uu = np.zeros_like(tt) uu[0] = y0 for n inrange(len(tt) -1): k_init = phi(tt[n], uu[n]) eqs =lambda KK: [ -KK[0] + phi(tt[n] , uu[n] + h/4*( KK[0] - KK[1]) ) ,-KK[1] + phi(tt[n] +2/3*h, uu[n] + h/12*( 3*KK[0] +5*KK[1]) ) ] KK = fsolve( eqs, [k_init,k_init] ) uu[n+1] = uu[n] + h/4*(KK[0]+3*KK[1])# eqs = lambda KK: [ -KK[i] + phi(tt[n] + cc[i]*h, uu[n] + h*sum([AA[i,j]*KK[j] for j in range(s)])) for i in range(s)]# KK = fsolve( eqs , k_init*np.ones(s) )# uu[n+1] = uu[n] + h*sum([KK[j]*b[j] for j in range(s)])return uu################################################### ordre##################################################H = []err = []plt.figure(figsize=(16,5))ax1 = plt.subplot(1,2,1)plt.xlabel('$t$')plt.ylabel('$y$')ax1.grid(True)N =10for k inrange(6): N +=10 tt = np.linspace(t0, tfinal, N +1) yy = sol_exacte(tt) uu = RK(phi, tt, y0) H.append( tt[1] - tt[0] ) err.append( np.linalg.norm(uu-yy,np.inf) ) ax1.plot(tt,uu,label=f'Approchée avec N={</span>N<span class="sc">}')ax1.plot(tt,yy,label='Exacte') # sur la grille la plus fineax1.legend()ax2 = plt.subplot(1,2,2)ax2.plot( np.log(H), np.log(err), 'r-o')plt.xlabel(r'$\ln(h)$')plt.ylabel(r'$\ln(e)$')plt.title(f'Le schéma a ordre {</span>np<span class="sc">.</span>polyfit(np.log(H),np.log(err),<span class="dv">1</span>)[<span class="dv">0</span>]<span class="sc">:1.2f}')ax2.grid(True)
D’après la barrière de Butcher, un schéma RK à \(s=2\) étages implicite ne peut pas être d’ordre supérieur à \(s=4\).
On peut bien-sûr écrire les formules à la main, mais on peut aussi utiliser sympy comme suit :
Code
def ordre_RK(s, A=None, b=None, c=None): j = sympy.symbols('j')if A isNone: A = sympy.MatrixSymbol('a', s, s)else: A = sympy.Matrix(A)if c isNone: c = sympy.symbols(f'c_0:{</span>s<span class="sc">}') if b isNone: b = sympy.symbols(f'b_0:{</span>s<span class="sc">}') display(Markdown("**Matrice de Butcher**")) But = matrice_Butcher(s, A, b, c) Eqs = [] display(Markdown(f"**On a {</span>s<span class="op">+</span><span class="dv">1</span><span class="sc">} conditions pour avoir consistance = pour être d'ordre 1**")) Eq_1 = ordre_1(s, A, b, c, j) Eqs.append(Eq_1) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) Eq_2 = ordre_2(s, A, b, c, j) Eqs.append([Eq_2]) display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**")) Eq_3 = ordre_3(s, A, b, c, j) Eqs.append(Eq_3) display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**")) Eq_4 = ordre_4(s, A, b, c, j) Eqs.append(Eq_4)return Eqsdef matrice_Butcher(s, A, b, c): But = sympy.Matrix(A) But = But.col_insert(0, sympy.Matrix(c)) last = [sympy.Symbol(" ")] last.extend(b) But = But.row_insert(s,sympy.Matrix(last).T) display(Math(sympy.latex(sympy.Matrix(But))))return Butdef ordre_1(s, A, b, c, j): texte ="\sum_{j=1}^s b_j ="+f"{</span><span class="bu">sum</span>(b)<span class="sc">.</span>simplify()<span class="sc">}" texte +=r"\text{ doit être égale à }1" display(Math(texte)) Eq_1 = [sympy.Eq( sum(b).simplify(), 1 )]for i inrange(s): somma = sympy.summation(A[i,j],(j,0,s-1)).simplify() texte =r'\sum_{j=1}^s a_{'</span><span class="op">+</span><span class="bu">str</span>(i)<span class="op">+</span><span class="vs">r'j}='+ sympy.latex( somma ) texte +=r"\text{ doit être égale à }"+sympy.latex(c[i]) display(Math( texte )) Eq_1.append(sympy.Eq( somma, c[i] ))return Eq_1 def ordre_2(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j='+sympy.latex(sum([b[i]*c[i] for i inrange(s)]).simplify()) texte +=r"\text{ doit être égale à }\frac{1}{2}" display(Math(texte)) Eq_2 = sympy.Eq( sum([b[i]*c[i] for i inrange(s)]).simplify(), sympy.Rational(1,2) )return Eq_2def ordre_3(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^2=' texte += sympy.latex( sum([b[i]*c[i]**2for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{3}" display(Math(texte)) Eq_3_1 = sympy.Eq( sum([b[i]*c[i]**2for i inrange(s)]).simplify(), sympy.Rational(1,3) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j=' somma =sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{6}" display(Math(texte)) Eq_3_2 = sympy.Eq( sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,6) )return [Eq_3_1, Eq_3_2]def ordre_4(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^3=' texte += sympy.latex( sum([b[i]*c[i]**3for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{4}" display(Math(texte)) Eq_4_1 = sympy.Eq( sum([b[i]*c[i]**3for i inrange(s)]).simplify(), sympy.Rational(1,4) ) texte =r'\sum_{i,j=1}^s b_i c_i a_{ij} c_j=' somma =sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{8}" display(Math(texte)) Eq_4_2 = sympy.Eq( sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,8) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j^2=' somma =sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{12}" display(Math(texte)) Eq_4_3 = sympy.Eq( sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,12) ) texte =r'\sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=' somma =sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{24}" display(Math(texte)) Eq_4_4 = sympy.Eq( sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,24) )return [Eq_4_1, Eq_4_2, Eq_4_3, Eq_4_4]################################################### Conditions avec s étages##################################################s =2# paramètres dans le cas générale# b_0, b_1 = sympy.symbols('b_0 b_1', real=True)# c_0, c_1 = sympy.symbols('c_0 c_1', real=True)# a_00, a_01, a_10, a_11 = sympy.symbols('a_00 a_01 a_10 a_11', real=True)# matrice dans le cas général# b = [b_0, b_1]# c = [c_0, c_1]# A = [[a_00, a_01], [a_10, a_11]]# matrice dans notre cas particulierb = [ sympy.Rational(3,4), sympy.Rational(1,4) ]c = [ sympy.Rational(1,3) , 1 ]A = [ [ sympy.Rational(5,12), -sympy.Rational(1,12)] , [ sympy.Rational(3,4), sympy.Rational(1,4) ] ]Eqs = ordre_RK(s, A, b, c)
La suite vérifie \(u_n \xrightarrow[n\to \infty]{} 0\) ssi \(\left|q(x)\right|<1\). En étudiant brièvement la fonction \(q(x)\), on trouve que \(q(x)<1\) pour tout \(x>0\) :
Code
sympy.plot(q, (x,0,2.5), ylim=(-1.5,1.5), ylabel='q(x)', xlabel='x', title='q(x) en fonction de x')sympy.solve(abs(q)<1)
\(\displaystyle \text{True}\)
Correction point 4 : test de l’ordre
Code
################################################### EDO##################################################t0 =0tfinal =2y0 =1phi =lambda t,y: t*(1-t**2)-y################################################### solution exacte##################################################t = sympy.Symbol('t')y = sympy.Function('y')edo = sympy.Eq( (y(t)).diff() , phi(t,y(t)) )solpar = sympy.dsolve(edo , ics={y(t0):y0})display(solpar)sol_exacte = sympy.lambdify(t,solpar.rhs,'numpy')################################################### schéma ################################################### Paramètres du schéma recuperés depuis la matrice de Butcher obtenue précédemmentcc = np.array(c)bb = np.array(b)AA = np.array(A)s =len(cc)# Schéma de Runge-Kutta implicite à s étagesdef RK(phi, tt, y0): h = tt[1] - tt[0] uu = np.zeros_like(tt) uu[0] = y0 for n inrange(len(tt) -1): eqs =lambda KK: [ -KK[i] + phi(tt[n] + cc[i]*h, uu[n] + h*sum([AA[i,j]*KK[j] for j inrange(s)])) for i inrange(s)] k_init = phi(tt[n], uu[n]) KK = fsolve( eqs , k_init*np.ones(s) ) uu[n+1] = uu[n] + h*sum([KK[j]*b[j] for j inrange(s)])return uu################################################### ordre##################################################H = []err = []plt.figure(figsize=(16,5))ax1 = plt.subplot(1,2,1)plt.xlabel('$t$')plt.ylabel('$y$')ax1.grid(True)N =10for k inrange(6): N +=10 tt = np.linspace(t0, tfinal, N +1) H.append( tt[1] - tt[0] ) yy = sol_exacte(tt) uu = RK(phi, tt, y0) err.append( np.linalg.norm(uu-yy,np.inf) ) ax1.plot(tt,uu,label=f'Approchée avec N={</span>N<span class="sc">}')ax1.plot(tt,yy,label='Exacte') # sur la grille la plus fineax1.legend()ax2 = plt.subplot(1,2,2)ax2.plot( np.log(H), np.log(err), 'r-o')plt.xlabel(r'$\ln(h)$')plt.ylabel(r'$\ln(e)$')plt.title(f'Le schéma a ordre {</span>np<span class="sc">.</span>polyfit(np.log(H),np.log(err),<span class="dv">1</span>)[<span class="dv">0</span>]<span class="sc">:1.2f}')ax2.grid(True)
D’après la barrière de Butcher, un schéma RK à \(s=3\) étages explicite ne peut pas être d’ordre supérieur à \(s=3\).
On peut bien-sûr écrire les formules à la main, mais on peut aussi utiliser un solveur pour résoudre le système d’équations non-linéaires comme suit :
Code
def ordre_RK(s, A=None, b=None, c=None): j = sympy.symbols('j')if A isNone: A = sympy.MatrixSymbol('a', s, s)else: A = sympy.Matrix(A)if c isNone: c = sympy.symbols(f'c_0:{</span>s<span class="sc">}') if b isNone: b = sympy.symbols(f'b_0:{</span>s<span class="sc">}') display(Markdown("**Matrice de Butcher**")) But = matrice_Butcher(s, A, b, c) Eqs = [] display(Markdown(f"**On a {</span>s<span class="op">+</span><span class="dv">1</span><span class="sc">} conditions pour avoir consistance = pour être d'ordre 1**")) Eq_1 = ordre_1(s, A, b, c, j) Eqs.append(Eq_1) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) Eq_2 = ordre_2(s, A, b, c, j) Eqs.append([Eq_2]) display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**")) Eq_3 = ordre_3(s, A, b, c, j) Eqs.append(Eq_3) # display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**"))# Eq_4 = ordre_4(s, A, b, c, j)# Eqs.append(Eq_4)return Eqsdef matrice_Butcher(s, A, b, c): But = sympy.Matrix(A) But = But.col_insert(0, sympy.Matrix(c)) last = [sympy.Symbol(" ")] last.extend(b) But = But.row_insert(s,sympy.Matrix(last).T) display(Math(sympy.latex(sympy.Matrix(But))))return Butdef ordre_1(s, A, b, c, j): texte ="\sum_{j=1}^s b_j ="+f"{</span><span class="bu">sum</span>(b)<span class="sc">.</span>simplify()<span class="sc">}" texte +=r"\text{ doit être égale à }1" display(Math(texte)) Eq_1 = [sympy.Eq( sum(b).simplify(), 1 )]for i inrange(s): somma = sympy.summation(A[i,j],(j,0,s-1)).simplify() texte =r'\sum_{j=1}^s a_{'</span><span class="op">+</span><span class="bu">str</span>(i)<span class="op">+</span><span class="vs">r'j}='+ sympy.latex( somma ) texte +=r"\text{ doit être égale à }"+sympy.latex(c[i]) display(Math( texte )) Eq_1.append(sympy.Eq( somma, c[i] ))return Eq_1 def ordre_2(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j='+sympy.latex(sum([b[i]*c[i] for i inrange(s)]).simplify()) texte +=r"\text{ doit être égale à }\frac{1}{2}" display(Math(texte)) Eq_2 = sympy.Eq( sum([b[i]*c[i] for i inrange(s)]).simplify(), sympy.Rational(1,2) )return Eq_2def ordre_3(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^2=' texte += sympy.latex( sum([b[i]*c[i]**2for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{3}" display(Math(texte)) Eq_3_1 = sympy.Eq( sum([b[i]*c[i]**2for i inrange(s)]).simplify(), sympy.Rational(1,3) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j=' somma =sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{6}" display(Math(texte)) Eq_3_2 = sympy.Eq( sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,6) )return [Eq_3_1, Eq_3_2]def ordre_4(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^3=' texte += sympy.latex( sum([b[i]*c[i]**3for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{4}" display(Math(texte)) Eq_4_1 = sympy.Eq( sum([b[i]*c[i]**3for i inrange(s)]).simplify(), sympy.Rational(1,4) ) texte =r'\sum_{i,j=1}^s b_i c_i a_{ij} c_j=' somma =sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{8}" display(Math(texte)) Eq_4_2 = sympy.Eq( sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,8) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j^2=' somma =sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{12}" display(Math(texte)) Eq_4_3 = sympy.Eq( sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,12) ) texte =r'\sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=' somma =sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{24}" display(Math(texte)) Eq_4_4 = sympy.Eq( sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,24) )return [Eq_4_1, Eq_4_2, Eq_4_3, Eq_4_4]################################################### Conditions avec s étages##################################################s =3# paramètres dans le cas générale# b_0, b_1, b_2 = sympy.symbols('b_0 b_1 b_2', real=True)# c_0, c_1, c_2 = sympy.symbols('c_0 c_1 c_2', real=True)# a_00, a_01, a_02, a_10, a_11, a_12, a_20, a_21, a_22 = sympy.symbols('a_00 a_01 a_02 a_10 a_11 a_12 a_20 a_21 a_22', real=True)# matrice dans le cas général# b = [b_0, b_1, b_2]# c = [c_0, c_1, c_2]# A = [[a_00, a_01, a_02], [a_10, a_11, a_12], [a_20, a_21, a_22]]# matrice dans notre cas particulierb = [ sympy.Rational(1,3), sympy.Rational(1,3), sympy.Rational(1,3)]c = [ 0, sympy.Rational(1,2), 1 ]A = [[ 0, 0, 0], [ sympy.Rational(1,2), 0, 0], [ 0, 1, 0]]Eqs = ordre_RK(s, A, b, c)
La suite vérifie \(u_n \xrightarrow[n\to \infty]{} 0\) ssi \(\left|q(x)\right|<1\). En étudiant brièvement la fonction \(q(x)\), on trouve que \(q(x)<1\) ssi \(x<6\) donné ci-dessous:.
Code
sympy.plot(q, (x,0,4), ylim=(-1.5,1.5), ylabel='q(x)', xlabel='x', title='q(x) en fonction de x')sol = sympy.solveset(q+1, x, domain=sympy.S.Reals) display(Markdown(f"$\\beta h<{</span>sol<span class="sc">.</span>args[<span class="dv">0</span>]<span class="sc">.</span>evalf()<span class="sc">}$"))
\(\beta h<2.51274532661833\)
Correction point 4 : test de l’ordre
Code
################################################### EDO##################################################t0 =0tfinal =2y0 =1phi =lambda t,y: t*(1-t**2)-y################################################### solution exacte##################################################t = sympy.Symbol('t')y = sympy.Function('y')edo = sympy.Eq( (y(t)).diff() , phi(t,y(t)) )solpar = sympy.dsolve(edo , ics={y(t0):y0})display(solpar)sol_exacte = sympy.lambdify(t,solpar.rhs,'numpy')################################################### schéma ################################################### Paramètres du schéma recuperés depuis la matrice de Butcher obtenue précédemmentcc = np.array(c)bb = np.array(b)AA = np.array(A)s =len(cc)# Schéma de Runge-Kutta implicite à s étagesdef RK(phi, tt, y0): h = tt[1] - tt[0] uu = np.zeros_like(tt) uu[0] = y0 for n inrange(len(tt) -1): k_0 = phi(tt[n], uu[n]) k_1 = phi(tt[n]+cc[1]*h, uu[n]+h*AA[1,0]*k_0) k_2 = phi(tt[n]+cc[2]*h, uu[n]+h*(AA[2,0]*k_0+AA[2,1]*k_1)) KK = [k_0, k_1, k_2] uu[n+1] = uu[n] + h*sum([KK[j]*b[j] for j inrange(s)])return uu################################################### ordre##################################################H = []err = []plt.figure(figsize=(16,5))ax1 = plt.subplot(1,2,1)plt.xlabel('$t$')plt.ylabel('$y$')ax1.grid(True)N =10for k inrange(6): N +=10 tt = np.linspace(t0, tfinal, N +1) H.append( tt[1] - tt[0] ) yy = sol_exacte(tt) uu = RK(phi, tt, y0) err.append( np.linalg.norm(uu-yy,np.inf) ) ax1.plot(tt,uu,label=f'Approchée avec N={</span>N<span class="sc">}')ax1.plot(tt,yy,label='Exacte') # sur la grille la plus fineax1.legend()ax2 = plt.subplot(1,2,2)ax2.plot( np.log(H), np.log(err), 'r-o')plt.xlabel(r'$\ln(h)$')plt.ylabel(r'$\ln(e)$')plt.title(f'Le schéma a ordre {</span>np<span class="sc">.</span>polyfit(np.log(H),np.log(err),<span class="dv">1</span>)[<span class="dv">0</span>]<span class="sc">:1.2f}')ax2.grid(True)
D’après la barrière de Butcher, un schéma RK à \(s=3\) étages implicite ne peut pas être d’ordre supérieur à \(s=6\).
On peut bien-sûr écrire les formules à la main, mais on peut aussi utiliser un solveur pour résoudre le système d’équations non-linéaires comme suit :
Code
def ordre_RK(s, A=None, b=None, c=None): j = sympy.symbols('j')if A isNone: A = sympy.MatrixSymbol('a', s, s)else: A = sympy.Matrix(A)if c isNone: c = sympy.symbols(f'c_0:{</span>s<span class="sc">}') if b isNone: b = sympy.symbols(f'b_0:{</span>s<span class="sc">}') display(Markdown("**Matrice de Butcher**")) But = matrice_Butcher(s, A, b, c) Eqs = [] display(Markdown(f"**On a {</span>s<span class="op">+</span><span class="dv">1</span><span class="sc">} conditions pour avoir consistance = pour être d'ordre 1**")) Eq_1 = ordre_1(s, A, b, c, j) Eqs.append(Eq_1) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) Eq_2 = ordre_2(s, A, b, c, j) Eqs.append([Eq_2]) display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**")) Eq_3 = ordre_3(s, A, b, c, j) Eqs.append(Eq_3) display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**")) Eq_4 = ordre_4(s, A, b, c, j) Eqs.append(Eq_4)return Eqsdef matrice_Butcher(s, A, b, c): But = sympy.Matrix(A) But = But.col_insert(0, sympy.Matrix(c)) last = [sympy.Symbol(" ")] last.extend(b) But = But.row_insert(s,sympy.Matrix(last).T) display(Math(sympy.latex(sympy.Matrix(But))))return Butdef ordre_1(s, A, b, c, j): texte ="\sum_{j=1}^s b_j ="+f"{</span><span class="bu">sum</span>(b)<span class="sc">.</span>simplify()<span class="sc">}" texte +=r"\text{ doit être égale à }1" display(Math(texte)) Eq_1 = [sympy.Eq( sum(b).simplify(), 1 )]for i inrange(s): somma = sympy.summation(A[i,j],(j,0,s-1)).simplify() texte =r'\sum_{j=1}^s a_{'</span><span class="op">+</span><span class="bu">str</span>(i)<span class="op">+</span><span class="vs">r'j}='+ sympy.latex( somma ) texte +=r"\text{ doit être égale à }"+sympy.latex(c[i]) display(Math( texte )) Eq_1.append(sympy.Eq( somma, c[i] ))return Eq_1 def ordre_2(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j='+sympy.latex(sum([b[i]*c[i] for i inrange(s)]).simplify()) texte +=r"\text{ doit être égale à }\frac{1}{2}" display(Math(texte)) Eq_2 = sympy.Eq( sum([b[i]*c[i] for i inrange(s)]).simplify(), sympy.Rational(1,2) )return Eq_2def ordre_3(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^2=' texte += sympy.latex( sum([b[i]*c[i]**2for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{3}" display(Math(texte)) Eq_3_1 = sympy.Eq( sum([b[i]*c[i]**2for i inrange(s)]).simplify(), sympy.Rational(1,3) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j=' somma =sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{6}" display(Math(texte)) Eq_3_2 = sympy.Eq( sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,6) )return [Eq_3_1, Eq_3_2]def ordre_4(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^3=' texte += sympy.latex( sum([b[i]*c[i]**3for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{4}" display(Math(texte)) Eq_4_1 = sympy.Eq( sum([b[i]*c[i]**3for i inrange(s)]).simplify(), sympy.Rational(1,4) ) texte =r'\sum_{i,j=1}^s b_i c_i a_{ij} c_j=' somma =sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{8}" display(Math(texte)) Eq_4_2 = sympy.Eq( sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,8) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j^2=' somma =sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{12}" display(Math(texte)) Eq_4_3 = sympy.Eq( sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,12) ) texte =r'\sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=' somma =sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{24}" display(Math(texte)) Eq_4_4 = sympy.Eq( sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,24) )return [Eq_4_1, Eq_4_2, Eq_4_3, Eq_4_4]################################################### Conditions avec s étages##################################################s =3# paramètres dans le cas générale# b_0, b_1, b_2 = sympy.symbols('b_0 b_1 b_2', real=True)# c_0, c_1, c_2 = sympy.symbols('c_0 c_1 c_2', real=True)# a_00, a_01, a_02, a_10, a_11, a_12, a_20, a_21, a_22 = sympy.symbols('a_00 a_01 a_02 a_10 a_11 a_12 a_20 a_21 a_22', real=True)# matrice dans le cas général# b = [b_0, b_1, b_2]# c = [c_0, c_1, c_2]# A = [[a_00, a_01, a_02], [a_10, a_11, a_12], [a_20, a_21, a_22]]# matrice dans notre cas particulierb = [ sympy.Rational(1,6), sympy.Rational(4,6), sympy.Rational(1,6)]c = [ 0, sympy.Rational(1,2), 1 ]A = [[ 0, 0, 0], [ sympy.Rational(5,24), sympy.Rational(1,3), -sympy.Rational(1,24)], [ 0, 1, 0]]Eqs = ordre_RK(s, A, b, c)
\(\displaystyle q(x) = \frac{- x^{3} + 5 x^{2} - 16 x + 24}{x^{2} + 8 x + 24}\)
La suite vérifie \(u_n \xrightarrow[n\to \infty]{} 0\) ssi \(\left|q(x)\right|<1\). En étudiant brièvement la fonction \(q(x)\), on trouve que \(q(x)<1\) ssi \(x<6\) donné ci-dessous:.
Code
sympy.plot(q, (x,0,10), ylim=(-1.5,1.5), ylabel='q(x)', xlabel='x', title='q(x) en fonction de x')sol = sympy.solveset(q+1, x, domain=sympy.S.Reals) display(Markdown(f"$\\beta h<{</span>sol<span class="sc">.</span>args[<span class="dv">0</span>]<span class="sc">}$"))
\(\beta h<6\)
Correction point 4 : test de l’ordre
Code
################################################### EDO##################################################t0 =0tfinal =10y0 =1phi =lambda t,y: -y################################################### solution exacte##################################################t = sympy.Symbol('t')y = sympy.Function('y')edo = sympy.Eq( (y(t)).diff() , phi(t,y(t)) )solpar = sympy.dsolve(edo , ics={y(t0):y0})display(solpar)sol_exacte = sympy.lambdify(t,solpar.rhs,'numpy')################################################### schéma ################################################### Paramètres du schéma recuperés depuis la matrice de Butcher obtenue précédemmentcc = np.array(c)bb = np.array(b)AA = np.array(A)s =len(cc)# Schéma de Runge-Kutta implicite à s étagesdef RK(phi, tt, y0): h = tt[1] - tt[0] uu = np.zeros_like(tt) uu[0] = y0 for n inrange(len(tt) -1): k_init = phi(tt[n],uu[n]) KK = fsolve( lambda kk: [ -kk[i] + phi( tt[n]+cc[i]*h , uu[n] + h*sum([kk[j]*AA[i,j] for j inrange(s)]) ) for i inrange(s) ], k_init*np.ones((s,1)) ) uu[n+1] = uu[n] + h*sum([KK[j]*b[j] for j inrange(s)])return uu################################################### ordre##################################################H = []err = []plt.figure(figsize=(16,5))ax1 = plt.subplot(1,2,1)plt.xlabel('$t$')plt.ylabel('$y$')ax1.grid(True)N =10for k inrange(6): N +=10 tt = np.linspace(t0, tfinal, N +1) H.append( tt[1] - tt[0] ) yy = sol_exacte(tt) uu = RK(phi, tt, y0) err.append( np.linalg.norm(uu-yy,np.inf) ) ax1.plot(tt,uu,label=f'Approchée avec N={</span>N<span class="sc">}')ax1.plot(tt,yy,label='Exacte') # sur la grille la plus fineax1.legend()ax2 = plt.subplot(1,2,2)ax2.plot( np.log(H), np.log(err), 'r-o')plt.xlabel(r'$\ln(h)$')plt.ylabel(r'$\ln(e)$')plt.title(f'Le schéma a ordre {</span>np<span class="sc">.</span>polyfit(np.log(H),np.log(err),<span class="dv">1</span>)[<span class="dv">0</span>]<span class="sc">:1.2f}')ax2.grid(True)
\(\displaystyle y{\left(t \right)} = e^{- t}\)
2.7 🎨 Exercice (\(s=3\), explicite avec paramètres)
D’après la barrière de Butcher, un schéma RK à \(s=3\) étages explicite ne peut pas être d’ordre supérieur à \(s=3\).
On peut bien-sûr écrire les formules à la main, mais on peut aussi utiliser sympy comme suit :
Code
def ordre_RK(s, A=None, b=None, c=None): j = sympy.symbols('j')if A isNone: A = sympy.MatrixSymbol('a', s, s)else: A = sympy.Matrix(A)if c isNone: c = sympy.symbols(f'c_0:{</span>s<span class="sc">}') if b isNone: b = sympy.symbols(f'b_0:{</span>s<span class="sc">}') display(Markdown("**Matrice de Butcher**")) But = matrice_Butcher(s, A, b, c) Eqs = [] display(Markdown(f"**On a {</span>s<span class="op">+</span><span class="dv">1</span><span class="sc">} conditions pour avoir consistance = pour être d'ordre 1**")) Eq_1 = ordre_1(s, A, b, c, j) Eqs.append(Eq_1) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) Eq_2 = ordre_2(s, A, b, c, j) Eqs.append([Eq_2]) display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**")) Eq_3 = ordre_3(s, A, b, c, j) Eqs.append(Eq_3) # display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**"))# Eq_4 = ordre_4(s, A, b, c, j)# Eqs.append(Eq_4)return Eqsdef matrice_Butcher(s, A, b, c): But = sympy.Matrix(A) But = But.col_insert(0, sympy.Matrix(c)) last = [sympy.Symbol(" ")] last.extend(b) But = But.row_insert(s,sympy.Matrix(last).T) display(Math(sympy.latex(sympy.Matrix(But))))return Butdef ordre_1(s, A, b, c, j): texte ="\sum_{j=1}^s b_j ="+f"{</span><span class="bu">sum</span>(b)<span class="sc">.</span>simplify()<span class="sc">}" texte +=r"\text{ doit être égale à }1" display(Math(texte)) Eq_1 = [sympy.Eq( sum(b).simplify(), 1 )]for i inrange(s): somma = sympy.summation(A[i,j],(j,0,s-1)).simplify() texte =r'\sum_{j=1}^s a_{'</span><span class="op">+</span><span class="bu">str</span>(i)<span class="op">+</span><span class="vs">r'j}='+ sympy.latex( somma ) texte +=r"\text{ doit être égale à }"+sympy.latex(c[i]) display(Math( texte )) Eq_1.append(sympy.Eq( somma, c[i] ))return Eq_1 def ordre_2(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j='+sympy.latex(sum([b[i]*c[i] for i inrange(s)]).simplify()) texte +=r"\text{ doit être égale à }\frac{1}{2}" display(Math(texte)) Eq_2 = sympy.Eq( sum([b[i]*c[i] for i inrange(s)]).simplify(), sympy.Rational(1,2) )return Eq_2def ordre_3(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^2=' texte += sympy.latex( sum([b[i]*c[i]**2for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{3}" display(Math(texte)) Eq_3_1 = sympy.Eq( sum([b[i]*c[i]**2for i inrange(s)]).simplify(), sympy.Rational(1,3) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j=' somma =sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{6}" display(Math(texte)) Eq_3_2 = sympy.Eq( sum([b[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,6) )return [Eq_3_1, Eq_3_2]def ordre_4(s, A, b, c, j): texte ='\sum_{j=1}^s b_j c_j^3=' texte += sympy.latex( sum([b[i]*c[i]**3for i inrange(s)]).simplify() ) texte +=r"\text{ doit être égale à }\frac{1}{4}" display(Math(texte)) Eq_4_1 = sympy.Eq( sum([b[i]*c[i]**3for i inrange(s)]).simplify(), sympy.Rational(1,4) ) texte =r'\sum_{i,j=1}^s b_i c_i a_{ij} c_j=' somma =sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{8}" display(Math(texte)) Eq_4_2 = sympy.Eq( sum([b[i]*c[i]*A[i,j]*c[j] for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,8) ) texte =r'\sum_{i,j=1}^s b_i a_{ij} c_j^2=' somma =sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{12}" display(Math(texte)) Eq_4_3 = sympy.Eq( sum([b[i]*A[i,j]*c[j]**2for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,12) ) texte =r'\sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=' somma =sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify() texte = texte + sympy.latex(somma) texte +=r"\text{ doit être égale à }\frac{1}{24}" display(Math(texte)) Eq_4_4 = sympy.Eq( sum([b[i]*A[i,j]*A[j,k]*c[k] for k inrange(s) for j inrange(s) for i inrange(s)]).simplify(), sympy.Rational(1,24) )return [Eq_4_1, Eq_4_2, Eq_4_3, Eq_4_4]################################################### Conditions avec s étages##################################################s =3# paramètres dans le cas générale# b_0, b_1, b_2 = sympy.symbols('b_0 b_1 b_2', real=True)# c_0, c_1, c_2 = sympy.symbols('c_0 c_1 c_2', real=True)# a_00, a_01, a_02, a_10, a_11, a_12, a_20, a_21, a_22 = sympy.symbols('a_00 a_01 a_02 a_10 a_11 a_12 a_20 a_21 a_22', real=True)# matrice dans le cas général# b = [b_0, b_1, b_2]# c = [c_0, c_1, c_2]# A = [[a_00, a_01, a_02], [a_10, a_11, a_12], [a_20, a_21, a_22]]# matrice dans notre cas particulierb_0, b_1 = sympy.symbols('b_0 b_1', real=True)b = [ b_0, b_1, 0 ]c = [ 0, sympy.Rational(1,3), sympy.Rational(2,3) ]A = [[ 0, 0, 0], [ sympy.Rational(1,3), 0, 0], [ 0, sympy.Rational(2,3), 0]]Eqs = ordre_RK(s, A, b, c)
La suite vérifie \(u_n \xrightarrow[n\to \infty]{} 0\) ssi \(\left|q(x)\right|<1\). En étudiant brièvement la fonction \(q(x)\), on trouve que \(q(x)<1\) ssi \(x<6\) donné ci-dessous:.
Code
sympy.plot(q, (x,0,2.5), ylim=(-1.5,1.5), ylabel='q(x)', xlabel='x', title='q(x) en fonction de x')sympy.solve(abs(q)<1)
\(\displaystyle x < 2\)
Correction point 4 : test de l’ordre
Code
################################################### EDO##################################################t0 =0tfinal =2y0 =2phi =lambda t,y: y*(1-y)*t################################################### solution exacte##################################################t = sympy.Symbol('t')y = sympy.Function('y')edo = sympy.Eq( (y(t)).diff() , phi(t,y(t)) )solpar = sympy.dsolve(edo , ics={y(t0):y0})display(solpar)sol_exacte = sympy.lambdify(t,solpar.rhs,'numpy')################################################### schéma ################################################### Paramètres du schéma recuperés depuis la matrice de Butcher obtenue précédemmentcc = np.array(c)bb = np.array(b)AA = np.array(A)s =len(cc)# Schéma de Runge-Kutta implicite à s étagesdef RK(phi, tt, y0): h = tt[1] - tt[0] uu = np.zeros_like(tt) uu[0] = y0 for n inrange(len(tt) -1): k_0 = phi(tt[n], uu[n]) k_1 = phi(tt[n]+cc[1]*h, uu[n]+h*AA[1,0]*k_0) k_2 = phi(tt[n]+cc[2]*h, uu[n]+h*(AA[2,0]*k_0+AA[2,1]*k_1)) KK = [k_0, k_1, k_2] uu[n+1] = uu[n] + h*sum([KK[j]*b[j] for j inrange(s)])return uu################################################### ordre##################################################H = []err = []plt.figure(figsize=(16,5))ax1 = plt.subplot(1,2,1)plt.xlabel('$t$')plt.ylabel('$y$')ax1.grid(True)N =10for k inrange(6): N +=10 tt = np.linspace(t0, tfinal, N +1) H.append( tt[1] - tt[0] ) yy = sol_exacte(tt) uu = RK(phi, tt, y0) err.append( np.linalg.norm(uu-yy,np.inf) ) ax1.plot(tt,uu,label=f'Approchée avec N={</span>N<span class="sc">}')ax1.plot(tt,yy,label='Exacte') # sur la grille la plus fineax1.legend()ax2 = plt.subplot(1,2,2)ax2.plot( np.log(H), np.log(err), 'r-o')plt.xlabel(r'$\ln(h)$')plt.ylabel(r'$\ln(e)$')plt.title(f'Le schéma a ordre {</span>np<span class="sc">.</span>polyfit(np.log(H),np.log(err),<span class="dv">1</span>)[<span class="dv">0</span>]<span class="sc">:1.2f}')ax2.grid(True)
Dans la littérature on trouve beaucoup de schémas de Runge-Kutta. Ci-dessous une petite liste de ces méthodes. Pour chaque méthode de Runge-Kutta indiquée, il est indiqué le nombre d’étages \(s\), son ordre de convergence \(\omega\) et si le schéma est explicite, semi-implicite ou implicite.
Exercice : étudier l’ordre théorique de convergence et le vérifier empiriquement.