Calculer la solution exacte en fonction de \(\beta\) et \(\varepsilon\).
Si \(\beta = -5\) et \(\varepsilon=0\), quel type de schéma doit-on privilégier pour résoudre ce problème de Cauchy ?
1.1Correction point 1
Méthode 1 On peut résoudre ce problème de Cauchy directement en remarquant que l’edo se réécrit comme \(
y'(t) - \cos(t) = -\beta \big(y(t)-\sin(t)\big),
\)
soit encore \(
\big(y(t)-\sin(t)\big)' = -\beta \big(y(t)-\sin(t)\big).
\)
Si on pose \(z(t)=y(t)-\sin(t)\) on a le problème de Cauchy \(
z'(t) = -\beta z(t)
\)
avec \(z(0) = y(0)-0=\varepsilon\). La solution est donc \(z(t) = z(0) e^{-\beta t}= \varepsilon e^{-\beta t}\) et donc \(
\boxed{y(t)} = z(t)+\sin(t) \boxed{= \sin(t)+\varepsilon e^{-\beta t}}
\)
Méthode 2 On peut résoudre le problème de Cauchy comme en L1 : la solution générale de l’EDO \(a(t)y'(t)+b(t)y(t)=g(t)\) est donnée par \(
y(t) = C e^{-A(t)} + B(t) e^{-A(t)}
\)
où \(A(t) = \int^t \frac{b(s)}{a(s)}ds\) et \(B(t) = \int^t \frac{g(s)}{a(s)}e^{A(s)}ds\). Dans notre cas, on a \(y'(t) +\beta y(t) = \beta \sin(t) + \cos(t)\), donc \(A(t) = \int^t \beta ds = \beta t\) et \(B(t) = \int^t e^{\beta s}(\beta \sin(s) + \cos(s))ds=e^{\beta t}\sin(t)\). La solution générale est alors \(y(t) = C e^{-\beta t} + \sin(t)\). En utilisant la condition initiale \(y(0)=\varepsilon\), on trouve \(C=\varepsilon\) et enfin \(y(t) = \sin(t)+\varepsilon e^{-\beta t}\).
Méthode 3 On peut calculer la solution en utilisant sympy :
Si \(\beta<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\), \(y(t) \sim \varepsilon e^{-\beta t} \xrightarrow[t\to\infty]{} +\infty\),
si \(\varepsilon<0\), \(y(t) \sim \varepsilon e^{-\beta t} \xrightarrow[t\to\infty]{} -\infty\),
si \(\varepsilon=0\), \(y(t) = \sin(t) \in [-1;1]\) pour tout \(t\).
Une toute (petite) erreur de calcul aura le même effet qu’une perturbation de la condition initiale : on “réveille” le terme exponentielle. On doit donc choisir un schéma d’ordre élevé car les erreurs d’approximation amènent toujours à résoudre un problème perturbé.
Pour bien comprendre, allons voir l’influence de l’ordre du schéma en comparant les approximations obtenues avec le schéma d’Euler explicite et un schéma RK aussi explicite d’ordre 4 dans le cas \(\varepsilon=0\) et \(\beta=-5\). On remarque qu’initialement les approximations sont proches de la solution exacte, mais l’erreur d’approximation du schéma d’Euler explicite fait que la solution approchée correspond plutôt à une solution ayant \(\varepsilon>0\). Le schéma RK est plus précis mais finit par diverger lui aussi.
Code
import matplotlib.pyplot as pltimport numpy as nptt = np.linspace(0, 5, 300)fig, (ax1, ax2) = plt.subplots(nrows=1,ncols=2,figsize=(16, 6))# Solutions exactes pour différentes valeurs de epsilon et beta = -5for epsi in [-1e-3, -1e-8, 0, 1e-8, 1e-3]: y_sol = sp.lambdify(t, sol.rhs.subs({beta:<span class="op">-</span><span class="dv">5</span>,epsilon:epsi}), 'numpy') ax1.plot(tt, y_sol(tt), label=fr'$\epsilon={</span>epsi<span class="sc">}$')ax1.set_xlabel('t')ax1.set_ylabel('y')ax1.grid()ax1.legend()ax1.axes.set_ylim(-5, 5)ax1.set_title('Solutions exactes pour différents $\epsilon$')# Approximations du cas epsilon = 0 avec un schéma d'ordre 1 et un schéma d'ordre 4def EE(phi, tt, y0): h = tt[1] - tt[0] uu = np.zeros_like(tt) uu[0] = y0for i inrange(len(tt) -1): uu[i+1] = uu[i] + h*phi(tt[i],uu[i])return uudef RK4(phi,tt,y0): h = tt[1]-tt[0] uu = np.zeros_like(tt) uu[0] = y0for n inrange(len(tt)-1): k1 = phi( tt[n], uu[n] ) k2 = phi( tt[n]+h/2 , uu[n]+k1*h/2 ) k3 = phi( tt[n]+h/2 , uu[n]+h*k2/2 ) k4 = phi( tt[n+1] , uu[n]+h*k3 ) uu[n+1] = uu[n] + (k1+2*k2+2*k3+k4)*h/6return uuphi =lambda t,y : -5*(np.sin(t)-y)+np.cos(t)y0 =0ax2.plot(tt, EE(phi, tt, y0), ':', label='Euler explicite')ax2.plot(tt, RK4(phi, tt, y0), ':', label='RK4')y_sol = sp.lambdify(t, sol.rhs.subs({beta:<span class="op">-</span><span class="dv">5</span>,epsilon:<span class="dv">0</span>}), 'numpy')ax2.plot(tt, y_sol(tt), label='Exacte')ax2.set_xlabel('t')ax2.set_ylabel('y')ax2.grid()ax2.legend()ax2.axes.set_ylim(-5, 5)ax2.set_title(r"Solution exacte VS approximations avec EE et RK4 pour $\varepsilon=0$");
2 EXERCICE 2 : schémas 👣 linéaire à 3 pas d’ordre maximal
Écrire le schéma à \(q=3\) pas linéaire (il comportera donc 7 coefficients).
Il n’est pas nécessaire de répondre à cette question pour la suite de l’exercice.
Les 7 équations linéaires \(\xi(i)=1\) pour \(i=0,\dots,6\) constituent un système linéaire dont les 7 inconnues sont les coefficients du schéma. Calculer les coefficients de ce système consistant d’ordre 6 et montrer qu’il n’est pas zéro-stable.
Sans effectuer de calculs, répondre aux deux questions suivantes :
quel est l’ordre maximal d’un schéma à 3 pas implicite convergent ?
quel est l’ordre maximal d’un schéma à 3 pas explicite convergent ?
Dans la suite on fixera \(b_{-1}=0\) et \(b_1 = -4/3\). De plus, \(a_1\) sera fixé en fonction de votre prénom et nom (pour cela, remplacez mon prénom et mon nom par les vôtres dans la cellule ci-dessous).
Déterminer les 4 paramètres manquants pour que le schéma soit d’ordre maximal et convergent.
Tester empiriquement l’ordre de convergence du schéma ainsi obtenu sur le problème de Cauchy \(y'(t) = \sin^2(t)y(t)\) et \(y(0) = 1\) pour \(t\in[0,2]\).
Code
%reset -ffrom IPython.display import display, Math, Markdownimport sympy as spimport numpy as npimport matplotlib.pyplot as pltfrom scipy.optimize import fsolve# ================================================# On fixe $a_1$ pour le point 4# ================================================nom ="Faccanoni"prenom ="Gloria"S =sum([ord(c) for c in nom+prenom])Lista = [ sp.Rational(num,12) for num inrange(-24,13) ]idx = S%len(Lista)display(Markdown(f"**{</span>nom<span class="sc">}{</span>prenom<span class="sc">}** : $a_1 = {</span>Lista[idx]<span class="sc">}$"))
Faccanoni Gloria : \(a_1 = 0\)
2.1Correction point 1 : schéma
Un schéma implicite à \(q=3\) étapes s’écrit \(
u_{n+1}=a_0u_n+a_1u_{n-1}+a_2u_{n-2}+h\big(b_{-1}\varphi_{n+1}+b_0\varphi_n+b_1\varphi_{n-1}+b_2\varphi_{n-2}\big)
\)
2.2Correction point 2 : ordre maximal et non convergence
q =3def xi(i, q): sa =sum((-j)**i * aa[j] for j inrange(q)) sb = b_m1 +sum((-j)**(i-1) * bb[j] for j inrange(1, q))if i ==1: sb += bb[0]return (sa).factor() + (i * sb).factor()# Ordre maximal selon Dalquistomega = q +2if q%2==0else q +1# i = 0, ..., omega# Définition des symbolesa_0, a_1, a_2 = sp.symbols('a_0 a_1 a_2', real=True)b_0, b_1, b_2 = sp.symbols('b_0 b_1 b_2', real=True)b_m1 = sp.symbols('b_{-1}', real=True)aa = [a_0, a_1, a_2]bb = [b_0, b_1, b_2]# display(Markdown(f"Pour une méthode à q={q} pas, on affiche $\\xi(i)$ pour i = 0, ..., {2*q+1}"))# for i in range(7):# display(Markdown(f"$\\xi({i}) = {sp.latex(xi(i, q))}$"))display(Markdown(f"Une méthode à q={</span>q<span class="sc">} pas contient {</span><span class="dv">2</span><span class="op">*</span>q<span class="op">+</span><span class="dv">1</span><span class="sc">} paramètres, on peut donc résoudre le système de {</span><span class="dv">2</span><span class="op">*</span>q<span class="op">+</span><span class="dv">1</span><span class="sc">} équations suivant (garantissant la consistance d'ordre {</span><span class="dv">2</span><span class="op">*</span>q<span class="sc">}) pour les déterminer :"))systeme = [sp.Eq(xi(i, q),1) for i inrange(7)]display(Markdown(r"$\begin{cases}"+' '.join([sp.latex(s)+r"\\"for s in systeme]) +r"\end{cases}$"))
Une méthode à q=3 pas contient 7 paramètres, on peut donc résoudre le système de 7 équations suivant (garantissant la consistance d’ordre 6) pour les déterminer :
Cépendant on sait, d’après la première barrière de Dalquist, qu’un schéma multipas linéaire implicite à \(q\) pas avec \(q\) impair est au mieux d’ordre \(q+1\). Donc un schéma à 3 pas ne peut pas être d’ordre 6. On peut le vérifier en calculant le polynôme caractéristique du schéma : \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}=r^3-a_0r^2-a_1r-a_2=(r-1)(r^2+\frac{38}{11}r+1).
\)
La méthode n’est pas zéro-stable car une des racines n’est pas dans le cercle unité (voir le calcul des racines ci-dessous) :
Code
r = sp.Symbol('r')p = q-1rho = sp.poly(r**(p+1) -sum( aa[j].subs(sol) * r**(p-j) for j inrange(p+1)), r)display(Markdown(f"Le premier polynome caractéristique est :"))txt = sp.latex(sp.Eq(sp.symbols(r'\varrho(r)'),rho.as_expr()),order='old')txt +="="+ sp.latex(rho.as_expr().factor(),order='old')display(Math(txt))display(Markdown(f"Ses racines sont :"))racines = sp.solve(rho,r)display(racines)display(Markdown(f"dont les modules valent :"))display([abs(rac).evalf() for rac in racines])
Le cas correspondant à mon prénom et nom est le suivant :
Code
# voir la cellule initiale pour fixer le paramètrechoix = {b_m1 : <span class="dv">0</span> , a_1 : Lista[idx] , b_1 : sp.Rational(<span class="op">-</span><span class="dv">4</span>,<span class="dv">3</span>)}display(Markdown(f"Pour le choix ${</span>sp<span class="sc">.</span>latex(choix)<span class="sc">}$"))systeme = [sp.Eq(xi(i, q).subs(choix),1) for i inrange(4)]display(Markdown("le système de 4 équations devient :"))display(Markdown(r"$\begin{cases}"+' '.join([sp.latex(s)+r"\\"for s in systeme]) +r"\end{cases}$"))
Pour le choix \(\left\{ a_{1} : 0, \ b_{1} : - \frac{4}{3}, \ b_{-1} : 0\right\}\)
Vérifions si le schéma ainsi obtenu est zéro-stable en calculant les racines du premier polynôme caractéristique.
Le premier polynôme caractéristique est \(
\varrho(r)=r^{p+1}-\sum_{j=0}^p a_jr^{p-j}=r^3-r^2=r^3-a_0r^2-a_1r-a_2.
\)
La méthode est zéro-stable ssi ses racines sont de module inférieur ou égal à 1 et si elles sont simples lorsqu’elles ont module égal à 1. Ce qui est bien le cas ici :
Code
r = sp.Symbol('r')p = q-1rho = sp.poly(r**(p+1) -sum( aa[j].subs(sol).subs(choix) * r**(p-j) for j inrange(p+1)), r)display(Markdown(f"Le premier polynome caractéristique est :"))display(Math(sp.latex(rho.as_expr() ,order='old')))display(Markdown(f"Ses racines, avec leur multiplicité, sont :"))racines = sp.roots(rho,r)display(racines)display([float(abs(rac)) for rac in racines.keys()])
Le premier polynome caractéristique est :
\(\displaystyle - r^{2} + r^{3}\)
Ses racines, avec leur multiplicité, sont :
{1: 1, 0: 2}
[1.0, 0.0]
Remarque : juste en considérant la condition de consistance, on peut factoriser le polynôme caractéristique par \(r-1\), car \(a_0 = 1-a_1-a_2\) ainsi :
Attention : ils sont donnés comme des fractions sympy, il faudra les convertir en flottants pour les utiliser dans vos codes d’approximation numérique.
Déterminer \(\alpha\) pour que le schéma soit d’ordre maximal.
Tester empiriquement l’ordre de convergence de ce schéma sur le problème de Cauchy \(y'(t) = 4t(1-t^2)-y(t)\) et \(y(0) = 1\) pour \(t\in[0,1]\).
Conclusion : tous les schémas donnés sont d’ordre 2 si on pose \(\alpha\) comme ci-dessous : \(
\begin{array}{c|cc|c}
\text{Lettre} & b_0 & b_1 & \alpha\\
\hline
A-F & {2}/{3} & {1}/{3} & 1/4\\
G-L & {1}/{3} & {2}/{3} & -1/2\\
M-R & {4}/{3} & -{1}/{3} & 5/8\\
S-Z & -{1}/{3} & {4}/{3} & 5/2\\
\end{array}
\)
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, 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# alpha = sympy.symbols(r'\alpha')b = [ b0, b1]alpha=1-1/(2*b0)display(Math(f"\\alpha = {</span>alpha<span class="sc">}, b = {</span>b<span class="sc">}"))c = [alpha,1]A = [[0, alpha], [1,0]]Eqs = ordre_RK(s, A, b, c)