TP 3 Schéma des trapèzes implicites

In [1]:
import numpy as np
from scipy.integrate import solve_ivp  # solveur EDO de Python (initial value problem)
from matplotlib import pyplot as plt
In [2]:
def fun(t, y): 
    return 3* y - 4*np.exp(-t)
In [3]:
t0, tfinal = 0, 5
y0 = 1.0

Code du schéma des trapèzes implicites

In [4]:
pas=[];
erreur=[];
h=1;#pas de depart
nbiter=10; #on passe DIX fois dans la boucle
#le dernier pas de temps utilise est 1/2^9 
# la mise à jour du pas s'effectue en effet après le calcul de 
# la solution approchee

# boucle sur les pas de temps de plus en plus petits
for k in range(nbiter):
    #initialisation
    x=np.arange(t0,tfinal+h,h)
    N=np.size(x)
    yapp=np.zeros(N)
    t = t0
    y = y0
    yapp[0]=y0
    # code la methode des trapezes pour le pas h
    for j in range(1,N):
        y=yapp[j-1]
        #initialisation avec Euler
        z=y+h* fun(t,y)
        # iterations de point fixe
        for i in range(3):
            z = y + 0.5*h*(fun(t,y) + fun(t+h,z))
        yapp[j]=z
        #pas de temps suivant
        t = t + h
    err=np.max(np.abs(yapp-np.exp(-x)));
    pas.append(h);
    erreur.append(err)
    h=h/2 #divise le pas par deux. c'est pour cela que nbiter=10 et pas 9
In [5]:
#trace la solutions exacte
xexact=np.arange(t0,tfinal,1e-2)
yexact=np.exp(-xexact);
plt.plot(xexact,yexact,'r');
plt.plot(x,yapp,'-k')#trace la solution approchee
plt.legend(['solution exacte', 'solution approchee trapèzes implicites'])
plt.xlabel('t')
plt.ylabel('y')
plt.show()
In [6]:
#trace l'erreur en fonction du pas en coordonnées log-log 
plt.loglog(pas, erreur,'-og')
plt.loglog(pas,np.power(pas,2),'--og')
plt.legend(['schéma trapèze implicite','pente 2'],loc='best')
plt.xlabel('log pas')
plt.ylabel('log erreur')
plt.title('ordre de convergence du schéma des trapèzes implicites')
plt.show()
In [7]:
#solveur basé sur schéma RK45 de Scipy
sol = solve_ivp(fun, [t0, tfinal], [1], 'RK45',dense_output=True)
In [8]:
plt.plot(sol.t, sol.y.T, '-ob')
plt.plot(x,yapp,'-k')
t_eval=np.arange(t0,tfinal,1e-2)
plt.plot(t_eval, np.exp(-t_eval),'-r')
plt.xlabel('t')
plt.ylabel('y')
plt.legend(['RK45','Trapèzes implicites', 'sol. exacte'], shadow=True)
plt.show()

La solution générale de l'équation différentielle est $ y(t) = C \, \exp(3t) + \exp(-t).$ Pour la solution exacte vérifiant la condition initiale, $y(t) = \exp(-t)$ i.e. $C=0.$ Les schémas numériques en s'écartant un peu de la solution exacte calculent des approximations avec $C \ll 1$ mais non rigoureusement nul. Au bout d'un certain temps le terme $C \, \exp(3t)$ devient dominant.

In [9]:
# tracé de solutions voisines de la solution qui s'en écartent progressivement.
plt.plot(t_eval, np.exp(-t_eval),'r')
for C in [-3e-7, -2e-7, -1e-7,-0.5e-7,0.5e-7,1e-7, 2e-7, 3e-7 ]:
    plt.plot(t_eval, C*np.exp(3*t_eval)+ np.exp(-t_eval))
plt.xlabel('t')
plt.ylabel('y')
plt.title('sol C exp(3t) + exp(-t) pour C entre -3e-7 et 3e-7')
plt.show()