Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Bakhmeteff’s specific energy (1912)#
Boris Bakhmeteff, in a 1912 book on varied flow written at St Petersburg,
measured the energy of a stream from the channel bed instead of from a
fixed datum: the specific energy \(E = y + q^2/(2gy^2)\)
(specific_energy()). Plotted
against depth, it has a least value at the critical depth
\(y_c = (q^2/g)^{1/3}\)
(critical_depth()), where the
Froude number is 1, and any larger energy can be carried at a subcritical
and a supercritical alternate depth
(alternate_depths()). This example
draws the specific-energy diagram and uses it to find the flow over a
raised step in the bed.
import matplotlib.pyplot as plt
import numpy as np
from engineeringkit.fluid_engineering import alternate_depths, critical_depth, froude_number, specific_energy
The specific-energy diagram#
y = np.linspace(0.08, 3.0, 300)
fig, ax = plt.subplots(figsize=(5, 5))
for q in [1.0, 2.0, 4.0]:
yc = critical_depth(q)
ax.plot(specific_energy(y, q), y, label=f"q = {q:g} m²/s")
ax.plot(1.5 * yc, yc, "ko")
ax.plot([0, 3], [0, 3], "k:", lw=0.8, label="E = y")
ax.set(xlim=(0, 3), ylim=(0, 3), xlabel="specific energy E [m]", ylabel="depth y [m]", title="Specific energy")
ax.legend()
fig.tight_layout()

Flow over a raised step#
A stream 1.8 m deep carrying 2 m²/s meets a step 0.2 m high. With no loss, the specific energy over the step is \(E_1 - \Delta z\), and the subcritical stream stays subcritical: its surface dips.
q, y1, dz = 2.0, 1.8, 0.2
E1 = specific_energy(y1, q)
deep, shallow = alternate_depths(E1 - dz, q)
print(f"upstream: y = {y1} m, E = {E1:.3f} m, Fr = {froude_number(q / y1, y1):.2f}")
print(f"over the step: y = {deep:.3f} m (the supercritical alternate would be {shallow:.3f} m)")
print(f"water surface drops by {y1 - (deep + dz):.3f} m")
upstream: y = 1.8 m, E = 1.863 m, Fr = 0.26
over the step: y = 1.581 m (the supercritical alternate would be 0.402 m)
water surface drops by 0.019 m
The largest step the stream can pass without backing up is the one that brings the energy down to its minimum, \(3y_c/2\).
yc = critical_depth(q)
dz_max = E1 - 1.5 * yc
print(f"critical depth {yc:.3f} m; largest step {dz_max:.3f} m")
assert np.isclose(specific_energy(deep, q), E1 - dz) and deep > yc > shallow
assert np.isclose(froude_number(q / yc, yc), 1.0)
assert np.allclose(alternate_depths(E1 - dz_max, q), yc)
plt.show()
critical depth 0.742 m; largest step 0.751 m
Total running time of the script: (0 minutes 0.103 seconds)