Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Conception de ressaut hydraulique

Run this notebook in your web browser: Open in marimo

Le lien ouvre hydraulic-jump.py en tant que portable interactif marimo qui fonctionne entièrement dans votre navigateur Web, sans rien installer.

  1. Attendez un moment jusqu’à ce que Python ait chargé dans le navigateur (cela ne prend plus que le premier départ).

  2. Cliquez sur le bouton d’exécution jaune (en bas à droite) pour exécuter toutes les cellules.

  3. Modifier et ré-exécuter n’importe quelle cellule de code pour expérimenter: marimo met automatiquement à jour toutes les cellules qui en dépendent.

  4. Vos modifications restent dans l’onglet du navigateur seulement. Pour les conserver, enregistrez le carnet dans le menu (-) > Exporter... > Python.

Cet exercice oriente à Clyde Dam, sur la rivière Clutha / Mata-Au dans le centre d’Otago, est le plus grand barrage de gravité en béton de Nouvelle-Zélande: 490 m de large, jusqu’à 60 m de haut au-dessus du vieux lit de rivière, et la retenue du lac Dunstan. Son déversoir fermé a quatre portes radiales, chacune de 15 m de haut et 10 m de large, conçues pour parcourir un débit de 3200 m3^3/s (0,2% AEP) à un niveau de lac de 195,1 m. L’eau passant par le déversoir descend une goulotte sur la face du barrage. Le débit d’énergie élevée à l’orteil de ce parachute doit être dissipé dans un bassin de dissipation, de sorte que le lit de la rivière en aval ne soit pas escarpé.

Défi de l’élève : tailler la géométrie du bassin pour que le ressaut hydraulique se forme à l’intérieur du bassin et y soit conservé, et éviter ainsi l’affouillement en aval du barrage.

Structure du modèle de calcul

Aperçu général

Qui fait le travail C’est le cas. *** L’écoulement arrivant au bassin : décharge unitaire, tête d’énergie à l’orteil et profondeur d’eau aval. II= Conception d’un bassin de dissipation et d’un ressaut hydraulique=** étudiant - le flux de travail est donné, les équations de ressaut hydraulique doivent être entrées=

Détails

La partie I établit les quantités sur lesquelles le ressaut, et donc le bassin, est conçu: la décharge QQ et la décharge de l’unité qq, la tête d’énergie H0H_0 au-dessus du bassin un-sunk inversé, et la profondeur d’eau aval htwh_{tw} obtenue de l’équation Manning.

La partie II contient trois fonctions courtes, marquées Task 1 à Task 3. Chacun est une seule équation de la conférence. Les chiffres qui les entourent, c’est-à-dire la recherche de racine, la recherche sur la profondeur du bassin et les placettes, sont donnés, de sorte qu’une équation incorrecte produit un nombre incorrect plutôt qu’une trace de retour. L’équation au centre de l’exercice est l’équation de profondeur séquentielle (Bélanger) de la tâche 2; les deux autres établissent l’état auquel elle est appliquée et le critère par lequel le résultat est jugé. Une fois la partie II remplie, vous devriez pouvoir :

  • exprimer l’énergie, la continuité et les relations d’élan qui fixent un ressaut hydraulique comme code;

  • déterminer si un niveau aval donné conserve un ressaut dans un bassin ou le balaye en aval;

  • déterminer la profondeur, la longueur et la protection d’un bassin contre ces relations.

Notation

Les profondeurs sont indiquées hh et les têtes HH, dans la conférence et ici aussi. Le taux de rétention est indiqué rtr_{\mathrm{t}} plutôt que le ε\varepsilon de l’exemple travaillé allemand à partir duquel ce workflow est adapté, car ε\varepsilon indique le taux de dissipation turbulente dans la conférence.

symbolmeaningunit
QQspillway design flowm3^3/s
wwwidth of the stilling basinm
wtww_{tw}tailwater river widthm
qqdischarge per unit width, q=Q/wq = Q/wm2^2/s
H0H_0energy head above the un-sunk basin invertm
db\mathbf{d_b}depth of the basin floor below the downstream bedm
HHenergy head above the basin floor, H=H0+dbH = H_0 + \mathbf{d_b}m
h1h_1, v1v_1, Fr1Fr_1depth, velocity and Froude number at the basin entrance (supercritical)m, m/s, --
h2h_2conjugate (sequent) depth of the jumpm
htwh_{tw}tailwater depth in the downstream reachm
nMn_MManning roughness coefficient of the downstream reachs/m1/3^{1/3}
rtr_{\mathrm{t}}retention ratio, (htw+db)/h2(h_{tw} + \mathbf{d_b})/h_2--
S0,twS_{0,tw}longitudinal bed slope of the downstream reach--
ΔH\Delta Hhead loss across the jumpm
flf_{l}Peterka basin-length multiplier, read from Fr1Fr_1--
lbl_b, lsl_sbasin length and scour-protection lengthm

La cellule suivante importe les paquets Python et les couleurs utilisées pour les chiffres. Ces cellules servent au fonctionnement du modèle de calcul et ne contiennent aucun contenu d’apprentissage.

import math
from dataclasses import dataclass

import matplotlib.patheffects as pe
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import brentq

# Physical constants used throughout.
G = 9.81  # gravitational acceleration [m/s2]

# The lecture palette, so that figures and slides read as one piece.
NAVY, BLUE, CYAN, GREEN, WARN, GREY = (
    "#0C0C48", "#00467F", "#00CAEF", "#167D61", "#C74B2A", "#4A4A4C",
)

plt.rcParams.update({
    "figure.figsize": (8.4, 4.2),
    "figure.dpi": 110,
    "axes.spines.top": False,
    "axes.spines.right": False,
    "axes.titleweight": "bold",
    "axes.labelcolor": NAVY,
    "axes.edgecolor": NAVY,
    "text.color": NAVY,
    "xtick.color": NAVY,
    "ytick.color": NAVY,
    "font.size": 9,
})

Partie I : conditions limites pour la conception du ressaut hydraulique

Tout dans cette partie est donné. Exécutez les cellules et notez les quantités transmises à la partie II. Aucun calcul hydraulique n’est effectué ici.

Note: only the discharge, the associated lake level and the gate dimensions are published figures; the remainder are stated assumptions. The real structure is not this simple. A gate-controlled sluice rated at 1500 m3^3/s adjoins the spillway, and the two together pass the largest anticipated flood of 6820 m3^3/s. The energy dissipation at the toe was developed on physical models by the Ministry of Works and Development rather than from a closed-form calculation. This exercise therefore represents the first step that engineers typically complete before a detailed design study with physical or numerical models; it is not a substitute for such a study.

quantityvalueremark
QQ, spillway design flow3200 m3^3/spublished, at a lake level of 195.1 m
ww, width of the chute and basin40 mfour 10 m gate bays, idealised as one rectangular chute with the piers ignored
H0H_0, energy head above the un-sunk basin invert50.00 massumed: the design flood level stands approximately 60 m above the riverbed, of which some 10 m is taken as lost down the chute
wtww_{tw}, nMn_M, S0,twS_{0,tw} of the Clutha downstream of the dam60 m, 0.045 s/m1/3^{1/3}, 0.0006assumed

Dans la pratique néo-zélandaise, les inondations de conception de bassins versants sont citées comme une probabilité de dépassement annuel, de sorte que l’inondation de 100 ans est l’événement AEP de 1% et l’inondation de 500 ans citée pour Clyde est l’événement AEP de 0,2%; l’intervalle moyen de récurrence (ARI) plus ancien indique la même chose. Toutefois, un déversoir de barrage n’est pas conçu pour un bassin versant AEP du tout : sous le NZSOLD * Lignes directrices pour la sécurité du barrage de Nouvelle-Zélande* l’inondation de la conception de l’écoulement découle de la classification des impacts potentiels du barrage, et pour un barrage à forte conséquence, elle s’étend jusqu’à la crue maximale probable.

La cellule suivante définit ces conditions hydrologiques, hydrauliques et géométriques.

# --- the design discharge ----------------------------------------------------
Q_design = 3200.0  # m3/s   Clyde Dam spillway design flow at lake level 195.1 m
                   #        (published; the 500-year, 0.2% AEP flood)

# --- the chute toe and the stilling basin below it ---------------------------
w_chute = 40.0     # m      four 10 m gate bays, idealised as one rectangle
H0 = 50.00         # m      energy head above the un-sunk basin invert (assumed)

# --- the Clutha River below the dam (assumed) --------------------------------
n_manning = 0.045   # s/m^(1/3)  Manning roughness of the downstream reach
slope = 6.0e-4      # -          bed slope of the downstream reach
w_tw = 60.0         # m          width of the downstream reach (rectangular idealisation)
h_tw = 19.060       # m          tailwater depth of that reach in uniform flow

print(f"spillway design flow Q  = {Q_design:7.1f} m3/s")
print(f"chute and basin width w = {w_chute:7.2f} m")
print(f"head at the invert   H0 = {H0:7.2f} m")
spillway design flow Q  =  3200.0 m3/s
chute and basin width w =   40.00 m
head at the invert   H0 =   50.00 m

Calcul des limites

Décharge unitaire

Pour le calcul du ressaut hydraulique, le débit par mètre de largeur est nécessaire:

q=Qwq = \frac{Q}{w}

Le parachute délivre ce flux supercritiquement, qui est la condition pour un ressaut pour se former. La profondeur critique imprimée ci-dessous est la limite supérieure sur la profondeur d’entrée h1h_1, et la partie II l’utilise comme support lors de la résolution de l’équation d’énergie.

q_unit = Q_design / w_chute
h_crit = (q_unit**2 / G)**(1 / 3)

print(f"unit discharge   q = Q / w   = {q_unit:7.3f} m2/s")
print(f"critical depth   h_c         = {h_crit:7.3f} m")
print(f"critical velocity            = {q_unit / h_crit:7.3f} m/s")
unit discharge   q = Q / w   =  80.000 m2/s
critical depth   h_c         =   8.673 m
critical velocity            =   9.224 m/s

Profondeur d’eau aval htwh_{tw}

La profondeur dans la portée en aval détermine si le ressaut est retenu ou balayé, et il est déterminé par la portée elle-même plutôt que par le déversoir. Pour un canal rectangulaire en flux uniforme, l’équation Manning donne

Q=1nM A R2/3 S0,tw,A=wtw htw,R=wtw htwwtw+2 htwQ = \frac{1}{n_M}\,A\,R^{2/3}\,\sqrt{S_{0,tw}}, \qquad A = w_{tw}\,h_{tw}, \qquad R = \frac{w_{tw}\,h_{tw}}{w_{tw} + 2\,h_{tw}}

Évaluer ceci pour la portée ci-dessus donne htw=19.060h_{tw} = 19.060 m, qui est affecté directement dans la cellule ci-dessous et utilisé à partir de là.

Note: Les canaux naturels ne sont pas rectangulaires, et htwh_{tw} entre directement le taux de rétention. En pratique, la courbe de tarage aval est obtenue à partir d’un gabarit, d’un modèle numérique ou de données sur le terrain, et une gamme de niveaux aval est testée plutôt qu’une seule valeur.

La cellule ci-dessous imprime également la profondeur critique de la portée en aval, car un ressaut peut se terminer dans l’eau aval seulement alors que cette portée est sous-critique.

h_crit_tw = ((Q_design / w_tw)**2 / G)**(1 / 3)

print(f"tailwater depth h_tw = {h_tw:.3f} m   (given, from the reach above)")
print(f"critical depth of the reach = {h_crit_tw:.3f} m"
      f"   -> {'subcritical' if h_tw > h_crit_tw else 'SUPERCRITICAL'}")
tailwater depth h_tw = 19.060 m   (given, from the reach above)
critical depth of the reach = 6.619 m   -> subcritical

Définir les structures de données et les valeurs par défaut

Le bloc de code suivant construit les structures de données requises et définit les valeurs par défaut pour la partie principale II.

@dataclass(frozen=True)
class DesignData:
    Q: float       # spillway design flow [m3/s]
    q: float       # discharge per unit width [m2/s]
    H0: float      # energy head above the un-sunk basin invert [m]
    h_tw: float    # tailwater depth [m]
    w: float       # width the basin has to cover [m]


DESIGN = DesignData(
    Q=Q_design,
    q=q_unit,
    H0=H0,
    h_tw=h_tw,
    w=w_chute,
)

print(f"Q      = {DESIGN.Q:8.1f} m3/s   spillway design flow")
print(f"q      = {DESIGN.q:8.3f} m2/s   unit discharge")
print(f"H0     = {DESIGN.H0:8.2f} m      energy head above the un-sunk invert")
print(f"h_tw   = {DESIGN.h_tw:8.3f} m      tailwater depth")
print(f"w      = {DESIGN.w:8.2f} m      width the basin has to cover")
Q      =   3200.0 m3/s   spillway design flow
q      =   80.000 m2/s   unit discharge
H0     =    50.00 m      energy head above the un-sunk invert
h_tw   =   19.060 m      tailwater depth
w      =    40.00 m      width the basin has to cover

Partie II : conception du bassin et du ressaut hydraulique

L’équation de profondeur séquentielle (Bélanger)

Pour un canal horizontal et rectangulaire, la position et la taille du ressaut découlent de la conservation de l’élan, des forces de pression hydrostatique et de la continuité. Étant donné que la force spécifique est égale en amont (1) et en aval (2) du ressaut, c’est-à-dire M1=M2M_1 = M_2 avec M=q2/(g h)+h2/2M = q^2/(g\,h) + h^2/2, le rapport de profondeur est calculé par l’équation de profondeur séquentielle de Bélanger:

  h2h1=12(1+8 Fr12−1)  \boxed{\;\frac{h_2}{h_1} = \frac{1}{2}\left(\sqrt{1 + 8\,Fr_1^{2}} - 1\right)\;}

Notamment, h1h_1 et h2h_2 sont les profondeurs séquence (conjuguant). Chaque quantité subséquente de cet exercice est obtenue à partir de h2h_2: le taux de rétention qui indique si le ressaut reste dans le bassin, la longueur du bassin, et la longueur requise de protection de l’affouillement en aval.

Problème de conception

La position du ressaut n’est pas fixée par le déversoir. Il est contrôlé par la profondeur tailwater: un ressaut forme où la profondeur en aval correspond à la profondeur conjuguée h2h_2 appartenant à l’état supercritique entrant. Lorsque l’eau de la queue est trop peu profonde, le ressaut est ** balayé** sur un lit de rivière en aval non protégé; où il est trop profond, le ressaut est drown et dissipe moins.

La liberté de conception unique est la profondeur basin db\mathbf{d_b}, par laquelle le plancher du bassin est placé sous le lit de rivière en aval. Augmenter db\mathbf{d_b} agit dans deux directions opposées :

  1. il augmente la tête d’énergie H=H0+dbH = H_0 + \mathbf{d_b} au-dessus du plancher, de sorte que le flux d’entrée est plus rapide et plus faible, ce qui élève Fr1Fr_1 et donc h2h_2;

  2. il augmente la profondeur disponible sur le sol, à savoir htw+dbh_{tw} + \mathbf{d_b}.

Une conception acceptable est une profondeur de bassin à laquelle les deux objectifs techniques sont satisfaits simultanément:

4.5≤Fr1<9.0and1.05≤rt=htw+dbh2≤1.154.5 \le Fr_1 < 9.0 \qquad\text{and}\qquad 1.05 \le r_{\mathrm{t}} = \frac{h_{tw} + \mathbf{d_b}}{h_2} \le 1.15

Le premier objectif d’ingénierie est le ressaut stationnaire** qui entraîne une perte de tête de 45 % à 70 %, et aucune poussée oscillante pour fatiguer la structure. Le deuxième objectif d’ingénierie exige que le bassin conserve un peu plus d’eau que le ressaut nécessaire, de sorte que le ressaut soit maintenu avec une petite marge sans être noyé.

Le flux de travail

Les étapes se déroulent dans l’ordre de la table, et chacune est donnée ou l’une des trois tâches:

contenthint
choose a trial basin depth db\mathbf{d_b}here: 1.0 m (given)
h1h_1 and v1v_1 from the energy equation at the entrancegiven
Fr1=v1/g h1Fr_1 = v_1/\sqrt{g\,h_1}Task 1
is 4.5≤Fr1<9.04.5 \le Fr_1 < 9.0? if not, adjust db\mathbf{d_b}given
the conjugate depth h2h_2 from the Bélanger equationTask 2
is 1.05≤rt≤1.151.05 \le r_{\mathrm{t}} \le 1.15? if not, adjust db\mathbf{d_b}Task 3 + given
basin length lbl_b and scour-protection length lsl_sgiven
head loss ΔH\Delta Hgiven

Les trois tâches

Chaque tâche est une équation de la conférence.

Remplacez la ligne raise NotImplementedError(...) par une déclaration return.

Les noms des fonctions et leurs arguments ne doivent pas être modifiés, car le workflow ci-dessous les appelle.

Important: Après chaque tâche, exécutez la cellule ** auto-vérification**. Il marque chaque fonction [OK] ou [XX] contre les valeurs de la conférence.

Donnée : tête d’énergie au-dessus du plancher du bassin

Négligeant la vitesse d’approche, la tête d’énergie disponible au-dessus du plancher du bassin est H=H0+dbH = H_0 + \mathbf{d_b}. À l’entrée du bassin, c’est-à-dire la section 1, la tête est divisée entre la profondeur et la tête de vitesse. Avec continuité v=q/hv = q/h pour une section rectangulaire,

H=h+v22g=h+q22g h2H = h + \frac{v^2}{2g} = h + \frac{q^2}{2g\,h^2}

Le côté droit est codé ci-dessous en fonction de hh et qq. Lisez-le, parce que l’état d’entrée de chaque profondeur du bassin d’essai vient de lui: le solveur donné entry_depth plus bas sélectionne la racine peu profonde et supercritique de energy_head(h, q) == H, qui est la branche livrée par le parachute.

def energy_head(h, q, g=G):
    '''
    Given: specific energy head of a rectangular section [m].

    Parameters
    ----------
    h : water depth [m]
    q : discharge per unit width [m2/s]

    Returns
    -------
    the energy head h + q^2 / (2 g h^2) [m]
    '''
    return h + q**2 / (2 * g * h**2)

Tâche 1 : nombre de Froude

Le nombre de Froude compare la vitesse d’écoulement avec la vitesse des vagues d’eau peu profonde c=ghc = \sqrt{g h}:

Fr=vg hFr = \frac{v}{\sqrt{g\,h}}

Rappelons que Fr>1Fr > 1 indique un flux supercritique et Fr<1Fr < 1 subcritic. Cette étape du workflow ne calcule que la valeur du nombre de Froude (ici: Fr1Fr_1) pour la comparaison ultérieure avec la fenêtre de ressaut permanent:

def froude_number(v, h, g=G):
    '''
    Task 1: Froude number of a rectangular section [-].

    Parameters
    ----------
    v : depth-averaged velocity [m/s]
    h : water depth [m]
    '''
    # >>> YOUR CODE HERE
    raise NotImplementedError("Task 1: return the Froude number")

Tâche 2 : équation de profondeur de séquence (Bélanger)

C’est l’équation centrale de l’exercice. Mettre en oeuvre le ratio de profondeur aux sections 2 (h2h_2) et 1 (h1h_1):

h2h1=12(1+8 Fr12−1)\frac{h_2}{h_1} = \frac{1}{2}\left(\sqrt{1 + 8\,Fr_1^{2}} - 1\right)

Note: Cette équation ne décrit ni le rouleau entre les sections transversales ni la structure interne du ressaut. Tout ce que la conception exige après ce point, c’est-à-dire le taux de rétention, la longueur du bassin et la longueur de protection de l’affouillement, suit l’équation h2h_2 séquent.

def conjugate_depth(h1, Fr1):
    '''
    Task 2: conjugate (sequent) depth downstream of the jump [m].

    Parameters
    ----------
    h1  : supercritical depth upstream of the jump [m]
    Fr1 : Froude number at section 1 [-]
    '''
    # >>> YOUR CODE HERE
    raise NotImplementedError("Task 2: return the conjugate depth h2")

Tâche 3 : taux de rétention

La profondeur d’eau sur le plancher du bassin est la profondeur d’eau aval plus la profondeur du bassin. La comparaison avec la profondeur que le ressaut exige conduit au taux de rétention :

rt=htw+dbh2r_{\mathrm{t}} = \frac{h_{tw} + \mathbf{d_b}}{h_2}

rt<1r_{\mathrm{t}} < 1 signifie que le bassin ne peut fournir la profondeur conjuguée et le ressaut est balayé en aval; rtr_{\mathrm{t}} bien au-dessus de 1 signifie que le ressaut est noyé. La vérification de rétention demande 1.05≤rt≤1.151.05 \le r_{\mathrm{t}} \le 1.15.

def retention_ratio(h_tw, d_b, h2):
    '''
    Task 3: retention ratio of the basin [-].

    Parameters
    ----------
    h_tw : tailwater depth in the downstream reach [m]
    d_b  : depth of the basin floor below the downstream bed [m]
    h2   : conjugate depth required by the jump [m]
    '''
    # >>> YOUR CODE HERE
    raise NotImplementedError("Task 3: return the retention ratio")

Donnée : longueurs du bassin et de la protection contre l’affouillement

Pour calculer empiriquement la longueur requise du bassin de dissipation lbl_b, Peterka (USBR Engineering Monographie 25) a mesuré la longueur du ressaut dans six flumes d’essai et l’a tracée contre le nombre de Froude comme un compteur prêt (sa figure 7, ressaut libre sur un tablier horizontal). La courbe donne un facteur (ici: flf_l), qui est lu au nombre de Froude de la section transversale 1 (Fr1Fr_1) et multiplié par la profondeur conjuguée (h2h_2):

Fr1Fr_12.4456 to 1114
flf_{l}4.85.86.06.136.0

La fonction peterka_f ci-dessous lit ce tableau (aucune intervention nécessaire) et retourne flf_{l}. Il ne correspond à rien : np.interp interpole linéairement entre les points tabulés d’une courbe mesurée, et cette courbe n’est pas une ligne droite.

def peterka_f(Fr1):
    '''Given: basin-length multiplier after Peterka (USBR EM 25), interpolated [-].'''
    knots_Fr = [2.4, 4.0, 5.0, 6.0, 11.0, 14.0]
    knots_f = [4.8, 5.8, 6.0, 6.13, 6.13, 6.0]
    return float(np.interp(Fr1, knots_Fr, knots_f))


print(f"f_l at Fr1 = 5.0 : {peterka_f(5.0):.3f}")
print(f"f_l at Fr1 = 8.0 : {peterka_f(8.0):.3f}")
f_l at Fr1 = 5.0 : 6.000
f_l at Fr1 = 8.0 : 6.130

Ensuite, calculez la longueur de bassin requise lbl_b pour contenir le ressaut avec la fonction peterka_f. Comme le débit qui quitte le ressaut (et le seuil de l’extrémité du bassin) est encore turbulent, le lit de la rivière immédiatement en aval du bassin doit être blindé sur une longueur lsl_s:

lb=fl(Fr1)h2,ls=3.5lbl_b = f_{l}(Fr_1) h_2, \qquad l_s = 3.5 l_b

Les deux longueurs sont codées ci-dessous, basin_lengths appelant peterka_f pour le multiplicateur.

def basin_lengths(h2, Fr1):
    '''
    Given: basin length and scour-protection length [m].

    Parameters
    ----------
    h2  : conjugate depth downstream of the jump [m]
    Fr1 : Froude number at section 1, which selects the multiplier [-]

    Returns
    -------
    (l_b, l_s) : basin length and scour-protection length [m]
    '''
    l_b = peterka_f(Fr1) * h2
    return l_b, 3.5 * l_b

Note: Pour un ressaut régulier, lbl_b est proche de la règle du pouce lj≈l_j \approx 6 h2h_2, et les cellules dans ce cahier impriment à la fois ljl_j et lbl_b. Pourtant, d’autres manuels de conception donneraient différents facteurs, ce qui est l’une des raisons pour lesquelles une conception détaillée avec un modèle physique ou numérique est critique.

Autocontrôle

Exécutez cette cellule après chaque tâche. Les valeurs de référence sont les résultats approximatifs présentés dans les diapositives de lecture, donc [OK] sur chaque ligne indique que les trois tâches reproduisent les diapositives.

CHECKS = [
    ("Task 1  froude_number(31.623, 2.5298)",
     lambda: froude_number(31.623, 2.5298), (6.348,), "-"),
    ("Task 2  conjugate_depth(2.5298, 6.348)",
     lambda: conjugate_depth(2.5298, 6.348), (21.481,), "m"),
    ("Task 3  retention_ratio(19.060, 3.5, 21.481)",
     lambda: retention_ratio(19.060, 3.5, 21.481), (1.050,), "-"),
]


def check_tasks(tolerance=5e-3, verbose=True):
    '''Compare each task against the worked values from the lecture.'''
    passed = 0
    for label, call, expected, unit in CHECKS:
        try:
            value = call()
        except NotImplementedError:
            if verbose:
                print(f"[ ] {label:<46} not implemented yet")
            continue
        got = value if isinstance(value, tuple) else (value,)
        ok = (len(got) == len(expected) and
              all(abs(g - e) <= tolerance * max(1.0, abs(e))
                  for g, e in zip(got, expected)))
        passed += ok
        if verbose:
            mark = "OK" if ok else "XX"
            shown = ", ".join(f"{g:.3f}" for g in got)
            wanted = ", ".join(f"{e:.3f}" for e in expected)
            print(f"[{mark}] {label:<46} {shown:>19} {unit:<3}"
                  f" (expected {wanted})")
    if verbose:
        print("-" * 78)
        print(f"{passed} of {len(CHECKS)} tasks correct.")
    return passed == len(CHECKS)


TASKS_DONE = check_tasks()
[ ] Task 1  froude_number(31.623, 2.5298)          not implemented yet
[ ] Task 2  conjugate_depth(2.5298, 6.348)         not implemented yet
[ ] Task 3  retention_ratio(19.060, 3.5, 21.481)   not implemented yet
------------------------------------------------------------------------------
0 of 3 tasks correct.

Mise en œuvre du flux de travail : la recherche sur la profondeur du bassin

Les autres calculs de la partie II sont donnés (les réponses aux questions de suivi ne le sont pas).

La fonction basin_state évalue une profondeur de bassin d’essai de bout en bout et appelle les fonctions écrites ci-dessus; search_basin_depth choisit les profondeurs d’essai, ajustant db\mathbf{d_b} par bisection jusqu’à ce qu’elle ait trouvé la profondeur shallowest à laquelle les deux objectifs d’ingénierie sont atteints. La logique de bisection doit être lue avant l’exécution de la cellule.

Fr1Fr_1 et rtr_{\mathrm{t}} augmentent avec db\mathbf{d_b}, ce qui permet d’utiliser un seul support pour les deux tests: trop peu profond un bassin ne fournit pas la profondeur demande le ressaut et balaye en aval, mais trop profond un bassin fournit plus que le ressaut exige et noie. Chaque procès échoué indique donc la moitié de la fourchette à conserver et, en l’espèce, la recherche échoue dans les deux sens avant la convergence.

Observer: Le processus de recherche commence par un premier essai de db\mathbf{d_b} = 1,0 m. Ce procès satisfait la fenêtre de ressaut stable, Fr1Fr_1 = 6.1 étant déjà un ressaut stable, et échoue la fenêtre de rétention, le ressaut étant balayé. La bisection approfondit ensuite le bassin à 10,5 m, ce qui noie le ressaut, et remonte. Une profondeur acceptable n’est pas la fin de la recherche : parce qu’un bassin plus profond coûte des travaux d’excavation pour aucun bénéfice, le support continue de fermer jusqu’à ce que la profondeur acceptable challowest soit trouvée, et cette valeur est arrondie à 0,25 m pour un chiffre constructible. Le résultat dépend toujours de la largeur du support, de sorte qu’un rapport doit indiquer quel support l’a produit.

FR_WINDOW = (4.5, 9.0)     # steady-jump range
RT_WINDOW = (1.05, 1.15)   # retention window


@dataclass(frozen=True)
class BasinState:
    d_b: float     # trial basin depth [m]
    H: float       # energy head above the basin floor [m]
    h1: float      # supercritical entry depth [m]
    v1: float      # entry velocity [m/s]
    Fr1: float     # entry Froude number [-]
    h2: float      # conjugate depth [m]
    Rt: float      # retention ratio [-]

    @property
    def fr_ok(self):
        return FR_WINDOW[0] <= self.Fr1 < FR_WINDOW[1]

    @property
    def rt_ok(self):
        return RT_WINDOW[0] <= self.Rt <= RT_WINDOW[1]


def critical_depth(q, g=G):
    '''Critical depth of a rectangular section [m]; the bracket for the entry depth.'''
    return (q**2 / g)**(1 / 3)


def entry_depth(H, q):
    '''
    The shallow, supercritical root of energy_head(h, q) = H [m].

    Both roots satisfy the energy equation. The supercritical one lies below the
    critical depth, and it is the branch the spillway delivers, so the bracket is
    closed at the critical depth.
    '''
    return brentq(lambda h: energy_head(h, q) - H, 1e-4, critical_depth(q))


def basin_state(d_b, design=None):
    '''The workflow evaluated for one trial basin depth d_b.'''
    design = design or DESIGN
    H = design.H0 + d_b                          # head above the basin floor
    h1 = entry_depth(H, design.q)                # supercritical root
    v1 = design.q / h1                           # continuity
    Fr1 = froude_number(v1, h1)                  # Task 1
    h2 = conjugate_depth(h1, Fr1)                # Task 2
    Rt = retention_ratio(design.h_tw, d_b, h2)   # Task 3
    return BasinState(d_b=d_b, H=H, h1=h1, v1=v1, Fr1=Fr1, h2=h2, Rt=Rt)
def search_basin_depth(db_start=1.0, db_min=0.0, db_max=20.0, max_iter=25,
                       tol=0.005, grid=0.25, verbose=True):
    '''
    Bisection on the basin depth d_b for the SHALLOWEST depth at which both
    engineering objectives are met, rounded up to the next `grid` metres.

    Returns the accepted BasinState and the full iteration history.
    '''
    d_b = db_start
    history = []
    if verbose:
        print(f"{'iter':>4}{'d_b [m]':>9}{'Fr1':>8}{'h1 [m]':>9}{'h2 [m]':>9}"
              f"{'Rt':>8}   verdict")
        print("-" * 66)

    for i in range(1, max_iter + 1):
        state = basin_state(d_b)
        history.append(state)
        if verbose:
            flags = []
            if not state.fr_ok:
                flags.append("Fr1 low" if state.Fr1 < FR_WINDOW[0] else "Fr1 high")
            if not state.rt_ok:
                flags.append("swept out" if state.Rt < RT_WINDOW[0] else "drowned")
            print(f"{i:>4}{state.d_b:>9.3f}{state.Fr1:>8.2f}{state.h1:>9.4f}"
                  f"{state.h2:>9.4f}{state.Rt:>8.3f}   "
                  f"{'accepted' if not flags else ', '.join(flags)}")

        # A deeper basin raises H, so the entry flow is shallower and faster: Fr1 and Rt increase monotonically with d_b. One bracket therefore serves both criteria, and each verdict says which way to move: a jump that is too gentle or swept out wants a deeper basin, one that is too fierce or drowned wants a shallower one. An acceptable trial is not the end of the search either, because a deeper basin than necessary costs excavation for no benefit, so it too narrows the bracket from above.
        if not state.fr_ok:
            if state.Fr1 < FR_WINDOW[0]:
                db_min = d_b  # jump too gentle: deepen the basin
            else:
                db_max = d_b  # jump too fierce: raise the floor
        elif state.Rt < RT_WINDOW[0]:
            db_min = d_b      # swept out: deeper basin
        else:
            db_max = d_b      # accepted or drowned: try a shallower one

        if db_max - db_min < tol:
            break
        d_b = 0.5 * (db_min + db_max)
    else:
        raise RuntimeError("no acceptable basin depth found in the search range")

    # db_max is the shallowest depth known to work; round it up to a buildable one.
    d_b = math.ceil(db_max / grid) * grid
    state = basin_state(d_b)
    history.append(state)
    if not (state.fr_ok and state.rt_ok):
        raise RuntimeError(f"rounding up to {d_b:.2f} m no longer meets the engineering objectives")
    if verbose:
        print(f"{'->':>4}{state.d_b:>9.3f}{state.Fr1:>8.2f}{state.h1:>9.4f}"
              f"{state.h2:>9.4f}{state.Rt:>8.3f}   shallowest, rounded up")
    return state, history


if TASKS_DONE:
    DESIGN_STATE, HISTORY = search_basin_depth()
    print(f"\naccepted basin depth d_b = {DESIGN_STATE.d_b:.3f} m")
else:
    DESIGN_STATE, HISTORY = None, []
    print("Complete Tasks 1 to 3, then re-run this cell.")
Complete Tasks 1 to 3, then re-run this cell.

Perte de la tête à travers le ressaut

La perte de tête quantifie le travail du bassin. Ce n’est pas une tâche: la décision de conception a déjà été prise par les deux objectifs d’ingénierie ci-dessus. La perte est calculée ici parce que c’est la raison pour laquelle le bassin existe. La combinaison de l’équation d’énergie avec la relation conjuguée-profondeur sur un lit horizontal donne la perte de tête sous forme fermée,

ΔH=H1−H2=(h2−h1)34h1h2>0\Delta H = H_1 - H_2 = \frac{(h_2 - h_1)^3}{4 h_1 h_2} > 0

ΔH\Delta H est une perte de tête plutôt que d’énergie: elle représente la conversion irréversible de l’énergie mécanique à flux moyen en turbulence et finalement en énergie interne, l’énergie totale étant conservée tout au long.

def head_loss(h1, h2):
    '''Given: head loss across the jump [m].'''
    return (h2 - h1)**3 / (4 * h1 * h2)


if TASKS_DONE:
    delta_H = head_loss(DESIGN_STATE.h1, DESIGN_STATE.h2)
    H1 = energy_head(DESIGN_STATE.h1, DESIGN.q)

    print(f"head loss           dH        = {delta_H:8.3f} m")
    print(f"energy head at 1    H1        = {H1:8.3f} m")
    print(f"relative loss       dH / H1   = {delta_H / H1:8.1%}")
else:
    delta_H = H1 = None
    print("Complete Tasks 1 to 3, then re-run this cell.")
Complete Tasks 1 to 3, then re-run this cell.

Longueur du bassin et protection contre l’affouillement

La donnée basin_lengths, évaluée à la conception acceptée, parallèlement à la règle du pouce (lj≈l_j \approx 6 h2h_2) par rapport à laquelle la longueur du bassin peut être vérifiée.

if TASKS_DONE:
    f_peterka = peterka_f(DESIGN_STATE.Fr1)
    l_b, l_s = basin_lengths(DESIGN_STATE.h2, DESIGN_STATE.Fr1)

    print(f"Peterka multiplier  f_l  = {f_peterka:7.2f}  (at Fr1 = {DESIGN_STATE.Fr1:.2f})")
    print(f"basin length        l_b  = {l_b:7.2f} m   <- given")
    print(f"rule of thumb     6 h_2  = {6 * DESIGN_STATE.h2:7.2f} m"
          f"   ({abs(6 * DESIGN_STATE.h2 / l_b - 1):.1%} from l_b)")
    print(f"scour protection    l_s  = {l_s:7.2f} m   <- given")
else:
    f_peterka = l_b = l_s = None
    print("Complete Tasks 1 to 3, then re-run this cell.")
Complete Tasks 1 to 3, then re-run this cell.

Évaluation des résultats

Contrôle objectif technique

Les deux objectifs d’ingénierie sont ici évalués graphiquement en fonction de la profondeur du bassin db\mathbf{d_b}. Les bandes ombragées dans les parcelles sont les objectifs et la ligne verticale en tirets est la conception acceptée. Un seul critère est déterminant : Fr1Fr_1 reste à l’intérieur de sa bande à travers tous les tests, mais rtr_{\mathrm{t}} entre dans sa bande et la laisse à nouveau à environ 2,5 m de profondeur du bassin, entre 6,79 m et 9,31 m. Le critère de rétention choisit donc db\mathbf{d_b}, et c’est le critère qui dépend de la profondeur d’eau aval donnée htwh_{tw}.

if TASKS_DONE:
    db_range = np.linspace(0.2, 20.0, 240)
    states = [basin_state(float(x)) for x in db_range]
    Fr_curve = np.array([s.Fr1 for s in states])
    Rt_curve = np.array([s.Rt for s in states])

    fig, axes = plt.subplots(1, 2, figsize=(9.4, 3.6), sharex=True)

    axes[0].axhspan(*FR_WINDOW, color=CYAN, alpha=0.18, lw=0)
    axes[0].plot(db_range, Fr_curve, color=BLUE, lw=2.2)
    axes[0].set_ylabel("$Fr_1$ at the basin entrance [-]")
    axes[0].set_title("Steady-jump window")
    axes[0].set_ylim(4.3, 9.3)
    axes[0].annotate("steady jump\n$4.5 \\leq Fr_1 < 9$", (0.8, 8.4),
                     color=BLUE, fontsize=8.5)

    axes[1].axhspan(Rt_curve.min(), RT_WINDOW[0], color=WARN, alpha=0.10, lw=0)
    axes[1].axhspan(*RT_WINDOW, color=CYAN, alpha=0.18, lw=0)
    axes[1].axhspan(RT_WINDOW[1], Rt_curve.max(), color=GREY, alpha=0.10, lw=0)
    axes[1].axhline(1.0, color=GREY, lw=0.8, ls=":")
    axes[1].plot(db_range, Rt_curve, color=BLUE, lw=2.2)
    axes[1].set_ylabel("retention ratio $r_\\mathrm{t}$ [-]")
    axes[1].set_title("Retention window")
    axes[1].set_ylim(Rt_curve.min(), Rt_curve.max())
    axes[1].annotate("jump swept out", (4.2, 0.83), color=WARN, fontsize=8.5)
    axes[1].annotate("retained", (0.8, 1.09), color=BLUE, fontsize=8.5)
    axes[1].annotate("jump drowned", (0.8, 1.42), color=GREY, fontsize=8.5)

    for ax in axes:
        ax.axvline(DESIGN_STATE.d_b, color=WARN, lw=1.4, ls="--")
        # the design variable is the one symbol set apart from the notation:
        # bold and in the warn colour, on the slides and here alike
        ax.set_xlabel("basin depth $\\mathbf{d_b}$ [m]", color=WARN)
        ax.set_xlim(0.2, 20.0)

    axes[0].plot([DESIGN_STATE.d_b], [DESIGN_STATE.Fr1], "o", color=WARN, ms=6, zorder=3)
    axes[1].plot([DESIGN_STATE.d_b], [DESIGN_STATE.Rt], "o", color=WARN, ms=6, zorder=3)
    axes[0].annotate(f"design\n$\\mathbf{{d_b}} = {DESIGN_STATE.d_b:.2f}$ m,"
                     f"  $Fr_1 = {DESIGN_STATE.Fr1:.2f}$",
                     (DESIGN_STATE.d_b, DESIGN_STATE.Fr1), textcoords="offset points",
                     xytext=(-104, 34), color=WARN, fontsize=8.5,
                     arrowprops=dict(arrowstyle="-", color=WARN, lw=0.8))
    axes[1].annotate(f"$r_\\mathrm{{t}} = {DESIGN_STATE.Rt:.3f}$",
                     (DESIGN_STATE.d_b, DESIGN_STATE.Rt), textcoords="offset points",
                     xytext=(40, -58), color=WARN, fontsize=8.5,
                     arrowprops=dict(arrowstyle="-", color=WARN, lw=0.8))

    fig.tight_layout()
    plt.show()
else:
    print("Complete Tasks 1 to 3, then re-run this cell.")
Complete Tasks 1 to 3, then re-run this cell.

Section longitudinale du bassin de dissipation

Le modèle accepté est tracé dans le bloc de codes suivant à l’échelle, avec le lit de rivière en aval comme référence. Deux profondeurs sont marquées au-dessus du plancher du bassin, et la différence entre elles fait l’objet du contrôle de rétention:

  • Disponible est la profondeur fournie par l’eau aval et la profondeur du bassin, htw+dbh_{tw} + \mathbf{d_b}.

  • Requis est la profondeur requise pour le ressaut, c’est-à-dire la profondeur conjuguée h2h_2.

Leur rapport est rtr_{\mathrm{t}}, et l’excédent est la marge par laquelle le ressaut est conservé dans le bassin plutôt que sur le lit en aval. Seules les profondeurs finales du ressaut suivent les relations 1d, de sorte que la surface tirée entre les sections 1 et 2 est indicative.

if TASKS_DONE:
    s = DESIGN_STATE
    floor = -s.d_b                       # basin floor, below the downstream riverbed
    h_avail = DESIGN.h_tw + s.d_b        # depth available over the floor
    h_need = floor + s.h2                # level the jump demands, above the datum
    top = DESIGN.H0                      # energy head above the un-sunk invert
    u = l_b / 24.8                       # one drawing unit, so the layout scales

    x_face, x_toe, x_end = -7.0 * u, 0.0, l_b
    x_tail = x_end + 0.6 * l_b
    x_j0, x_j1 = 0.26 * l_b, 0.62 * l_b

    # every label gets a white glow, so that one crossing a line stays readable
    glow = [pe.withStroke(linewidth=2.6, foreground="white")]

    fig, ax = plt.subplots(figsize=(9.4, 3.4))

    # --- structure and bed ---------------------------------------------------
    # the chute face descends from the spillway crest to the basin floor,
    # then the floor runs to the end sill and the river bed continues downstream
    ax.plot([x_face - 2.0 * u, x_face, x_face + 3.2 * u, x_toe, x_end, x_end, x_tail],
            [top, top, top, floor, floor, 0.0, 0.0],
            color=NAVY, lw=2.4, solid_joinstyle="round")

    # --- water body ----------------------------------------------------------
    xs = np.linspace(x_toe, x_tail, 500)
    bed = np.where(xs <= x_end, floor, 0.0)
    ramp = np.clip((xs - x_j0) / (x_j1 - x_j0), 0.0, 1.0)
    surface = (floor + s.h1) + (DESIGN.h_tw - floor - s.h1) * (
        0.5 - 0.5 * np.cos(math.pi * ramp))
    # a small crest at the end of the jump, so that the roller reads as a roller
    # rather than as a smooth asymptote; it is schematic, like the ramp itself
    surface = surface + 0.04 * (DESIGN.h_tw - floor - s.h1) * np.exp(
        -((xs - x_j1) / (0.09 * l_b))**2)

    ax.fill_between(xs, surface, bed, color=CYAN, alpha=0.30, lw=0)
    ax.plot(xs, surface, color=BLUE, lw=2.0)

    # --- dimensions ----------------------------------------------------------
    def dim(x, y0, y1, label, colour=NAVY, dx=0.7 * u, ha="left", frac=0.5,
            outside=False, ext=0.4 * u):
        '''
        A dimension between two levels, with a tick at each end so that what it
        measures from and to is unambiguous. outside=True puts the two heads
        beyond the span, pointing in, for a span too short to hold them.
        '''
        for y in (y0, y1):
            ax.plot([x - 0.5 * u, x + 0.5 * u], [y, y], color=colour, lw=0.8)
        if outside:
            ax.annotate("", (x, y0), (x, y0 - ext),
                        arrowprops=dict(arrowstyle="->", color=colour, lw=1.1))
            ax.annotate("", (x, y1), (x, y1 + ext),
                        arrowprops=dict(arrowstyle="->", color=colour, lw=1.1))
        else:
            ax.annotate("", (x, y0), (x, y1),
                        arrowprops=dict(arrowstyle="<->", color=colour, lw=1.1))
        if label:
            ax.text(x + dx, y0 + frac * (y1 - y0), label, color=colour,
                    fontsize=8.2, va="center", ha=ha, path_effects=glow)

    # the level the jump demands, carried downstream so that it can be compared
    # with the water surface; it starts right of the jump arrow, never under it
    ax.plot([0.48 * x_end, x_end + 6.0 * u], [h_need] * 2,
            color=WARN, lw=1.0, ls="--")
    dim(0.50 * x_end, floor, h_need,
        f"required\n$h_2 \\approx {s.h2:.1f}$ m", colour=WARN, dx=-0.7 * u,
        ha="right", frac=0.86)
    dim(0.86 * x_end, floor, DESIGN.h_tw,
        f"available\n$h_{{tw}}+\\mathbf{{d_b}} \\approx {h_avail:.1f}$ m",
        dx=-0.7 * u, ha="right")

    # the surplus is 1.1 m on a 22 m bar, so it is named rather than left to the eye
    x_gap = x_end + 4.6 * u
    dim(x_gap, h_need, DESIGN.h_tw, "", colour=WARN, outside=True)
    ax.annotate(f"surplus $\\approx {h_avail - s.h2:.1f}$ m\n"
                f"(water above the level $h_2$ demands)",
                (x_gap, DESIGN.h_tw + 0.6 * u), textcoords="offset points",
                xytext=(0, 32), color=WARN, fontsize=8.2, ha="center",
                arrowprops=dict(arrowstyle="->", color=WARN, lw=0.9),
                path_effects=glow)

    ax.annotate(f"$h_1 \\approx {s.h1:.1f}$ m",
                (x_toe + 3.2 * u, floor + 0.5 * s.h1), textcoords="offset points",
                xytext=(2, 54), color=NAVY, fontsize=8.2,
                arrowprops=dict(arrowstyle="->", color=NAVY, lw=0.9),
                path_effects=glow)
    dim(x_end + 2.4 * u, floor, 0.0,
        f"$\\mathbf{{d_b}} \\approx {s.d_b:.1f}$ m", colour=WARN, outside=True,
        ext=0.8 * u, dx=1.2 * u)
    dim(x_end + 9.0 * u, 0.0, DESIGN.h_tw,
        f"$h_{{tw}} \\approx {DESIGN.h_tw:.1f}$ m")

    ax.annotate("", (x_toe, floor - 0.365 * s.h2), (x_end, floor - 0.365 * s.h2),
                arrowprops=dict(arrowstyle="<->", color=NAVY, lw=1.1))
    ax.text(0.5 * x_end, floor - 0.62 * s.h2,
            f"basin length $l_b \\approx {l_b:.1f}$ m",
            color=NAVY, fontsize=8.2, ha="center", path_effects=glow)

    # --- labels --------------------------------------------------------------
    ax.axhline(0.0, color=GREY, lw=0.7, ls=":")
    # the arrow points at the crest of the roller, and stays above the dashed
    # level line so that it can cross neither that line nor the "required" label
    x_jump = x_j1
    y_jump = float(np.interp(x_jump, xs, surface))
    ax.text(x_jump, y_jump + 1.75 * u, "hydraulic jump", color=NAVY, fontsize=9,
            ha="center", style="italic", path_effects=glow)
    ax.annotate("", (x_jump, y_jump + 0.25 * u), (x_jump, y_jump + 1.45 * u),
                arrowprops=dict(arrowstyle="->", color=NAVY, lw=0.9))
    ax.text(x_face - 1.6 * u, top + 0.12 * s.h2,
            f"from the spillway chute,  $H_0 \\approx {top:.1f}$ m",
            color=NAVY, fontsize=8.2, path_effects=glow)

    ax.set_xlim(x_face - 2.5 * u, x_tail + 1.0 * u)
    ax.set_ylim(floor - 0.75 * s.h2, top + 0.55 * s.h2)
    ax.set_aspect("equal")
    ax.set_xlabel("distance along the basin [m]")
    ax.set_ylabel("level above the\ndownstream bed [m]")
    ax.spines["left"].set_visible(True)
    fig.tight_layout()
    plt.show()
else:
    print("Complete Tasks 1 to 3, then re-run this cell.")
Complete Tasks 1 to 3, then re-run this cell.

Résumé de la conception

if TASKS_DONE:
    s = DESIGN_STATE
    rows = [
        ("given", "spillway design flow", "Q", DESIGN.Q, "m3/s"),
        ("given", "unit discharge", "q", DESIGN.q, "m2/s"),
        ("given", "energy head above the invert", "H0", DESIGN.H0, "m"),
        ("given", "tailwater depth", "h_tw", DESIGN.h_tw, "m"),
        ("design", "basin depth", "d_b", s.d_b, "m"),
        ("design", "energy head above the floor", "H", s.H, "m"),
        ("design", "entry depth", "h1", s.h1, "m"),
        ("design", "entry velocity", "v1", s.v1, "m/s"),
        ("design", "entry Froude number", "Fr1", s.Fr1, "-"),
        ("design", "conjugate depth", "h2", s.h2, "m"),
        ("design", "retention ratio", "Rt", s.Rt, "-"),
        ("result", "head loss", "dH", delta_H, "m"),
        ("result", "relative head loss", "dH/H1", 100 * delta_H / H1, "%"),
        ("result", "basin length", "l_b", l_b, "m"),
        ("result", "scour protection length", "l_s", l_s, "m"),
    ]

    print(f"{'':8}{'quantity':<34}{'symbol':<14}{'value':>10}  unit")
    group = None
    for kind, name, symbol, value, unit in rows:
        if kind != group:
            print("-" * 70)
            group = kind
        print(f"{kind:<8}{name:<34}{symbol:<14}{value:>10.3f}  {unit}")

    print("=" * 70)
    print(f"windows: Fr1 in [{FR_WINDOW[0]}, {FR_WINDOW[1]}) -> "
          f"{'met' if s.fr_ok else 'NOT met'};  "
          f"Rt in [{RT_WINDOW[0]}, {RT_WINDOW[1]}] -> "
          f"{'met' if s.rt_ok else 'NOT met'}")
else:
    print("Complete Tasks 1 to 3, then re-run this cell.")
Complete Tasks 1 to 3, then re-run this cell.

Questions complémentaires

Chacun des éléments suivants nécessite un seul changement à une entrée du code écrit ci-dessus, afin d’explorer comment les incertitudes et les changements dans les conditions limites agissent sur le ressaut hydraulique, et donc sur la conception du bassin de cale.

  1. Que se passe-t-il si la profondeur d’eau aval est inférieure? Recalculer avec la profondeur d’eau aval réduite de 2 m et tout le reste inchangé, c’est-à-dire main basin_state a DesignData dont h_tw est 2 m plus petit. Déterminer l’effet sur rtr_{\mathrm{t}} et ses conséquences pour le lit de rivière en aval, et déterminer comment la position de ressaut change.

  2. Comment se comporte le ressaut sous différents scénarios de décharge? Le bassin est conçu pour une inondation de 500 ans, mais fonctionne principalement à des débits beaucoup plus faibles. Donc réévaluer basin_state avec un DesignData dont q est réduit de moitié, et déterminer si le ressaut reste stable et maintenu.

Limites de la simplification

Ce modèle de calcul utilise des équations 1d simplifiées, et ses résultats sont donc sujets à une incertitude considérable, liée (mais non limitée à):

  • l’hydrologie, c’est-à-dire la dérivation de l’inondation de conception;

  • la courbe d’évaluation de l’eau aval, au lieu de l’idéalisation de Manning rectangulaire;

  • les scénarios de charge et de défaillance, y compris les inondations dépassant la conception du déversoir, l’exploitation de la porte partielle et les portes d’écluses situées à côté du déversoir;

  • cavitation, entraînement à l’air, soulèvement, pressions fluctuantes et fatigue de la structure;

  • l’évaluation de la stabilité de l’affouillement et du lit de rivière en aval de la longueur protégée;

  • analyse géotechnique et conception structurelle;

  • le passage des poissons et la gestion des sédiments.

Sources