diff --git a/ligne-eau-reservoir_vuCP.py b/ligne-eau-reservoir_vuCP.py new file mode 100644 index 0000000000000000000000000000000000000000..7ef5df852fef76917c09b8782337640b801335f8 --- /dev/null +++ b/ligne-eau-reservoir_vuCP.py @@ -0,0 +1,150 @@ +###################################################### +# Céline Berni, Christine Poulard, INRAE +# juin 2021 +# Démo pour le cours Sciences de l'Eau ENTPE 1èreA +###################################################### + +import numpy as np # Numpy for array computing + +import matplotlib.pyplot as plt +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 = 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 +dh = 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): + 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(dh,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 + +# CORPS DU PROGRAMME + +# initialisations + +liste_h, liste_x = calcul_x_de_proche_en_proche(Q, K, b, I, h0) + + + +h_critique = hauteur_critique(Q, b) + +## tracé du profil en long +# on crée une figure composée de 3 "vignettes" (subplots) +fig, ax = plt.subplots() + +# éléments toujours traçables +ax.plot(x0, h0, 'v', label='niveau imposé par le réservoir') + +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)') + +# la ligne d'eau peut être calculable ou pas selon la valeur de K +if liste_x is not None: + # tout est calculable est traçable avec comme abscisse le vecteur x + ## 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 + # vecteur des altitudes de la surface libre + zsl = zf + h + # vecteur des charges + H = zf + h + Q ** 2 / (2 * g * b ** 2 * h ** 2) + ax.plot(x, H, '--', marker='.', label='ligne de charge', color='green') + ax.plot(x,zsl,marker='.', label='surface libre', color='blue') + ax.plot(x, zf + hauteur_normale(Q, K, b, I), marker='None', ls='--', color='orange', + label="Zf+ hn (dépendant de K)") + ax.plot(x, zf + h_critique, marker='None', ls=':', color='red', label="Zf+ hc (indépendant de K)") + ax.fill_between(x, y1=zf,y2=zsl,color="lightblue", alpha=0.75) + ax.plot(x, zf, label='fond du canal', color='sienna') +else: + # la ligne d'eau et donc la ligne d'énergie ne sont pas calculables + # on peut tracer quelques infos en se passant du vecteur x + x_gauche = -1000 + x_droite = 0 + + h_normale = hauteur_normale(Q, K, b, I) + xy_normale = (x_gauche, - I * x_gauche + h_normale), (x_droite, - I * x_droite + h_normale) + lcol_normale = LineCollection([xy_normale], color=["red"], lw=2, ls="--", label="Zf+ hn (dépendant de K)") + ax.add_collection(lcol_normale) + + xy_critique = (x_gauche, - I * x_gauche + h_critique), (x_droite, - I * x_droite + h_critique) + lcol_critique = LineCollection([xy_critique], color=["orange"], lw=2, ls=":", + label="z_fond + hc (indépendant de K)") + ax.add_collection(lcol_critique) + + xy_zfond = (x_gauche, - I * x_gauche), (x_droite, - I * x_droite) + lcol_zfond = LineCollection([xy_zfond], color=["sienna"], lw=2, label='fond du canal') + ax.add_collection(lcol_zfond) + ax.set_xlim(x_gauche, x_droite + 50) + +ax.legend() + +plt.show()