1.1 EXERCICE 1 : Étude de l’ ❤️ entre Roméo et Juliette
Considérons une histoire d’amour entre Roméo et Juliette. Nous définissons \(R(t)\) comme l’amour de Roméo pour Juliette à l’instant \(t\) et \(J(t)\) comme l’amour de Juliette pour Roméo au même instant. Leur amour est modélisé par le système d’équations différentielles suivant :
Les paramètres \(a\), \(b\), \(c\) et \(d\) sont des constantes réelles qui décrivent les styles romantiques de Roméo et Juliette. Plus précisément, \(a\) et \(b\) caractérisent le style romantique de Roméo, tandis que \(c\) et \(d\) décrivent celui de Juliette.
Nous introduisons également une influence externe ou une fonction de perturbation \(f(t)\) pour Roméo et \(g(t)\) pour Juliette, pour tenir compte des influences ou perturbations externes.
Nous allons maintenant examiner comment leur dynamique amoureuse évolue dans différentes situations, avec différents types de fonctions de perturbation \(f(t)\) et \(g(t)\). Pour tous les tests, nous prenons \(a = -1\), \(b = 2\), \(c = -2\), \(d = 1\) et la valeur initiale est \((0.1; 0.1)\). Nous considérons l’intervalle de temps d’un mois (c’est-à-dire 30 jours).
Sans Perturbation Externe : Nous commençons par exclure les termes de perturbation externes dans le système : \(f(t)=g(t)=0\) pour tout \(t\). Nous examinerons le comportement périodique de leur amour.
Surprise pour Juliette : Supposons que Juliette reçoit une surprise de la part de Roméo, comme un cadeau inattendu. Cette situation peut être décrite par \(g(t)\), une fonction de stimulation, qui n’a de valeur qu’à un jour donné : \( g(t) = \begin{cases} 12 & \text{ si }10<t<11\\ 0 & \text{ sinon} \end{cases} \) Nous examinerons le comportement de leur amour dans cette situation avec \(f(t)=0\).
Nouvel Emploi pour Roméo : Supposons que Roméo obtient un nouvel emploi satisfaisant et est confiant dans leur vie future. Ici, \(f(t)=-0.03t\) et \(g(t)=0\) pour tout \(t\).
Perturbation Périodique Mineure : Enfin, nous considérons une situation de perturbation périodique mineure, qui représente l’influence de toutes sortes de petits faits quotidiens. Ici, \(f(t)=\sin(0.2\pi t)\) et \(g(t)=0\) pour tout \(t\).
EXERCICE : utiliser le schéma de Heun pour approcher la solution du système d’équations différentielles. Pour chaque situation, tracer sur le même plan les graphiques de \(R(t)\) et \(J(t)\) sur l’intervalle \([0, 30]\). Tracer ensuite le portrait de phase de leur amour, c’est-à-dire le graphe de \(J(t)\) en fonction de \(R(t)\).
affichage(24*11+1) # 11 joursaffichage(24*tfin+1) # 30 jours
Sans Perturbation Externe : le plan de phase suggère que leur amour est périodique. Leurs sentiments l’un pour l’autre oscillent périodiquement.
Surprise pour Juliette : le plan de phase suggère que ce type de perturbation ou de stimulus romantique peut entraîner un amour mutuel.
Nouvel Emploi pour Roméo : le plan de phase suggère que leur relation se développe vers un amour mutuel.
Perturbation Périodique Mineure : il est difficile de prévoir le développement de leur relation.
1.1.5Affichage dynamique (si interact installé)
Code
from ipywidgets import interactinteract(affichage, heures=(24,24*tfin,24));# on increment par 24h
1.2 EXERCICE 2 : schéma 👣 explicite avec paramètres
Pour quelles valeurs de \(\eta\) et \(\vartheta\) le schéma multipas linéaire suivant est convergent ? \(
u_{n+1} = (3\vartheta-2\eta)u_n + \left(2-\frac{5}{2}\eta\right)u_{n-1} + h \eta(\varphi_n+\varphi_{n-1})
\)
Sans effectuer de calculs, quel est l’ordre maximal théorique de ce schéma ?
Calculer l’ordre de convergence de ce schéma.
Tester empiriquement l’ordre de convergence du schéma ainsi obtenu sur le problème de Cauchy \(y'(t) = \sin(2t)-y(t)\sin(t)\) et \(y(\pi/2) = 1\) pour \(t\in[\pi/2,2\pi]\).
Remarques :
les deux premiers points peuvent être résolus “à la main” ou avec sympy (dans ma correction, je vous montrerai comment faire avec sympy).
dans le dernier point, attention à bien indiquer à chaque étape si les fonctions que vous utlisez appartiennent à numpy ou à sympy.
1.2.1Correction point 1
C’est un schéma à \(q=2\) pas, c’est-à-dire de la forme \(
u_{n+1} = a_0u_n+a_1u_{n-1}+h\big(b_{-1}\varphi_{n+1}+b_0\varphi_n+b_1\varphi_{n-1}\big)
\) avec \(a_0=3\vartheta-2\eta\), \(a_1=2-\frac{5}{2}\eta\), \(b_{-1}=0\) et \(b_0=b_1=\eta\). Il est donc explicite.
Pour qu’il soit convergent, il faut que le schéma soit zéro-stable et consistant.
Écrivons donc qui sont \(\xi(0)\), \(\xi(1)\), \(\xi(2)\), \(\xi(3)\) puis le premier polynôme caractéristique \(\varrho\) et calculons ses racines dans le cas général d’un schéma à \(q=2\) pas :
Code
%reset -ffrom sympy import symbols, Symbol, latex, factor, solve, Eq, poly, Rational, rootsfrom IPython.display import display, Math, Markdown, Latex# ========================q =2# ========================a_0, a_1 = symbols('a_0 a_1 ', real=True)b_0, b_1, b_m1 = symbols('b_0 b_1 b_{-1}', real=True)r = Symbol('r')# ========================def 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()# ========================aa = [a_0, a_1]bb = [b_0, b_1]display(Markdown(f"Pour une méthode à q={</span>q<span class="sc">} pas")) display(Markdown(f"- on écrit le premier polynôme caractéristique (pour étudier la zéro-stabilité)")) rho = poly(r**(q) -sum( aa[j] * r**(q-1-j) for j inrange(q)), r)texte =r"$\varrho(r)="+ latex(rho.as_expr(),order='old') +r"$"display(Math(texte))display(Markdown(f"dont les racines sont :"))racines = roots(rho,r)for k,v in racines.items(): display(k)display(Markdown(f"- on affiche $\\xi(i)$ (pour étudier la consistance et l'ordre de consistance)"))for i inrange(4): display(Markdown(f"$\\xi({</span>i<span class="sc">}) = {</span>latex(xi(i, q))<span class="sc">}$"))
Pour une méthode à q=2 pas
on écrit le premier polynôme caractéristique (pour étudier la zéro-stabilité)
\(\displaystyle \varrho(r)=- a_{1} - r a_{0} + r^{2}\)
Pour que le schéma soit consistant il faut que \(\xi(0)=\xi(1)=1\): \(
\begin{cases}
a_0+a_1=1 \\
-a_1+b_0+b_1+b_{-1}=1
\end{cases}
\) Dans notre cas, cela donne
Code
eta, theta = symbols(r'\eta \vartheta', real=True)aa = [3*theta-2*eta, 2-5*eta/2]bb = [eta, eta]b_m1 =0systeme = [Eq(xi(i, q),1) for i inrange(2)]display(Markdown(r"$\begin{cases}"+' '.join([ r"\displaystyle"+latex(s)+r"\\"for s in systeme]) +r"\end{cases}$"))
Pour que le schéma soit zéro-stable il faut que le premier polynôme caractéristique \(\varrho(r)=r^2-a_0r-a_1\) ait ses racines de module inférieur ou égal à 1. Si une racine est de module 1, elle doit être simple.
Le premier polynôme caractéristique est \(r^2+2r-3\). Ses racines sont \(r_1=-1/3\) et \(r_2=1\). Le schéma est donc zéro-stable.
D’après la première barrière de Dahlquist, un schéma à \(q=2\) pas explicite est au mieux d’ordre \(q=2\). On doit donc juste vérifier si \(\xi(2)=1\).
Il s’agit d’un schéma explicite, car la matrice \(\mathbb A\) est triangulaire inférieure stricte.
1.3.2Correction point 2 : borne supérieure pour l’ordre et calcul de \(b_0\)
La barrière de Dalquist affirme qu’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
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 =3# paramètres dans le cas généraleb_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éralb = [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 = [ b_0, 0, 1-b_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)
On a 4 conditions pour avoir consistance = pour être d’ordre 1
\(\displaystyle \sum_{j=1}^s b_j =1\text{ doit être égale à }1\)
\(\displaystyle \sum_{j=1}^s a_{0j}=0\text{ doit être égale à }0\)
\(\displaystyle \sum_{j=1}^s a_{1j}=\frac{1}{3}\text{ doit être égale à }\frac{1}{3}\)
\(\displaystyle \sum_{j=1}^s a_{2j}=\frac{2}{3}\text{ doit être égale à }\frac{2}{3}\)
On doit ajouter 1 condition pour être d’ordre 2
\(\displaystyle \sum_{j=1}^s b_j c_j=\frac{2}{3} - \frac{2 b_{0}}{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=\frac{4}{9} - \frac{4 b_{0}}{9}\text{ doit être égale à }\frac{1}{3}\)
\(\displaystyle \sum_{i,j=1}^s b_i a_{ij} c_j=\frac{2}{9} - \frac{2 b_{0}}{9}\text{ doit être égale à }\frac{1}{6}\)
En conclusion, le schéma est d’ordre 1 par construction. De plis, le paramètre \(b_0\) doit vérifier les conditions suivantes pour que le schéma soit d’ordre 2 et éventuellement 3 :
Code
for i,eq inenumerate(Eqs[1:]): display(Markdown(f"**Pour être d'ordre {</span>i<span class="op">+</span><span class="dv">2</span><span class="sc">} il faut vérifier**")) display(Math(sympy.latex((eq))))
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<x_0\) donné ci-dessous:.
Code
sympy.plot(q, (x,0,5), 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">}$"))