Commit e0b4350f authored by Poulard Christine's avatar Poulard Christine :snake:
Browse files

Upload New File : main script, with sliders

parent bb423397
No related merge requests found
Showing with 220 additions and 0 deletions
+220 -0
######################################################
# Céline Berni, Christine Poulard, INRAE
# juin 2021
# Démo pour le cours HySL2 Sciences de l'Eau ENTPE 1èreA
######################################################
import numpy as np # Numpy for array computing
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider # widgets du module matplotlib !
from matplotlib.patches import Rectangle
from matplotlib.collections import LineCollection
## Calcul d'une ligne d'eau en fluvial
## pour un canal rectangulaire de grande largeur :
# calcul d'aval en amont
## Données d'entrée
# débit
Q = 50 # m3/s
# Coefficient de Strickler
K_ini = 60 # m**(1/3)/s
# pente
I = 0.0012
# largeur
b = 20 # m
# gravité
g = 9.81 # m/s²
## point de départ
x0 = 0 # m
h0 = 1.5 # m
## pas de calcul
delta_h_ini = 0.025 # m
# Fonctions (pour être éventuellement réutilisées dans un autre code)
## calcul de la hauteur normale
def hauteur_normale(Q, K, b, I):
hn = (Q / (K * b * np.sqrt(I))) ** (3 / 5)
return hn
## calcul de la hauteur critique
def hauteur_critique(Q, b):
hc = (Q ** 2 / (g * b ** 2)) ** (1 / 3)
return hc
def calcul_x_de_proche_en_proche(Q, K, b, I, h0, delta_h):
hn = hauteur_normale(Q, K, b, I)
hc = hauteur_critique(Q, b)
print(f"hauteur normale : {hn:.2f}")
print(f"hauteur critique : {hc:.2f}")
liste_h = None
liste_x = None
if hn < hc:
print('le régime uniforme doit être fluvial : calcul impossible.')
elif hn > h0:
print('la hauteur normale doit être inférieure à la hauteur imposée par la réservoir : calcul impossible.')
else:
## boucle de calcul pour calculer la hauteur d'eau par itération
# initialisation
hi = h0
xi = x0
liste_h = [h0]
liste_x = [x0]
while hi > hn:
dhi = min(delta_h, hi - hn) # pour ajuster le pas de calcul en dernière itération
hip1 = hi - dhi # hauteur d'eau au pas suivant i+1
hm = hi - dhi / 2 # hauteur d'eau moyenne sur le segment i i+1 considéré
dhdxi = I * (1 - (hn / hm) ** (10 / 3)) / (
1 - (hc / hm) ** 3) # pente de la ligne d'eau (hyp grande largeur)
xip1 = xi - dhi / dhdxi # abscisse du point de hauteur d'eau hip1
# itération iplus1
xi = xip1
hi = hip1
print(f"itération : xi={xi:.3f} et hi={hi:.3f}")
# stockage des valeurs de h et x dans un tableau
liste_h.append(hi)
liste_x.append(xi)
return liste_h, liste_x
def update_from_sliders(val):
global plot_fb, ligne_normale
# on prend comme valeur de K la valeur donnée par le slider, mais en convertissant en entier
K_slider = int(slider_K.val)
dh_slider = slider_dh.val
liste_h, liste_x = calcul_x_de_proche_en_proche(Q, K_slider, b, I, h0, dh_slider)
try:
plot_fb.remove()
ligne_normale.remove()
except:
pass
hn = hauteur_normale(Q, K_slider, b, I)
xy_normale = (min_de_x, - I * min_de_x + hn), (max_de_x, - I * max_de_x + hn)
lcol_normale = LineCollection([xy_normale], color=["red"], lw=2, ls="--", label=f"Zf+ hn (pour K={K_slider})")
ligne_normale = ax.add_collection(lcol_normale)
if liste_h is not None and liste_x is not None:
# on a pu calculer
x = np.asarray(liste_x)
h = np.asarray(liste_h)
# altitude du fond (on a besoin de tous les points pour le tracé)
zf = - I * x
# altitude de la surface libre
zsl = zf + h
# charge
H = zf + h + Q ** 2 / (2 * g * b ** 2 * h ** 2)
plot_zsl.set_data(x, zsl)
plot_H.set_data(x, H)
plot_fb = ax.fill_between(x, y1=zf, y2=zsl, color="lightblue", alpha=0.75)
fig.suptitle(f'profil en long, K={val:.2f}')
else:
# on n'a pas pu calculer
plot_zsl.set_data(x0, h0)
plot_H.set_data(x0, h0)
fig.suptitle(f'profil en long, K={val:.2f} ; calcul impossible')
if hn < h_critique:
# print('le régime uniforme doit être fluvial : calcul impossible.')
plot_fb = ax.fill_between([-1000, 0], y1=0, y2=h0, color="pink", alpha=0.75)
elif hn > h0:
# print('la hauteur normale doit être inférieure à la hauteur imposée par la réservoir : calcul impossible.')
plot_fb = ax.fill_between([-1400, 0], y1=[1400 * I, 0], y2=[1400 * I + h0, h0], color="pink", alpha=0.75)
# on retrace
plt.title(f'profil en long, K={K_slider}')
fig.canvas.draw_idle()
# CORPS DU PROGRAMME
# initialisations
liste_h, liste_x = calcul_x_de_proche_en_proche(Q, K_ini, b, I, h0, delta_h_ini)
## pour la visualisation : on transforme les listes en vecteur numpy, pour ensuite travailler directement en VECTEURS
x = np.asarray(liste_x)
h = np.asarray(liste_h)
# vecteur des altitudes du fond
zf = - I * x # définition avec un point par point de x alors que 2 points suffisent pour définir la droite
min_de_x = min(x)
max_de_x = max(x)
xy_zfond = (min_de_x, - I * min_de_x) , (max_de_x, - I *max_de_x)
lcol_zfond = LineCollection([xy_zfond], color=["sienna"], lw=2, label = 'fond du canal')
# vecteur des altitudes de la surface libre
zsl = zf + h
# vecteur des charges
H = zf + h + Q ** 2 / (2 * g * b ** 2 * h ** 2)
h_critique = hauteur_critique(Q, b)
# Takes list of lines, where each line is a sequence of coordinates
xy_critique =(min_de_x, - I * min_de_x + h_critique), (max_de_x, - I * max_de_x+ h_critique)
lcol_critique = LineCollection([xy_critique], color=["orange"], lw=2, ls=":", label="z_fond + hc (indépendant de K)")
h_normale = hauteur_normale(Q, K_ini, b, I)
xy_normale = (min_de_x, - I * min_de_x + h_normale), (max_de_x, - I * max_de_x+ h_normale)
lcol_normale = LineCollection([xy_normale], color=["red"], lw=2, ls="--", label = f"Zf+ hn (pour K={K_ini})")
## tracé du profil en long
# on crée une figure composée de 3 "vignettes" (subplots)
fig, (ax, ax_espace, ax_slider_K, ax_slider_dh) = plt.subplots(nrows=4, ncols=1,
gridspec_kw={'height_ratios': [10, 1, 1, 1]})
# on ajoute les courbes si possible dans l'ordre haut vers bas (cas de l'exercice)
ax.plot(x0, h0, 'v', label='cote aval imposée par le réservoir')
plot_H, = ax.plot(x, H, '--', marker='.', label='ligne de charge', color='green')
plot_zsl, = ax.plot(x, zsl, marker='.', label='surface libre', color='blue')
ligne_normale = ax.add_collection(lcol_normale)
# lignes fixes
ax.add_collection(lcol_critique)
ax.add_collection(lcol_zfond)
plot_fb = ax.fill_between(x, y1=zf, y2=zsl, color="lightblue", alpha=0.75)
rect = Rectangle((x0, -I * x0), 100, h0, color='darkblue')
ax.add_patch(rect)
ax.annotate("réservoir", (x0 + 10, h0 * 1.1), color="darkblue")
ax.set_xlabel('x (m)')
ax.set_ylabel('z (m)')
ax.legend()
ax_espace.xaxis.set_visible(False)
ax_espace.yaxis.set_visible(False)
for pos in ['right', 'top', 'bottom', 'left']:
ax_espace.spines[pos].set_visible(False)
ax_espace.spines[pos].set_visible(False)
# K
slider_K = Slider(
ax_slider_K, "Rugosité de Strickler", valmin=0.01, valmax=100, valfmt='%0.0f', valinit=K_ini, color="sienna")
slider_K.on_changed(update_from_sliders)
# dh
slider_dh = Slider(
ax_slider_dh, "Pas d'espace", valmin=0.001, valmax=0.5, valfmt='%0.3f', valinit=delta_h_ini, color="silver")
slider_dh.on_changed(update_from_sliders)
fig.suptitle(f'profil en long')
plt.show()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment