Beispiel zur hydraulischen Durchbildung einer Staustufe#
Dieses Notebook fasst zwei zusammengehörige Aufgaben zusammen:
Hydraulische Vorbemessung des Wehrs (Poleni, (n‑1)‑Regel)
Tosbeckenbemessung (iterativer Workflow nach Bollrich / Peterka)
Lernziele:
Rechengänge sehen;
Kernannahmen verstehen;
Größenordnungen prüfen können;
Grenzen von Vereinfachungen erkennen.
import math
from scipy.optimize import brentq
from pprint import pprint
Teil 1: Hydraulische Vorbemessung#
Inhalte#
Es wird eine überschlägige hydraulische Vorbemessung eines vollregelnden Wehrs durchgeführt:
Wahl eines plausiblen Bemessungsfalls
Vorbemessung der erforderlichen lichten Wehrbreite
Aufteilung in Wehrfelder
Nachweis der (n‑1)‑Regel (DIN 19700)
Grober Check von Freibord
Gegebene Daten und Notation#
Poleni-Gleichung für den freien Überfall:
Effektive Überflussbreite (Einschnürung durch Pfeiler):
Herleitung: \(b_{\text{eff}} = b_{\text{ges}} - \sum b_{\text{pf}} - 2\,n_{\text{pf}}\,\xi_{\text{pf}}\,h_{\text{ü}}\) mit \(n_{\text{pf}} = (n-1) + 2\cdot0{,}5 = n\) Pfeileräquivalenten
Symbol |
Bedeutung |
|---|---|
\(Q\) |
Durchfluss (m³/s) |
\(b_{\text{eff}}\) |
wirksame Wehrbreite (m) |
\(h_{\text{ü}}\) |
Überfallhöhe (m) |
\(c\) |
Abminderungsbeiwert bei unvollkommenem Überfall (–) |
\(\mu\) |
Abflussbeiwert (–) |
\(h_{\text{ü,zul}}\) |
zulässige Überfallhöhe bei BHQ₁ (m über Wehrkrone) |
\(z_H\) |
höchster zulässiger Oberwasserstand bei BHQ₁ (m ü. NHN); \(h_{\text{ü,zul}} = z_H - z_{\text{Kr}}\) |
\(f\) |
erforderlicher Freibord (m) |
\(n\) |
Anzahl Wehrfelder |
\(b_F\) |
Breite eines Wehrfelds (m) |
\(b_{\text{pf}}\) |
Breite eines Pfeilers (m) |
\(\xi_{\text{pf}}\) |
Einschnürungsbeiwert (–) |
Eingangsgrößen#
BHQ1 = 65.0 # m³/s Bemessungshochwasser 1 (Regelfall)
BHQ2 = 85.0 # m³/s Bemessungshochwasser 2 (Kontrollfall)
# h_ue_zul: zulässige Überfallhöhe über Wehrkrone bei BHQ1 (= z_H - z_Kr, relativ)
# Nicht zu verwechseln mit z_H (absolutem Oberwasserstand in m ü. NHN, vgl. Notation)
h_ue_zul = 1.10 # m
f = 0.50 # m Freibord (DIN 19700: f ≥ 0,5 m bei BHQ1)
mu = 0.64 # Abflussbeiwert (bewegliches Wehr, scharfkantig)
c = 1.0 # Abminderungsbeiwert (vollkommener Überfall, Anfangswert)
xi_pf = 0.10 # Einschnürungsbeiwert (abgerundete Pfeilerköpfe)
b_F = 15.0 # m gewählte Wehrfeldbreite (technisch bedingt)
b_pf = b_F * 0.225 # m Pfeilerbreite (Drucksegmentverschluss)
g = 9.81 # m/s²
print(f"Pfeilerbreite b_pf = {b_pf:.2f} m")
Pfeilerbreite b_pf = 3.38 m
Poleni & erforderliche Wehrbreite#
Entwurfsziel (DIN 19700, (n‑1)‑Regel):
Mit \((n-1)\) aktiven Wehrfeldern muss BHQ₁ abgeführt werden, ohne dass \(h_{\text{ü}} > h_{\text{ü,zul}}\).
Auflösung der Poleni-Gleichung nach \(b_{\text{eff}}\):
Auflösung nach \(h_{\text{ü}}\) (für gegebene Breite):
Hilfsfunktionen für Poleni-Solver#
c_pol = (2/3) * mu * math.sqrt(2 * g) # kombinierter Poleni-Koeffizient ohne b und h_ue
def b_eff_von_Q(Q, h_ue, c_abd=1.0):
"""Erforderliche effektive Wehrbreite für gegebenen Durchfluss."""
return Q / (c_abd * c_pol * h_ue**1.5)
def h_ue_von_Q(Q, b_eff, c_abd=1.0):
"""Überfallhöhe bei gegebenem Durchfluss und effektiver Breite."""
return (Q / (c_abd * c_pol * b_eff))**(2/3)
def b_eff_n_felder(n_aktiv, h_ue):
"""Effektive Breite für n_aktiv nebeneinanderliegende Felder (Einschnürung berücksichtigt)."""
return n_aktiv * (b_F - 2 * xi_pf * h_ue)
Erforderliche Breite und Anzahl Wehrfelder#
# Gesamte b_eff für (n-1)-Fall muss b_eff_erf >= b_eff_von_Q(BHQ1, h_ue_zul) erfüllen
b_eff_erf = b_eff_von_Q(BHQ1, h_ue_zul, c)
b_F_eff = b_F - 2 * xi_pf * h_ue_zul # wirksame Feldbreite je Feld
n_minus1 = math.ceil(b_eff_erf / b_F_eff) # benötigte Anzahl (n-1)-Felder
n = n_minus1 + 1 # Gesamtanzahl Wehrfelder
print(f"Kombinierter Poleni-Koeffizient c_pol = {c_pol:.4f}")
print(f"Erforderliche b_eff (n-1-Fall) = {b_eff_erf:.2f} m")
print(f"Wirksame Feldbreite b_F_eff = {b_F_eff:.2f} m")
print(f"Benötigte (n-1)-Felder = {n_minus1}")
print(f"Gewählte Wehrfeldanzahl n = {n}")
Kombinierter Poleni-Koeffizient c_pol = 1.8899
Erforderliche b_eff (n-1-Fall) = 29.81 m
Wirksame Feldbreite b_F_eff = 14.78 m
Benötigte (n-1)-Felder = 3
Gewählte Wehrfeldanzahl n = 4
Wehrabmessungen und Breite#
n_pfeiler = n - 1 # Zwischenpfeiler
b_licht = n * b_F # lichte Gesamtbreite (nur Felder)
b_pfeiler = n_pfeiler * b_pf # Summe Pfeilerbreiten
b_gesamt = b_licht + b_pfeiler # Gesamtbreite inkl. Pfeiler
print(f"Anzahl Zwischenpfeiler : {n_pfeiler}")
print(f"Lichte Gesamtbreite : {b_licht:.1f} m")
print(f"Summe Pfeilerbreiten : {b_pfeiler:.2f} m")
print(f"Bauwerksbreite gesamt : {b_gesamt:.2f} m")
Anzahl Zwischenpfeiler : 3
Lichte Gesamtbreite : 60.0 m
Summe Pfeilerbreiten : 10.12 m
Bauwerksbreite gesamt : 70.12 m
(n‑1) – Nachweis#
Bedingung: Mit \((n-1)\) aktiven Feldern muss gelten: \(h_{\text{ü}} \leq h_{\text{ü,zul}}\)
Zusätzlich werden BHQ₁ und BHQ₂ mit allen \(n\) Feldern geprüft.
faelle = [
("BHQ1, alle n Felder", BHQ1, n),
("BHQ1, (n-1) Felder", BHQ1, n - 1),
("BHQ2, alle n Felder", BHQ2, n),
]
print(f"{'Fall':<28} {'n_akt':>5} {'b_eff':>8} {'h_ü':>7} {'≤ h_ü,zul?':>10}")
print("-" * 62)
for label, Q, n_akt in faelle:
h_ue_iter = h_ue_zul
for _ in range(20):
beff = b_eff_n_felder(n_akt, h_ue_iter)
h_ue_neu = h_ue_von_Q(Q, beff, c)
if abs(h_ue_neu - h_ue_iter) < 1e-6:
break
h_ue_iter = h_ue_neu
ok = "OK" if h_ue_iter <= h_ue_zul else "!!"
print(f"{label:<28} {n_akt:>5} {beff:>8.2f} {h_ue_iter:>7.3f} {ok:>10}")
print(f"\n h_ü,zul = {h_ue_zul:.2f} m (max. zulässige Überfallhöhe bei BHQ1)")
Fall n_akt b_eff h_ü ≤ h_ü,zul?
--------------------------------------------------------------
BHQ1, alle n Felder 4 59.44 0.694 OK
BHQ1, (n-1) Felder 3 44.49 0.842 OK
BHQ2, alle n Felder 4 59.33 0.831 OK
h_ü,zul = 1.10 m (max. zulässige Überfallhöhe bei BHQ1)
Freibord-Check#
Kronenhöhe = \(h_{\text{ü,zul}} + f \quad \text{mit} \quad f \geq 0{,}5\,\text{m (BHQ}_1\text{)}\)
# h_ue bei BHQ1, (n-1)-Felder (konservativster Fall)
h_ue_n1 = h_ue_zul
for _ in range(20):
beff_n1 = b_eff_n_felder(n - 1, h_ue_n1)
h_ue_n1 = h_ue_von_Q(BHQ1, beff_n1, c)
freibord_vorhanden = h_ue_zul - h_ue_n1
kronenhoehe = h_ue_zul + f
print(f"h_ü bei BHQ1, (n-1)-Felder : {h_ue_n1:.3f} m")
print(f"Freibord über h_ü bis h_ü,zul : {freibord_vorhanden:.3f} m")
print(f"Kronenhöhe (= h_ü,zul + f) : {kronenhoehe:.2f} m über Wehrschwelle")
print(f"Freibordanforderung ≥ 0,5 m: {'OK' if f >= 0.5 else 'Nicht erfüllt'}")
h_ü bei BHQ1, (n-1)-Felder : 0.842 m
Freibord über h_ü bis h_ü,zul : 0.258 m
Kronenhöhe (= h_ü,zul + f) : 1.60 m über Wehrschwelle
Freibordanforderung ≥ 0,5 m: OK
Teil 2: Tosbeckenbemessung#
Konzept#
Ziel ist es, den Wechselsprung innerhalb des Tosbeckens zu erzwingen. Konstruktiver Freiheitsgrad: Tosbeckeneintiefung \(e\) (in m).
Einstaugrad \(\varepsilon\) muss im Zielbereich liegen: $\( \varepsilon = \frac{h_u + e}{h_2} \in [1{,}05;\; 1{,}15] \)$
Iterativer Algorithmus (vgl. Vorlesungsfolie):
Schritt |
Inhalt |
|---|---|
A |
\(e\) festlegen (Startwert) |
B |
\(h_1\), \(v_1\) aus Bernoulli-Gleichung (Energiehöhe \(H_{\text{ges}}\)) |
C |
\(Fr_1 = v_1 / \sqrt{g\,h_1}\) |
D |
\(4{,}5 \leq Fr_1 < 9{,}0\)? → Nein: \(e\) anpassen |
E |
\(h_u\) aus Manning–Strickler bzw. gemessen |
F |
\(h_2 = \dfrac{h_1}{2}\left(\sqrt{1+8\,Fr_1^2}-1\right)\) (Bélanger) |
G |
\(1{,}05 \leq \varepsilon \leq 1{,}15\)? → Nein: \(e\) anpassen |
+ |
\(l_T\) und \(l_K\) berechnen |
Zusätzliche Eingangsgrößen Tosbecken#
Neben den Wehrparametern werden benötigt:
Symbol |
Bedeutung |
|---|---|
\(w\) |
Wehrhöhe über UW-Sohle (m) |
\(k_{St}\) |
Strickler-Beiwert der UW-Strecke (m¹/³/s) |
\(I_E\) |
Sohlgefälle der UW-Strecke (–) |
\(B_u\) |
Breite der UW-Strecke (m) |
\(H_{\text{ges}}\) |
Gesamtenergielinie über Tosbeckensohle: \(H_{\text{ges}} = h_{\text{ü,zul}} + w + e\) |
w_wehr = 2.5 # m Wehrhöhe über UW-Sohle
k_st = 30.0 # m^1/3/s Strickler-Beiwert UW-Strecke (naturnahe Sohle)
I_E = 0.001 # -- Sohlgefälle UW-Strecke
b_u = 40.0 # m Breite UW-Strecke (Rechteckprofil)
# Einheitsdurchfluss für Tosbeckenbemessung (alle n Felder aktiv)
h_ue_n = h_ue_zul
for _ in range(20):
beff_n = b_eff_n_felder(n, h_ue_n)
h_ue_n = h_ue_von_Q(BHQ1, beff_n, c)
q = BHQ1 / beff_n # m²/s – Einheitsdurchfluss
print(f"BHQ1-Wehrbreite (n Felder): b_eff = {beff_n:.2f} m")
print(f"Einheitsdurchfluss q = BHQ1/b_eff = {q:.3f} m²/s")
BHQ1-Wehrbreite (n Felder): b_eff = 59.44 m
Einheitsdurchfluss q = BHQ1/b_eff = 1.093 m²/s
Unterwassertiefe \(h_u\) durch Manning-Strickler (Vorbereitung Schritt E)#
Für ein Rechteckprofil gilt: $\( Q = k_{St} \cdot A \cdot R^{2/3} \cdot I_E^{1/2} \qquad \text{mit } A = b_u \cdot h_u,\quad R = \frac{b_u \cdot h_u}{b_u + 2\,h_u} \)$
Rechteckprofilannahme ist fehleranfällig
Natürliche Flüsse sind komplex und die Annahme eines Rechteckprofils ist ungenau. Es empfiehlt sich bessere Aussagen durch Messungen, numerische Modellierung oder aus digitalen Höhenmodellen bzw. Lidar-Daten abzuleiten.
Ein numerischer 1D-Gleichungslöser für die Manning kann mittels folgender Funktion definiert und in der Folge aufgerufen werden:
def Q_manning(h, b, k, I):
A = b * h
R = (b * h) / (b + 2 * h)
return k * A * R**(2/3) * math.sqrt(I)
# brentq sucht h in [0.01, 20] m mit Q_manning(h) = BHQ1
h_u = brentq(lambda h: Q_manning(h, b_u, k_st, I_E) - BHQ1, 0.01, 20.0)
print(f"Unterwassertiefe h_u = {h_u:.3f} m")
print(f"Probe: Q_Manning = {Q_manning(h_u, b_u, k_st, I_E):.2f} m³/s (Soll: {BHQ1} m³/s)")
Unterwassertiefe h_u = 1.420 m
Probe: Q_Manning = 65.00 m³/s (Soll: 65.0 m³/s)
Schritte A bis G: Iterative Tosbecken-Bemessung#
Schritt B Herleitung von \(h_1\) und \(v_1\)#
Energiehöhe über Tosbeckensohle (Bernoulli, vernachlässige \(v_0\) da \(v_0 < \) 1,0 m/s): $\( H_{\text{ges}} = h_{\text{ü,zul}} + w + e \)$
Am schießenden Querschnitt 1 (Tosbeckeneinlauf): $\( H_{\text{ges}} = h_1 + \frac{v_1^2}{2g} = h_1 + \frac{q^2}{2g\,h_1^2} \)$
Kodieren des Arbeitsablaufs#
Der Arbeitsablauf (Workflow) der Tosbeckenbemessung sowie die Ermittlung des k-Faktor in Abhängigkeit der Froude-Zahl wird in zwei Funktionen definiert, mit \(e\) als Eingangsvariable:
def tosbecken_check(e):
"""
Führt Schritte A-G des Tosbecken-Workflows für gegebene Eintiefung e durch.
Gibt (Fr1, epsilon, h1, h2, ok_Fr, ok_eps) zurück.
"""
# Schritt B: h1 aus Bernoulli (kleine, schießende Wurzel)
H_ges = h_ue_zul + w_wehr + e
# Suche h1 < h_grenz (kritische Tiefe) = (q**2/g)^(1/3)
h_krit = (q**2 / g)**(1/3)
h1 = brentq(lambda h: h + q**2 / (2 * g * h**2) - H_ges, 1e-4, h_krit)
v1 = q / h1
# Schritt C: Froude-Zahl
Fr1 = v1 / math.sqrt(g * h1)
# Schritt D: Fr1-Check
ok_Fr = 4.5 <= Fr1 < 9.0
# Schritt F: konjugierte Tiefe h2 (Belanger)
h2 = (h1 / 2) * (math.sqrt(1 + 8 * Fr1**2) - 1)
# Schritt G: Einstaugrad
eps = (h_u + e) / h2
ok_eps = 1.05 <= eps <= 1.15
return Fr1, eps, h1, h2, ok_Fr, ok_eps
# k-Faktor für Tosbeckenlänge (vgl. Peterka 1984 / USBR)
def k_faktor(Fr1):
if Fr1 < 2.4: return 4.8
elif Fr1 < 4.0: return 4.8 + (Fr1 - 2.4) / (4.0 - 2.4) * (5.8 - 4.8)
elif Fr1 < 5.0: return 5.8 + (Fr1 - 4.0) * (6.0 - 5.8)
elif Fr1 < 6.0: return 6.0
elif Fr1 <= 11.0: return 6.13
else: return 6.0
Iterieren über \(e\)#
Die Eintiefung kann nun mittels der zuvor definierten Funktionen berechnet werden, basierend auf einem Startwert und einem Wertebereich:
e_test = 1.0 # m Startwert (Schritt A)
e_min = 0.0 # m Suchbereich untere Grenze
e_max = 3.0 # m Suchbereich obere Grenze
iterationen = []
print(f"{'Iter':>4} {'e [m]':>7} {'Fr1':>6} {'Fr-OK':>6} {'h1 [m]':>8} {'h2 [m]':>8} {'ε':>6} {'ε-OK':>6}")
print("-" * 65)
for i in range(1, 15):
Fr1, eps, h1, h2, ok_Fr, ok_eps = tosbecken_check(e_test)
iterationen.append((e_test, Fr1, eps, h1, h2, ok_Fr, ok_eps))
fr_sym = "OK" if ok_Fr else "Nicht erfüllt"
eps_sym = "OK" if ok_eps else "Nicht erfüllt"
print(f"{i:>4} {e_test:>7.3f} {Fr1:>6.2f} {fr_sym:>6} {h1:>8.4f} {h2:>8.4f} {eps:>6.3f} {eps_sym:>6}")
if ok_Fr and ok_eps:
print("\n >>> Kriterien erfüllt: Iteration beendet.")
break
# Anpassungsstrategie (Bisektionslogik)
if not ok_Fr:
# Fr1 < 4.5 >>> e zu groß; Fr1 ≥ 9.0 >>> e zu klein
if Fr1 < 4.5:
e_max = e_test
else: # Fr1 >= 9.0
e_min = e_test
else:
# ok_Fr = True, aber ok_eps = False
if eps > 1.15: # zu viel Einstau >>> e verringern
e_max = e_test
else: # eps < 1.05 >>> zu wenig Einstau >>> e erhöhen
e_min = e_test
e_test = 0.5 * (e_min + e_max) # Bisektion
# Endwerte speichern
e_opt = e_test
Fr1_opt, eps_opt, h1_opt, h2_opt, _, _ = tosbecken_check(e_opt)
Iter e [m] Fr1 Fr-OK h1 [m] h2 [m] ε ε-OK
-----------------------------------------------------------------
1 1.000 8.77 OK 0.1166 1.3888 1.742 Nicht erfüllt
2 0.500 8.01 OK 0.1238 1.3427 1.430 Nicht erfüllt
3 0.250 7.63 OK 0.1280 1.3177 1.267 Nicht erfüllt
4 0.125 7.43 OK 0.1302 1.3047 1.184 Nicht erfüllt
5 0.062 7.33 OK 0.1314 1.2981 1.142 OK
>>> Kriterien erfüllt: Iteration beendet.
Tosbeckenlänge \(l_T\) und Kolkschutzlänge \(l_K\)#
Nach Peterka (1958/1984):
\(Fr_1\) |
2,4 |
4 |
5 |
6–11 |
14 |
|---|---|---|---|---|---|
\(k\) |
4,8 |
5,8 |
6 |
6,13 |
6 |
Tosbecken- und Kolkschutzlänge können durch Aufrufen der oben definierten Funktion für die Abschätzung des k-Faktors berechnet werden:
k = k_faktor(Fr1_opt)
l_T = k * h2_opt
l_K = 3.5 * l_T
print(f"Optimierte Eintiefung e = {e_opt:.3f} m")
print(f"Schießende Tiefe h1 = {h1_opt:.4f} m")
print(f"Froude-Zahl Fr1 = {Fr1_opt:.2f}")
print(f"Konjugierte Tiefe h2 = {h2_opt:.3f} m")
print(f"Unterwassertiefe h_u = {h_u:.3f} m")
print(f"Einstaugrad ε = {eps_opt:.3f} (Ziel: 1,05-1,15)")
print()
print(f"k-Faktor (Fr1={Fr1_opt:.1f}) k = {k:.2f}")
print(f"Tosbeckenlänge l_T = {l_T:.2f} m")
print(f"Kolkschutzlänge l_K = {l_K:.2f} m")
Optimierte Eintiefung e = 0.062 m
Schießende Tiefe h1 = 0.1314 m
Froude-Zahl Fr1 = 7.33
Konjugierte Tiefe h2 = 1.298 m
Unterwassertiefe h_u = 1.420 m
Einstaugrad ε = 1.142 (Ziel: 1,05-1,15)
k-Faktor (Fr1=7.3) k = 6.13
Tosbeckenlänge l_T = 7.96 m
Kolkschutzlänge l_K = 27.85 m
Zusammenfassung der hydraulischen Durchbildung inkl. Tosbeckenbemessung#
summary = {
"Hydraulik_Wehr": {
"BHQ1 (m3/s)": BHQ1,
"BHQ2 (m3/s)": BHQ2,
"h_ue_zul (m)": h_ue_zul,
"Freibord (m)": f,
"n (Wehrfelder)": n,
"bF (m)": b_F,
"Lichte Breite (m)": round(b_licht, 2),
"Gesamtbreite (m)": round(b_gesamt, 2),
"hü bei BHQ1 mit n Feldern (m)": round(h_ue_n, 3),
"hü bei BHQ1 mit (n-1) Feldern (m)": round(h_ue_n1, 3),
"Kronenhöhe (m)": round(kronenhoehe, 2),
},
"Tosbecken": {
"Wehrhöhe w (m)": w_wehr,
"Abfluss je Meter Wehrbreite (m²/s)": round(q, 3),
"hu (m)": round(h_u, 3),
"eopt (m)": round(e_opt, 3),
"h1 (m)": round(h1_opt, 4),
"h2 (m)": round(h2_opt, 3),
"Fr1": round(Fr1_opt, 2),
"epsilon": round(eps_opt, 3),
"k": round(k, 2),
"lT (m)": round(l_T, 2),
"lK (m)": round(l_K, 2),
},
}
pprint(summary)
{'Hydraulik_Wehr': {'BHQ1 (m3/s)': 65.0,
'BHQ2 (m3/s)': 85.0,
'Freibord (m)': 0.5,
'Gesamtbreite (m)': 70.12,
'Kronenhöhe (m)': 1.6,
'Lichte Breite (m)': 60.0,
'bF (m)': 15.0,
'h_ue_zul (m)': 1.1,
'hü bei BHQ1 mit (n-1) Feldern (m)': 0.842,
'hü bei BHQ1 mit n Feldern (m)': 0.694,
'n (Wehrfelder)': 4},
'Tosbecken': {'Abfluss je Meter Wehrbreite (m²/s)': 1.093,
'Fr1': 7.33,
'Wehrhöhe w (m)': 2.5,
'eopt (m)': 0.062,
'epsilon': 1.142,
'h1 (m)': 0.1314,
'h2 (m)': 1.298,
'hu (m)': 1.42,
'k': 6.13,
'lK (m)': 27.85,
'lT (m)': 7.96}}
Grenzen der Vereinfachung#
Dieses Notebook ersetzt nicht:
standortbezogene Hydrologie (BHQ-Bestimmung)
1D/2D-Wasserstandsberechnungen für mehrere Abflüsse
die Rechteckannahme für das Unterwasser ist schwach und sollte durch genauere hydraulische und Geländedaten ersetzt werden
Nachweise für mehrere Last- und Ausfallfälle (a > 1, BHQ₂, …)
geotechnische Nachweise
konstruktive Bemessung nach den jeweils einschlägigen Regeln
Nachweise für Fischdurchgängigkeit, Sedimentmanagement und Betriebssicherheit