Calculer la solution exacte en fonction de \(\lambda\in\mathbb{R}\) et \(\varepsilon\).
Si \(\lambda = 10\) et \(\varepsilon=0\), quel type de schéma doit-on privilégier pour résoudre ce problème de Cauchy ?
Si \(\lambda = -10\) et \(\varepsilon\neq0\), quel type de schéma doit-on privilégier pour résoudre ce problème de Cauchy ?
1.1Correction
On peut résoudre ce problème de Cauchy à la main en remarquant que l’edo se réécrit comme \( \lambda \big(y(t) - \cos(t)\big) = y'(t) +\sin(t) = \big(y(t) - \cos(t)\big)'. \) Si on pose \(z(t)=y(t) - \cos(t)\) on a le problème de Cauchy \(z'(t) = \lambda z(t)\) avec \(z(0) = y(0) - 1\). La solution est donc \(z(t) = (y(0) - 1) e^{\lambda t}\) et donc \( y(t) = \varepsilon e^{\lambda t} + \cos(t). \)
Si \(\lambda>0\), il s’agit d’un problème de Cauchy numériquement mal posé (c’est-à-dire, il est très sensible aux perturbations sur la donnée initiale). En effet, si \(\varepsilon=0\), la solution exacte est simplement \(y(t) = \cos(t)\), mais pour \(\varepsilon>0\), elle croît comme une exponentielle.
On doit donc choisir un schéma d’ordre élévé.
Code
import matplotlib.pyplot as pltimport numpy as nptt = np.linspace(0, 10, 100)fig, ax = plt.subplots(figsize=(8, 6))for epsi in [-0.1,0,0.1]: y_sol = sp.lambdify(t, sol.rhs.subs({lamb:<span class="dv">10</span>,epsilon:epsi}), 'numpy') plt.plot(tt, y_sol(tt), label=fr'$\epsilon={</span>epsi<span class="sc">}$')ax.set_xlabel('t')ax.set_ylabel('y')ax.grid()ax.legend()ax.axes.set_ylim(-3, 3);
Si \(\lambda<0\) et \(|\lambda|\gg1\), il s’agit d’un problème de Cauchy raide. En effet, si \(\varepsilon\neq0\), la solution s’amorti vers \(\cos(t)\) sur une intervalle très court.
On doit donc choisir un schéma inconditionellement A-stable.
Code
import matplotlib.pyplot as pltimport numpy as nptt = np.linspace(0, 0.5, 100)fig, ax = plt.subplots(figsize=(8, 6))for epsi in [-0.1,0,0.1]: y_sol = sp.lambdify(t, sol.rhs.subs({lamb:<span class="op">-</span><span class="dv">10</span>,epsilon:epsi}), 'numpy') plt.plot(tt, y_sol(tt), label=fr'$\epsilon={</span>epsi<span class="sc">}$')ax.set_xlabel('t')ax.set_ylabel('y')ax.grid()ax.legend()ax.axes.set_ylim(1-0.2, 1+0.2);
2 EXERCICE 2 : schémas 🎨 de Runge-Kutta à 4 étages explicite d’ordre maximal
Écrire la matrice de Butcher d’un schéma RK à \(s=4\) étages expliciteconsistant (elle ne comportera que les 9 coefficients \(c_1\), \(c_2\), \(c_3\), \(b_1\), \(b_2\), \(b_3\), \(a_{21}\), \(a_{31}\), \(a_{32}\)).
Sans effectuer de calculs, donner l’ordre maximal d’un schéma explicite à 4 étages.
Soit \(\kappa\) le nombre de lettres de votre prénom, dans mon cas je pose kappa = len("Gloria").
Poser \(c_1=\frac{1}{\kappa}\), \(c_2=1-c_1\) et \(c_3=1\). Déterminer les autres 6 paramètres pour que le schéma explicite soit d’ordre maximal.
Tester empiriquement l’ordre de convergence de ce schéma sur le problème de Cauchy suivant : \(y'(t) = 10(y(t)-\sin(t))+\cos(t)\) et \(y(0) = 0\) pour \(t\in[0,\pi/2]\). Est-ce un schéma adapté à ce type de problème ?
Déterminer sous quelle condition sur \(h\) ce schéma est A-stable.
Code
%reset -fimport sympy sympy.init_printing()from IPython.display import display, Math, Markdownprlat =lambda*args : display(Math(''.join( sympy.latex(arg) for arg in args )))import numpy as npimport matplotlib.pyplot as plt# from scipy.optimize import fsolve
2.1Correction point 1 : matrice de Butcher
Si le schéma est explicite, la matrice \(\mathbb A\) est triangulaire inférieure et la diagonale ne contient que des zéros, donc \(a_{00}=a_{01}=a_{02}=a_{03}=a_{11}=a_{12}=a_{13}=a_{22}=a_{23}=a_{33}=0\).
Si le schéma est consistant alors \( \begin{cases}
\displaystyle\sum_{j=0}^3 b_{i}=1& \\
\displaystyle c_i=\sum_{j=0}^3 a_{ij}&i=0,\dots,3
\end{cases} \)
ainsi \(c_0=0\), \(a_{10}=c_1\), \(a_{20}=c_2-a_{21}\), \(a_{30}=c_3-a_{31}-a_{32}\) et enfin \(b_0=1-b_1-b_2-b_3\).
Avec ces 15 relations, il ne reste plus que 24-15=9 coefficients à déterminer, à savoir \(a_{21}\), \(a_{31}\), \(a_{32}\), \(b_1\), \(b_2\), \(b_3\), \(c_1\), \(c_2\) et \(c_3\): \(
\begin{array}{c|cccc}
0 & 0 & 0 & 0 & 0\\
c_1 & c_1 & 0& 0 & 0\\
c_2 & c_2-a_{21} & a_{21}& 0 & 0\\
c_3 & c_3-a_{31}-a_{32} & a_{31}& a_{32} & 0\\
\hline
& 1-b_1-b_2-b_3 & b_1 & b_2 & b_3
\end{array}
\)
2.2Correction point 2 : borne supérieure pour l’ordre
La barrière de Butcher affirme qu’un schéma RK à \(s=4\) étages explicite ne peut pas être d’ordre supérieur à \(s=4\).
2.3Correction point 3 : paramètres pour ordre maximal
On a déjà pris en compte les conditions de consistance. Il reste à déterminer les paramètres pour que le schéma soit d’ordre maximal. Cela revient à résoudre le système d’équations non-linéaires suivant :
On peut aussi utiliser sympy pour retrouver ce système :
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 {s+1} conditions pour avoir consistance = pour être d'ordre 1**"))# ordre_1(s, A, b, c, j) 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.extend(Eq_3) display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**")) Eq_4 = ordre_4(s, A, b, c, j) Eqs.extend(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))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 ))returnNonedef 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 =4# Construction de la matrice de Butcher en supposant # que le schéma est Explicite# et qu'il est consistant (i.e. au moins d'ordre 1) b_1, b_2, b_3 = sympy.symbols('b_1 b_2 b_3', real=True)c_1, c_2, c_3 = sympy.symbols('c_1 c_2 c_3', real=True)a_21, a_31, a_32 = sympy.symbols('a_21 a_31 a_32', real=True)b = [1-b_1-b_2-b_3, b_1, b_2, b_3]c = [0, c_1, c_2, c_3]A = [[0, 0, 0, 0], [c_1, 0, 0, 0], [c_2-a_21, a_21, 0, 0], [c_3-a_31-a_32, a_31, a_32, 0]]Eqs = ordre_RK(s, A, b, c)# for eq in Eqs:# display(eq)
\(\displaystyle \sum_{j=1}^s b_j c_j=b_{1} c_{1} + b_{2} c_{2} + b_{3} c_{3}\text{ doit être égale à }\frac{1}{2}\)
On doit ajouter 2 conditions pour être d’ordre 3
\(\displaystyle \sum_{j=1}^s b_j c_j^2=b_{1} c_{1}^{2} + b_{2} c_{2}^{2} + b_{3} c_{3}^{2}\text{ doit être égale à }\frac{1}{3}\)
\(\displaystyle \sum_{i,j=1}^s b_i a_{ij} c_j=a_{21} b_{2} c_{1} + a_{31} b_{3} c_{1} + a_{32} b_{3} c_{2}\text{ doit être égale à }\frac{1}{6}\)
On doit ajouter 4 conditions pour être d’ordre 4
\(\displaystyle \sum_{j=1}^s b_j c_j^3=b_{1} c_{1}^{3} + b_{2} c_{2}^{3} + b_{3} c_{3}^{3}\text{ doit être égale à }\frac{1}{4}\)
\(\displaystyle \sum_{i,j=1}^s b_i c_i a_{ij} c_j=a_{21} b_{2} c_{1} c_{2} + a_{31} b_{3} c_{1} c_{3} + a_{32} b_{3} c_{2} c_{3}\text{ doit être égale à }\frac{1}{8}\)
\(\displaystyle \sum_{i,j=1}^s b_i a_{ij} c_j^2=a_{21} b_{2} c_{1}^{2} + a_{31} b_{3} c_{1}^{2} + a_{32} b_{3} c_{2}^{2}\text{ doit être égale à }\frac{1}{12}\)
\(\displaystyle \sum_{i,j,k=1}^s b_i a_{ij} a_{jk} c_k=a_{21} a_{32} b_{3} c_{1}\text{ doit être égale à }\frac{1}{24}\)
On résout ce système NON LINÉAIRE pour trouver les coefficients dans le cas particulier où \(c_1\), \(c_2\) et \(c_3\) sont donnés. Voici le démarche de résolution :
on trouve \(b_1\), \(b_2\) et \(b_3\) en résolvant le sous-sytème (linéaire) : \(
\begin{cases}
b_{1} c_{1} + b_{2} c_{2} + b_{3} c_{3} = \frac{1}{2}, \\
b_{1} c_{1}^{2} + b_{2} c_{2}^{2} + b_{3} c_{3}^{2} = \frac{1}{3}, \\
b_{1} c_{1}^{3} + b_{2} c_{2}^{3} + b_{3} c_{3}^{3} = \frac{1}{4}, \\
\end{cases}
\)
on trouve le dernier paramètre \(a_{32}\) en résolvant l’équation : \(
a_{21} a_{32} b_{3} c_{1} = \frac{1}{24}.
\)
Remarque Dans l’énoncé j’ai donné \(c_3=1\) car cela simplifie les calculs à la main, mais en réalité il suffit de fixer \(c_1\) et \(c_2\) et on retrouve \(c_3=1\) en résolvant le système :
Code
# 7 équations (non linéaires) et 9 inconnues# On fixe 2 paramètres et on résoud le système non linéairekappa =len("Gloria")choix = {c_1 : sympy.Rational(<span class="dv">1</span>,kappa), c_2 : sympy.Rational(kappa<span class="op">-</span><span class="dv">1</span>,kappa)}display(Markdown("On fixe $c_1$ et $c_2$"))display(choix)sol = sympy.solve( [eq.subs(choix) for eq in Eqs] )[0]display(Markdown("En imposant d'être d'ordre 4, on trouve les 7 autres paramètres :"))display(sol)display(Markdown("Autrement dit, la matrice de Butcher d'un schéma explicite consistant à 4 étages"))But = matrice_Butcher(s, A, b, c)display(Markdown("devient, avec les valeurs de $c_1$ et $c_2$ données en imposant l'ordre 4"))But = But.subs(choix).subs(sol)display(But)
# Variante "semi-automatique" # k_0 = sympy.symbols(r'k_0')# k_1 = sympy.symbols(r'k_1')# k_2 = sympy.symbols(r'k_2')# k_3 = sympy.symbols(r'k_3')# kk = [k_0, k_1, k_2, k_3]# phi_A = lambda y: -beta*y# Eqs = [ sympy.Eq( kk[i] , phi_A(u_n + dt*sum([kk[j]*A[i,j] for j in range(s)])) ) for i in range(s) ]# for eq in Eqs:# display(eq)# sol = sympy.solve( Eqs, kk ) # c'est un dictionnaire# KK = [sol[kk[i]] for i in range(s)]# schema = sympy.Eq( u_np1 , u_n + dt*sum([KK[j]*b[j] for j in range(s)]) )# # display(schema)# display(Math(sympy.latex(sympy.Eq(sympy.Symbol('u_{n+1}'),schema.rhs.simplify()))))
On a donc une suite du type \(u_{n+1}=q(\beta h) u_n\). On peut expliciter \(u_n\) en fonction de \(u_0\) et du produit \(\beta h\) (on notera \(x\) le produit \(\beta h\)) car \(u_n=q(x)^nu_0\) avec \(q(x)=u_{n+1}/u_n\) :
La suite vérifie \(\lim_{n\to \infty} u_n = 0\) ssi \(\left|q(x)\right|<1\). En étudiant brièvement la fonction \(q(x)\), on trouve que \(q(x)<1\) ssi \(x<x_0\) donné ci-dessous:.
Code
sympy.plot(q, (x,0,4), ylim=(-1,1), ylabel='q(x)', xlabel='x', title='q(x) en fonction de x')sol = sympy.solveset(q-1, x,domain=sympy.S.Reals) sol0, x0 = sol.argsdisplay(Markdown(f"$\\beta h<{</span>x0<span class="sc">.</span>evalf()<span class="sc">}$"))
\(\beta h<2.78529356340528\)
3 EXERCICE 3 : schémas 👣 à 2 pas d’ordre maximal
Écrire le schéma multipas à \(q=2\) pas (comportant 5 coefficients).
Sans effectuer de calculs, répondre aux deux questions suivantes :
quel est l’ordre maximal d’un schéma à 2 pas convergent ?
quel est l’ordre maximal d’un schéma à 2 pas explicite convergent ?
Parmi ces schémas, calculer les coefficients du seul schéma consistant d’ordre 4. Montrer que le schéma ainsi trouvé est zéro-stable.
Tester empiriquement l’ordre de convergence du schéma ainsi obtenu sur le problème de Cauchy \(y'(t) = 4t(t^2-1)+y(t)\) et \(y(0) = 1\) pour \(t\in[0,1]\).
Considérons les schémas explicites à 2 pas (comportant 4 coefficients).
Montrer que le schéma consistant d’ordre 3 n’est pas zéro-stable.
Écrire la famille de schémas consistants d’ordre 2 zéro-stables en les paramètrant par \(a_0\) (autrement-dit, indiquer sous quelles conditions sur \(a_0\) le schéma est convergent d’ordre 2).
Code
%reset -fimport sympy as spimport numpy as npimport matplotlib.pyplot as pltfrom scipy.optimize import fsolvefrom IPython.display import display, Math, Markdown
La première barrière de Dahlquist affirme qu’un schéma à \(q=2\) pas
s’il est implicite, il est au mieux d’ordre \(q+2=4\);
s’il est explicite, il est au mieux d’ordre \(q=2\).
3.3Correction point 3 : calcul des paramètres
Il contient les 5 paramètres \(a_0\), \(a_1\), \(b_{-1}\), \(b_0\), \(b_1\), il est donc théoriquement possible de construire un schéma d’ordre 4 en résolvant le système linéaire de \(q+1=5\) équations suivant
3.5Correction point 5 : calcul des paramètres pour les schémas explicites
Il contient les 4 paramètres \(a_0\), \(a_1\), \(b_0\), \(b_1\), il est donc théoriquement possible de construire un schéma d’ordre 3 en résolvant le système linéaire de \(4\) équations suivant
Cépendant on sait, d’après la première barrière de Dalquist, qu’un schéma multipas linéaire explicite à \(q\) pas est au mieux d’ordre \(q\). Donc un schéma à 2 pas ne peut pas être d’ordre 3. On peut le vérifier en calculant le polynôme caractéristique du schéma :
On trouve \(a_1=1-a_0\), \(b_0=2-\frac{a_0}{2}\) et \(b_1=-\frac{a_0}{2}\).
Ci-dessous la résolution avec sympy :
Code
systeme = [sp.Eq(xi(i, q),1) for i inrange(3)]display(Markdown(r"$\begin{cases}"+' '.join([sp.latex(s)+r"\\"for s in systeme]) +r"\end{cases}$"))sol = sp.solve(systeme, (a_1, b_0, b_1))display(sol)