Dans le sol, la température vérifie une équation de diffusion de coefficient . Les données à la surface sont acquises régulièrement par des stations météorologiques. Les données pour Quimper sont disponibles à l’adresse suivante : https://nuage03.apps.education.fr/index.php/s/LgXjiwkxJxcrZmz. Le temps est donné en secondes depuis le 1er janvier 1970 à 00:00:00 UTC. La température est donnée en degrés Celsius. Les mesures sont effectuées toutes les heures.
On peut importer les données dans Python grâce aux instructions suivantes
import numpy as np
data = np.load("températures Quimper.npy")
t = data[:,0] # temps en secondes
Tz0 = data[:,1] # température à la surface (en z=0) en degrés Celsius1/ Tracer la température à la surface en fonction du temps.
import matplotlib.pyplot as plt
plt.figure("Température à la surface")
plt.plot(t, Tz0)
plt.show()On souhaite simuler la température dans le sol sur une profondeur de à l’aide de la méthode d’Euler explicite généralisée aux équations aux dérivées partielles.
La température à l’instant à la profondeur est notée . On choisit points de profondeur.
2/ Calculer le pas de profondeur . La condition de stabilité de la méthode d’Euler est-elle vérifiée ?
Le pas de profondeur est donné par .
La condition de stabilité est bien vérifiée.
3/ Exprimer en fonction de , , , , et grâce à la méthode d’Euler explicite.
L’équation de diffusion est de la forme .
D’où
Et donc
Pour la dérivée temporelle, on a
L’énoncé demande , on fait donc le changement d’indice :
4/ Compléter le code suivant implémentant la méthode d’Euler explicite pour simuler la température dans le sol.
Nx = ... # nombre de points de profondeur
L = 10 # longueur de la colonne de sol simulée (en m)
x = np.linspace(..., ..., ...) # liste des profondeurs des points simulés (en m)
Nt = len(t) # nombre d'instants simulés
T = np.zeros((Nt,Nx)) + Tz0[0] # initialisation de la matrice de température
dt = 3600 # pas de temps (en s)
dx = L/(Nx-1) # pas de profondeur (en m)
D = 1e-6 # coefficient de diffusion (en m^2/s)
for i in range(1, Nt):
T[i,0] = ... # condition à la surface
for j in range(1, Nx-1):
T[i,j] = ... # schéma d'Euler explicite
T[i,-1] = T[i,-2] # le dernier point n'a pas de voisin de droite, on ne peut pas appliquer
# le schéma d'Euler explicite, on reprend la température du point
# précédent (condition de Neumann)Tz0.Nx = 101
L = 10
x = np.linspace(0, L, Nx)
Nt = len(t)
T = np.zeros((Nt,Nx)) + Tz0[0]
dt = 3600
dx = L/(Nx-1)
D = 1e-6
for i in range(1, Nt):
T[i,0] = Tz0[i]
for j in range(1, Nx-1):
T[i,j] = D * dt/dx**2 * T[i-1,j+1] + D * dt/dx**2 * T[i-1,j-1] + (1 - 2*D * dt/dx**2) * T[i-1,j]
T[i,-1] = T[i,-2]5/ Tracer la température en fonction du temps pour des profondeurs de , , et .
T[:,j] pour accéder à toutes les lignes d’une colonne j et T[i,:] pour accéder à toutes les colonnes d’une ligne i.for j in [0, 1, 10, 100]:
plt.plot(t, T[:,j], label=f"z={x[j]:.2f} m")
plt.legend()
plt.show()6/ Écrire une suite d’instructions permettant de calculer à quelle profondeur minimale il faut enterrer une conduite d’eau pour qu’elle ne subisse pas le gel.
T. Si tous les éléments sont positifs, alors il ne gèle jamais à cette profondeur. Sinon, il gèle au moins une fois à cette profondeur.for j in range(Nx):
gèle = False
for i in range(Nt):
if T[i,j] < 0:
gèle = True # il gèle au moins une fois à la profondeur x[j]
break # inutile de continuer, on passe à la profondeur suivante
if not gèle: # on a trouvé une profondeur où il ne gèle jamais
break # on s'arrête, pas la peine d'étudier les profondeurs suivantes
print(x[j])7/ Compléter le code ci-dessous pour animer l’évolution du profil de température dans le sol. La fonction line.set_data prend les mêmes arguments que la fonction plot : les abscisses et les ordonnées des points à tracer.
import matplotlib.animation as animation
from datetime import datetime, timezone
def formateDate(t): # met en forme le temps pour afficher la date et l'heure
return datetime.fromtimestamp(t, tz=timezone.utc).strftime("%d/%m/%Y %H:%M")
fig, ax = plt.subplots()
plt.clf()
ax = fig.add_subplot(111)
line, = ax.plot(..., ...) # tracé du profil de température à l'instant initial t0
ax.set_ylim(..., ...) # on choisit les limites de l'axe des ordonnées pour que la courbe soit bien visible
ax.set_xlabel("Profondeur (m)")
ax.set_ylabel("Température (°C)")
title = ax.set_title("")
def animate(i):
line.set_data(..., ...) # tracé du profil de température à l'instant ti
title.set_text(formateDate(t[i]))
return line, title
ani = animation.FuncAnimation(fig, animate, frames=range(0,Nt,10), interval=10, blit=False, repeat=False)
plt.show()import matplotlib.animation as animation
from datetime import datetime, timezone
def formateDate(t): # met en forme le temps pour afficher la date et l'heure
return datetime.fromtimestamp(t, tz=timezone.utc).strftime("%d/%m/%Y %H:%M")
fig, ax = plt.subplots()
plt.clf()
ax = fig.add_subplot(111)
line, = ax.plot(x, T[0,:])
ax.set_ylim(np.min(T), np.max(T))
ax.set_xlabel("Profondeur (m)")
ax.set_ylabel("Température (°C)")
title = ax.set_title("")
def animate(i):
line.set_data(x, T[i,:])
title.set_text(formateDate(t[i]))
return line, title
ani = animation.FuncAnimation(fig, animate, frames=range(0,Nt,10), interval=10, blit=False, repeat=False)
plt.show()