Mise en évidence des ordres de convergence
Pour les schémas d'Euler, point au milieu, Heun et Runge-Kutta d'ordre 4.
- Numpy : vectorisation, fonction sur les vecteurs
- Matplotlib : légende, échelle logarithmique
Pour les schémas d'Euler, point au milieu, Heun et Runge-Kutta d'ordre 4.
Considérons l'équation différentielle ordinaire
avec \(f\), \(U\), \(y_0\), \(t\) et \(T\) comme il faut (existence, unicité, etc.). Le plus souvent \(U\) de la forme \([t_0,t_0+T]\times V\) avec \(V\) ouvert de \(\mathbb{R}^m\).
Toujours sous certaines hypothèses, nous savons que les schémas d'Euler, point au milieu, Heun et Runge-Kutta convergent avec une estimation de l'erreur vers la solution exacte.
Les schémas (à pas fixe) consistent en une discrétisation du problème continue. Le pas est noté \(h=T/N\), la discrétisation en temps \(t_i=t_0+hi\). La suite \(y_n\) sensée approcher \(y(t_n)\) est initialisée par la donnée initiale.
Euler (explicite)
Point au milieu
Méthode Heun
Méthode de Runge-Kutta d'ordre 4
Il n'y aucune difficulté à programmer les quatre méthodes. La vectorisation de Numpy permet de gérer les systèmes différentiels. Par exemple Runge-Kutta d'ordre 4 s'écrit à peu près
def myrk4_all(f,t0,T,y0,n):
# retourne toutes les valeurs
dt = T/n
Y=np.zeros((np.size(y0),n+1))
Y[:,0]=y0
tpt=np.linspace(t0,t0+T,n+1)
for i in range(n):
p1=f(tpt[i],Y[:,i])
Y2=Y[:,i]+dt/2*p1
p2=f(tpt[i]+dt/2,Y2)
Y3=Y[:,i]+dt/2*p2
p3=f(tpt[i]+dt/2,Y3)
Y4=Y[:,i]+dt*p3
p4=f(tpt[i+1],Y4)
Y[:,i+1]=Y[:,i]+dt*(p1+2*p2+2*p3+p4)/6
return Y
Euler : \(C/n\)
Point au milieu et Heun : \(C/n^2\)
Runge-Kutta d'ordre 4 : \(C/n^4\)
Si ypt contient les approximations en la subdivision et si y est la solution exacte
np.max(np.abs(ypt-y(tpt)))
retourne le maximum de l'erreur discrète
Pour la visualisation un graphique à double échelle logarithmique est l'idéal
plt.xscale('log')
plt.yscale('log')
plt.plot(VN,err1,'+',label='Euler')
plt.plot(VN,err2,'*',label='Pt au milieu')
plt.legend()
p1, = plt.plot(VN,err1,'+')
p2, = plt.plot(VN,err2,'*')
p3, = plt.plot(VN,err3,'o')
p4, = plt.plot(VN,err4,'x')
q1, = plt.plot(VN,1/VN)
q2, = plt.plot(VN,1/(VN**2))
q3, = plt.plot(VN,1/(VN**4))
l1 = plt.legend([p1 , p2, p3, p4], ["Euler", "Pt au milieu", "Heun", "Runge Kutta 4"],loc=3)
l2 = plt.legend([q1, q2, q3],["1/N", "1/N^2", "1/N^4"],loc=1)
plt.gca().add_artist(l1)
plt.xscale('log')
plt.yscale('log')
plt.show()
On choisit les entiers \(n\) de tests d'erreur avec une échelle exponentielle
In [2]: VN=(1.3)**np.arange(10,32)
In [3]: VN=VN.astype(int)
In [4]: print(VN)
[ 13 17 23 30 39 51 66 86 112 146 190 247 321 417 542
705 917 1192 1550 2015 2619 3405]
La conversion permet de faire une boucle selon VN (ce n'est pas seule solution).