On ne peut pas calculer analytiquement la solution exacte.
Pour calculer des solutions approchées on doit utiliser un schéma numérique. Quelle caractéristique doit-il avoir ? Justifier la réponse.
Q [4 points] Pour calculer des solutions approchées on doit utiliser un schéma numérique. Quelle caractéristique doit-il avoir ? Justifier la réponse.
🐸 Il s’agit d’un des problèmes de Cauchy proposés lors du CT 2023 de l’ECUE M61 Équations différentielles.
Bien qu’on ne puisse pas calculer analytiquement la solution exacte, nous pouvons tracer les lignes de courant pour avoir une idée du comportement de la solution en fonction de la donnée initiale. On en déduit que le problème de Cauchy est numériquement mal posé. Il faut alors utiliser un schéma d’ordre elevé.
Pour s’en convaincre nous pouvons aussi demander à odeint du module scipy de tracer la solution approchée pour différentes valeurs de \(y_0\).
Code
%reset -f%matplotlib inlineimport numpy as npimport matplotlib.pyplot as pltfrom scipy.integrate import odeint# variables globalest0 =0tfinal =10phi =lambda t,y: np.sin(np.pi*2*y)*(1-1/(4+t)-y)N =200tt = np.linspace(t0, tfinal, N +1)plt.figure(figsize=(10,5))# On trace d'abord les lignes de courantg1 = np.linspace(0,10,21)g2 = np.linspace(0.5,1,21)T,Y = np.meshgrid(g1,g2) DT, DY =1, phi(T,Y) # compute growth rate on the gridM = np.hypot(DT,DY) # = sqrt(DT**2+DY**2) # norm growth rate plt.streamplot(T,Y, DT/M, DY/M, color=M, linewidth=0.5, cmap=plt.cm.viridis, density=2, arrowstyle='->', arrowsize=1.5)plt.grid()plt.xlabel('t')plt.ylabel('y')plt.title('Lignes de courant');# On trace quelque solution approchéefor y0 in np.linspace(0.7,0.9,7): uu = odeint(phi,y0,tt, tfirst=True) plt.plot(tt,uu,lw=4,label=f'$y_0={</span>y0<span class="sc">:g}$')plt.legend(bbox_to_anchor=(1.04, 1), loc='upper left');
2 Exercice 2 [7 points] : étude d’un schéma multipas
On notera \(\varphi_k\stackrel{\text{déf}}{=}\varphi(t_k,u_k)\). Considérons la méthode multipas
La méthode est elle consistente? Est elle convergente? Si oui, étudier théoriquement l’ordre de convergence.
Vérifier empiriquement l’ordre de convergence sur le problème de Cauchy \( \begin{cases}
y'(t) = (y(t)+2)\dfrac{2t^2+2t-1}{1+t}, &\forall t \in I=[0,2],\\
y(0) = -1,
\end{cases} \)
On remarque qu’il s’agit de la méthode de Crank-Nicolson sur l’intervalle \([t_{n-1},t_{n+1}]\).
\(
\begin{cases}
|r_j|\le1 \quad\text{pour tout }j=0,\dots,p
\\
\text{ multiplicité de $r_j$ > }1 \implies |r_j|<1
\end{cases}
\)
Q2 [3 points] La méthode est elle consistente? Est elle convergente? Si oui, étudier théoriquement l’ordre de convergence.
La méthode étant zéro-stable, si elle est consistante, alors elle est convergente. Pour étudier la convergence introduisons la quantité \(
\begin{align*}
\xi(i) &=
\sum_{j=0}^p (-j)^{i}a_j+i\sum_{j=-1}^p (-j)^{i-1}b_j
\\ &=
(-0)^{i}a_0+(-1)^ia_1+i \Big( (1)^{i-1}b_{-1}+(-0)^{i-1}b_0+(-1)^{i-1}b_1 \Big)
\end{align*}
\)
avec \((-0)^0=1\).
Pour que la méthode soit consistante il faut que \(\xi(0)=\xi(1)=1\). De plus, pour que la méthode soit d’ordre \(\omega\), il faut que \(\xi(i)=1\) pour tout \(i\le\omega\).
De plus, \(\omega\) vérifie la première barrière de Dahlquist: le schéma étant implicite à \(q=2\) (pair) pas consistante et zéro-stable, \(\omega=q+2\le4\).
En calculant \(\xi\) on trouve que la méthode est d’ordre 2 (cf. calculs avec sympy ci-dessous).
Code
%reset -fimport sympy aa_eval = [0,1]bb_eval = [0,1]bm1_eval =1###########################################################################from IPython.display import display, Math, Markdowndef xi(i,aa,bb,bm1): sa =sum( [ (-j)**i * aa[j] for j inrange(q) ] ) sb = bm1+sum( [(-j)**(i-1)*bb[j] for j inrange(1,q)] )if i==1: sb += bb[0]return (sa)+(i*sb)q =len(aa_eval) # nb de pasp = q-1# j = 0...p # coeffs du schemaomega = q+2if q%2==0else q+1aa = sympy.symbols(f'a_0:{</span>q<span class="sc">}')bb = sympy.symbols(f'b_0:{</span>q<span class="sc">}')bm1 = sympy.Symbol('b_{-1}')display(Markdown(f"C'est une méthode à $q={</span>p <span class="op">+</span> <span class="dv">1</span><span class="sc">}$ pas d'ordre $\\omega\\le{</span>omega<span class="sc">}$ avec"))texte =''.join([ f"{</span>sympy<span class="sc">.</span>latex(aa[j])<span class="sc">}={</span>sympy<span class="sc">.</span>latex(aa_eval[j])<span class="sc">},"+r"\quad "for j inrange(p+1)])texte +=''.join([ f"{</span>sympy<span class="sc">.</span>latex(bb[j])<span class="sc">}={</span>sympy<span class="sc">.</span>latex(bb_eval[j])<span class="sc">},"+r"\quad "for j inrange(p+1)])texte +=f"{</span>sympy<span class="sc">.</span>latex(bm1)<span class="sc">}={</span>sympy<span class="sc">.</span>latex(bm1_eval)<span class="sc">}"display(Math( texte )) xi_eval = [xi(i,aa_eval,bb_eval,bm1_eval) for i inrange(omega+1)]for i inrange(omega+1): display(Math( f"\\xi({</span>i<span class="sc">}) = {</span>sympy<span class="sc">.</span>latex(xi(i,aa,bb,bm1))<span class="sc">} = {</span>sympy<span class="sc">.</span>latex(xi_eval[i])<span class="sc">}" ))if xi_eval[i]!=1: display(Markdown( f"La méthode est donc d'ordre $\\omega = {</span>i<span class="op">-</span><span class="dv">1</span><span class="sc">}$" )) break
C’est une méthode à \(q=2\) pas d’ordre \(\omega\le4\) avec
Déterminer les coefficients \(\sigma\), \(\vartheta\), \(\gamma\) pour que le schéma soit d’ordre 3. Est-il d’ordre 4 ?
Étudier empiriquement l’ordre de convergence sur le problème de Cauchy \( \begin{cases}
y'(t)=\dfrac{t^2+y^2(t)}{ty(t)}, & t\in[1;5]\\
y(1)=1
\end{cases} \)
Étudier théoriquement la A-stabilité du schéma optimal.
Code
%reset -f%matplotlib inlineimport numpy as npimport matplotlib.pyplot as pltfrom scipy.optimize import fsolveimport sympy sympy.init_printing()from IPython.display import display, Math, Markdownprlat =lambda*args : display(Math(''.join( sympy.latex(arg) for arg in args )))
Q1 [5 points] Pour quelles valeurs des paramètres le schéma est d’ordre 3? Et d’ordre 4?
Soit \(\omega\) l’ordre de la méthode.
C’est un schéma implicite à \(2\) étages (\(s=2\)) donc \(\omega\le2s=4\).
Code
sigma = sympy.Symbol(r"\sigma")theta = sympy.Symbol(r"\vartheta")gamma = sympy.Symbol(r"\gamma")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**")) matrice_Butcher(s, A, b, c) 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**")) ordre_1(s, A, b, c, j) display(Markdown("**On doit ajouter 1 condition pour être d'ordre 2**")) ordre_2(s, A, b, c, j) display(Markdown("**On doit ajouter 2 conditions pour être d'ordre 3**")) ordre_3(s, A, b, c, j) display(Markdown("**On doit ajouter 4 conditions pour être d'ordre 4**")) ordre_4(s, A, b, c, j)returnNonedef 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))))returnNonedef 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))returnNonedef 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)) 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))returnNonedef 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)) 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)) 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)) 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))returnNone# APPLICATION A NOTRE CASc = [sigma,sympy.S(1)]b = [gamma,1-gamma]A = [[sigma,sympy.S(0)],[theta,1-theta]]s =len(c)display(Markdown(f"La méthode de Runge-Kutta est à {</span>s<span class="sc">} étages"))ordre_RK(s,A,b,c)
On commence à resoudre le système dont les inconnues sont les paramètres \(\sigma, \gamma, \vartheta\) pour avoir au moins l’ordre 3:
Code
cnst = sympy.solve( [ sum([b[i]*c[i] for i inrange(s)])-1/sympy.S(2),sum([b[i]*c[i]**2for i inrange(s)])-1/sympy.S(3),sum([b[i]*A[i][j]*c[j] for i inrange(s) for j inrange(s)])-1/sympy.S(6) ] )[0]display(Math(sympy.latex(cnst)))c_substituted = [expr.subs(cnst) for expr in c]b_substituted = [expr.subs(cnst) for expr in b]A_substituted = [[expr.subs(cnst) for expr in row] for row in A]
En particulier, dans le cas d’ordre 3, on a \(\begin{cases}
u_0 = y_0 \\
K_1 = -\beta u_n-\beta \frac{h}{3}K_1 \leadsto K_1=\frac{-3\beta}{3+\beta h}u_n\\
K_2 = -\beta\left(u_n+hK_1\right)\leadsto K_2=\frac{2\beta^2h-3\beta}{3+\beta h}u_n\\
u_{n+1} = u_n + \frac{h}{4}\left(3K_1+K_2\right) & n=0,1,\dots N-1
\end{cases}
\) L’étude ci-dessous montre que, dans ce cas, le schéma est A-stable ssi \(h<\frac{6}{\beta}\).
Code
sympy.var('u_n, h, β, K1, K2,') g =lambda y : -β*yeq1 = sympy.Eq( K1 , g(u_n+h*K1*sigma))eq2 = sympy.Eq( K2 , g(u_n+h*(K1*theta+K2*(1-theta))) )sol = sympy.solve([eq1,eq2],[K1,K2])sol = { key:value.factor() <span class="cf">for</span> key,value <span class="kw">in</span> sol.items() }display(sol)RHS = u_n+h*(gamma*K1+(1-gamma)*K2).factor()RHS = RHS.subs(sol).simplify().factor()texte ='u_{n+1}='+ sympy.latex(RHS)display(Math(texte)) print(r"Notons x=hβ>0. On trouve donc")x = sympy.Symbol('x',positive=True)RHS = RHS.subs(h*β,x).simplify()texte ='u_{n+1}='+ sympy.latex(RHS)display(Math(texte)) print("Considérons le schéma d'ordre 3:")display(cnst)RHS = RHS.subs(cnst)texte =r"\text{La méthode est A-stable ssi }|q(x)|<1\text{ avec }q(x)=\frac{u_{n+1</span><span class="sc">}}{u_n}="texte += sympy.latex(RHS/u_n)display(Math(texte)) sympy.solve([-1<RHS/u_n,RHS/u_n<1])
\(\displaystyle \left\{ K_{1} : - \frac{u_{n} β}{\sigma h β + 1}, \ K_{2} : \frac{u_{n} β \left(\sigma h β - \vartheta h β + 1\right)}{\left(\sigma h β + 1\right) \left(\vartheta h β - h β - 1\right)}\right\}\)
\(\displaystyle u_{n+1}=- \frac{u_{n} \left(\gamma \sigma h^{2} β^{2} - \gamma h^{2} β^{2} - \sigma \vartheta h^{2} β^{2} + \sigma h β + \vartheta h^{2} β^{2} - \vartheta h β + 1\right)}{\left(\sigma h β + 1\right) \left(\vartheta h β - h β - 1\right)}\)
Notons x=hβ>0. On trouve donc
Considérons le schéma d'ordre 3:
\(\displaystyle u_{n+1}=\frac{u_{n} \left(\gamma \sigma x^{2} - \gamma x^{2} - \sigma \vartheta x^{2} + \sigma x + \vartheta x^{2} - \vartheta x + 1\right)}{\left(\sigma x + 1\right) \left(- \vartheta x + x + 1\right)}\)