In [1]:
import numpy as np
import matplotlib.pyplot as plt
from scipy.sparse import linalg,diags
In [2]:
def diffusion(mu, T, xmin, xmax, dx, dt):
    """ calcule et trace la solution de l'edp
         u_t - mu u_xx =0
         avec la donnée initiale u(., t=0) =f(x)
         pour f(x) de différentes formes.
          sur  xmin<x<xmax, 0<t<T
         avec la méthode des différences finies
         on code 3  schémas
         discrétisation explicite centrée
         discrétisation implicite centrée
        discrétisation de Crank-Nicolson
         on affiche la CFL parabolique = c*dt/dx^2
        le script retourne la matrice u(j,n,s) = u(x_j, t_n,s)
         pour les 3 schémas s=0 explicite,
         1 implicite 2 Crank-Nicolson
    """ 
    # maillage
    x=np.arange(xmin,xmax,dx)
    Nx=np.size(x)
    t=np.arange(0,T,dt)
    Nt=np.size(t)
    #initialisation pour les 3 schémas
    u=np.empty((Nx,Nt,3));
    # condition initiale
    def f(x):
        #decommenter la fonction choisie.
        # fonction Heaviside lissée
        # y = 0.*(x<0)+4*x**2*(3-4*x)*(0<=x)*(x<=0.5)+ 1.*(x>0.5)
        #fonction 1_(x<0)
         y = 1.*(x<0);
        #fonction creneau 1_(-1/2,1/2)
        # y =  1.*(-0.5<=x)*(x<1/2);
        # cloche de Gauss.
        # y = np.exp(-25*( x- (xmin + xmax)/2)**2);
         return y
    # donnee initiale pour les 4 schémas.
    u[:,0,0] = f(x)
    u[:,0,1] = f(x)
    u[:,0,2] = f(x)
    # CFL
    r= mu*dt/dx**2;
    ###schéma explicite
    #iterations en temps
    for n in range(Nt-1):
        # on utilise le slicing plus efficace que les boucles
        u[1:-1,n+1,0] = r*u[:-2,n,0] + (1-2*r)* u[1:-1,n,0] + r*u[2:,n,0]
        #condition au bord x=xmin periodique
        u[0,n+1,0] = r*u[-1,n,0] +(1-2*r)* u[0,n,0] + r*u[1,n,0];
        #condition au bord x=xmax periodique
        u[-1,n+1,0] = r*u[-2,n,0] +(1-2*r)* u[-1,n,0] + r*u[0,n,0];
        
    ####schema implicite###
    #création de la matrice tridiagonale
    #on utilise le format sparse (creux)
    A = diags([-r,-r, 1+2*r, -r,-r],[-Nx+1,-1, 0, 1,Nx-1], shape=(Nx,Nx),format="csr")
    # A[0,-1]= -r et A[-1,0]= -r à cause des conditions limites périodiques
    
    # iterations en temps
    # a chaque itération on résout A U^{n+1} = U^n
    for n in range(Nt-1):
        u[:,n+1,1] = linalg.spsolve(A,u[:,n,1])
        
    ####schéma Crank-Nicolson####
    ####création des  matrices tridiagonales au format sparse
    A = diags([-r/2,-r/2, 1+r, -r/2,-r/2],[-Nx+1,-1,0,1,Nx-1],shape=(Nx,Nx),format="csr")
    # A[0,-1]= -r/2 et A[-1,0]= -r/2 à cause des conditions limites périodiques
    
    #
    B = diags([r/2,r/2, 1-r, r/2,r/2],[-Nx+1,-1,0,1,Nx-1],shape=(Nx,Nx), format="csr")
    #B[0,-1]= r/2 et B[-1,0]= r/2 à cause des conditions limites périodiques
    #iteration en temps
    #a chaque itération on résout A U^{n+1} = B U^n
    for n in range(Nt-1):
        u[:,n+1,2] = linalg.spsolve(A,B@u[:,n,2])

    
    # tracé des solutions à différents instants
    
    fig= plt.figure(figsize=(20, 10))
    #
    plt.subplot(131)
    plt.plot(x, u[:,0,0], label='condition initiale')
    plt.plot(x, u[:,int(T/(2*dt)),0], color='green', label=f'$t={T/2}$')
    plt.plot(x, u[:,-1,0], color='brown', label=f'$t={T}$')
    plt.xlabel('$x$')
    plt.ylabel('$u(.,t)$')
    plt.title('schéma différences finies explicite, CFL={:.2f}'.format(r))
    plt.legend();
    #
    plt.subplot(132)
    plt.plot(x, u[:,0,1], label='condition initiale')
    plt.plot(x, u[:,int(T/(2*dt)),1], color='green', label=f'$t={T/2}$')
    plt.plot(x, u[:,-1,1], color='brown', label=f'$t={T}$')
    plt.xlabel('$x$')
    plt.ylabel('$u(.,t)$')
    plt.title('schéma différences finies implicite, CFL={:.2f}'.format(r))
    plt.legend();
    #
    plt.subplot(133)
    plt.plot(x, u[:,0,2], label='condition initiale')
    plt.plot(x, u[:,int(T/(2*dt)),2], color='green', label=f'$t={T/2}$')
    plt.plot(x, u[:,-1,2], color='brown', label=f'$t={T}$')
    plt.xlabel('$x$')
    plt.ylabel('$u(.,t)$')
    plt.title('schéma différences finies Crank-Nicolson, CFL={:.2f}'.format(r))
    plt.legend();
    #
    return u

Résultats des différents schémas pour les paramètres μ = 0.5, T = 0.1, xmin = −1, xmax = 1 δx = 0.1 avec les pas de temps suivants δt = 0.005, δt = 0.01 et δt = 0.05.¶

In [3]:
u = diffusion(0.5,0.1, -1,1, 0.1, 0.005)
u = diffusion(0.5,0.1, -1,1, 0.1, 0.01)
u = diffusion(0.5,0.1, -1,1, 0.1, 0.05)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Pour le pas de temps $\delta t= 0.005, CFL=0.25$ on constate de bons résultats pour les 3 schémas. Pour $\delta t = 0.01, CFL=0.5$ le schéma explicite donne une solution irrégulière mais de valeur comparable aux deux autres schémas. Enfin pour $\delta t =0.05, CFL= 2.5$ le schéma explicite donne des résultats aberrants, tandis que le schéma implicite donne de bons résultats. Le schéma de Crank-Nicolson donne des résultats suspects près de zéro.

On change enfin μ en μ = −0.2. Que constatez-vous ?¶

In [4]:
u = diffusion(-0.2,0.1, -1,1, 0.1, 0.005)
No description has been provided for this image

Quand la diffusion est négative, tous les schémas donnent des résultats aberrants. Le problème mathématique est mal posé lorsque le coefficient de diffusion est négatif.¶

In [ ]: