Chapter 3 Hydraulics: Normal and Critical Depths#

  1. Introduction: Normal_Depths

  2. Simulation: Normal_Depths

  3. Self-Assessment: Normal_Depths

  4. Introduction: Critical_Depths

  5. Simulation: Manning’s Coeff.

  6. Self-Assessment: Mannings Coeff.

1. Introduction#

💧 What Is Hydraulics?#

Hydraulics is the branch of fluid mechanics that deals with the behavior of water (and other fluids) in motion and at rest, especially in open channels and closed conduits. It focuses on understanding how water flows, interacts with boundaries, and responds to changes in slope, geometry, and energy.

Two of the most fundamental parameters in open channel hydraulics are:

1. Normal Depth#

  • The depth of flow in a channel under steady, uniform conditions

  • Occurs when gravitational force is balanced by frictional resistance

  • Depends on channel slope, roughness, and geometry

2. Critical Depth#

  • The depth at which specific energy is minimized for a given discharge

  • Marks the transition between subcritical (slow, deep) and supercritical (fast, shallow) flow

  • Defined by the condition: $\( Fr = \frac{V}{\sqrt{gD}} = 1 \)\( Where \)( Fr $) is the Froude number


📐 Importance in Hydraulic Structure Design#

Parameter

Design Relevance

Normal Depth

- Used to size channels, culverts, and canals for steady flow

- Helps determine backwater profiles and flow capacity

Critical Depth

- Essential for designing transitions, weirs, spillways, and energy dissipators

- Identifies control sections and flow regime changes


🧠 Conceptual Insight#

Understanding normal and critical depth is key to predicting flow behavior,
ensuring structural stability, and optimizing hydraulic performance.


References#

[Chanson, 2004] and [Chow, 1959] provide a comprehensive and practical guide to the principles and applications of open-channel hydraulics.

2. Simulation#

Normal Depth Estimator for Trapezoidal Channels#

This notebook provides an interactive tool to estimate the normal depth \(( y_n \)) in open channel flow using the Manning equation for a trapezoidal channel. The tool enables users to investigate how variations in hydraulic and geometric parameters affect normal depth for a given discharge.


What Is Normal Depth?#

Normal depth is the depth of flow under steady, uniform conditions in an open channel. At normal depth:

  • Flow is parallel to the channel bed

  • The energy grade line and water surface are parallel

  • The driving force (gravity) balances the resisting force (friction)

It is determined by solving the Manning equation implicitly: \( Q = \frac{1}{n} A(y) \cdot R(y)^{2/3} \cdot \sqrt{S} \) Where:

  • \(( Q \)): Discharge (m³/s)

  • \(( n \)): Manning’s roughness coefficient

  • \(( S \)): Channel slope

  • \(( A \)): Flow area (function of y, b, z)

  • \(( R \)): Hydraulic radius \(( = A/P \))

  • \(( b \)): Bottom width

  • \(( z \)): Side slope (H:1V)

This equation is solved using the bisection method, since it’s nonlinear in depth \(( y \)).


Interactive Controls#

  • Discharge Q – Set target flow (m³/s)

  • Bottom width b – Rectangular component of channel (m)

  • Side slope z – Horizontal to vertical side slope ratio (e.g., z = 2 means 2H:1V)

  • Manning’s roughness n – Reflects channel material (e.g., concrete, grass)

  • Channel bed slope S – Longitudinal slope of the channel

You can also choose one variable to vary across a specified range while keeping others fixed, and visualize how the normal depth responds.


Output#

The chart shows the computed normal depth as a function of the selected variable, making it easy to see the sensitivity of flow depth to changes in geometry or resistance.


import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as widgets
from IPython.display import display, clear_output

# --- Hydraulic formulas ---
def area_trap(b, y, z): return y * (b + z * y)
def perimeter_trap(b, y, z): return b + 2 * y * np.sqrt(1 + z**2)
def radius_trap(b, y, z): return area_trap(b, y, z) / perimeter_trap(b, y, z)
def manning_Q(b, y, z, n, S): return (1/n) * area_trap(b, y, z) * radius_trap(b, y, z)**(2/3) * S**0.5

def solve_normal_depth(Q, b, z, n, S, y_min=0.01, y_max=20, tol=1e-6):
    for _ in range(100):
        y_mid = (y_min + y_max) / 2
        Q_mid = manning_Q(b, y_mid, z, n, S)
        if abs(Q_mid - Q) < tol:
            return y_mid
        elif Q_mid > Q:
            y_max = y_mid
        else:
            y_min = y_mid
    return np.nan

# --- Sliders for fixed values ---
Q_slider = widgets.FloatSlider(value=10, min=1, max=100, step=1, description="Discharge Q (m³/s)")
b_slider = widgets.FloatSlider(value=5, min=1, max=10, step=0.5, description="Width b (m)")
z_slider = widgets.FloatSlider(value=2, min=0.5, max=4.0, step=0.1, description="Side Slope z")
n_slider = widgets.FloatSlider(value=0.02, min=0.01, max=0.05, step=0.001, description="Manning n")
S_slider = widgets.FloatSlider(value=0.001, min=0.0001, max=0.01, step=0.0001, readout_format=".4f", description="Slope S")

# Dropdown to select parameter to vary
param_dropdown = widgets.Dropdown(options=["z", "S", "n", "b"], value="z", description="Vary:")

# Slider to define variation range
range_slider = widgets.FloatRangeSlider(value=(0.5, 4), min=0.01, max=15, step=0.1, description="Range")

# --- Plotting logic ---
def update_plot(varied, param_range, Q, b, z, n, S):
    x_vals = np.linspace(param_range[0], param_range[1], 100)
    y_vals = []

    for val in x_vals:
        args = {"b": b, "z": z, "n": n, "S": S}
        args[varied] = val
        y = solve_normal_depth(Q, **args)
        y_vals.append(y)

    # Plot
    plt.figure(figsize=(8, 5))
    plt.plot(x_vals, y_vals, linewidth=2, color='royalblue')
    plt.xlabel({
        "z": "Side Slope z (H:1V)",
        "S": "Channel Slope S",
        "n": "Manning’s n",
        "b": "Bottom Width b (m)"
    }[varied])
    plt.ylabel("Normal Depth y (m)")
    plt.title(f"Effect of {varied.upper()} on Normal Depth (Q = {Q:.1f} m³/s)")
    plt.grid(True, linestyle="--", alpha=0.6)
    plt.tight_layout()
    plt.show()

# --- Link UI ---
ui = widgets.VBox([
    param_dropdown,
    range_slider,
    Q_slider,
    b_slider,
    z_slider,
    n_slider,
    S_slider
])

out = widgets.interactive_output(update_plot, {
    "varied": param_dropdown,
    "param_range": range_slider,
    "Q": Q_slider,
    "b": b_slider,
    "z": z_slider,
    "n": n_slider,
    "S": S_slider
})

display(ui, out)

3. Self-Assessment#

Conceptual Questions#

  1. Why is the Manning equation nonlinear in depth ( y ) when applied to trapezoidal channels?
    Hint: Consider how area and hydraulic radius are both functions of depth.

  2. Explain the significance of normal depth in channel design. What practical decisions does it influence?

  3. What happens to normal depth if:

    • The channel slope is increased?

    • The roughness coefficient is doubled?

    • The side slope becomes steeper (e.g., z goes from 1 to 2)?

  4. Why do we solve for normal depth using an iterative approach like the bisection method instead of algebraic rearrangement?

  5. When might uniform flow (and therefore normal depth) not be a valid assumption in real channels?


Reflection Prompts#

  1. Which parameter—bottom width, side slope, slope, or roughness—did you find had the most dramatic effect on normal depth? Why do you think that is?

  2. If you were designing a canal for irrigation, what tradeoffs would you consider when selecting side slopes and roughness materials (e.g., grass, concrete, riprap)?

  3. How would you explain normal depth to someone unfamiliar with hydraulic principles using a physical analogy or visual metaphor?

  4. Suppose your calculated normal depth is very close to the top of the channel. What concerns might that raise for long-term operation?


✅ Quiz: Check Your Understanding#

Q1. In Manning’s equation, what does the term ( R^{2/3} \sqrt{S} ) represent?
A. Channel slope only
B. Flow velocity component
C. Hydraulic depth
D. Frictional resistance
🟢 Correct Answer: B


Q2. Which change will generally increase the normal depth for a given discharge?
A. Decreasing slope
B. Increasing bottom width
C. Using a smoother surface (lower \(( n \)))
D. Decreasing side slope \(( z \))
🟢 Correct Answer: A


Q3. What is the hydraulic radius \(( R \)) defined as?
A. \(( A \cdot n \cdot \sqrt{S} \))
B. \(( A / y \))
C. \(( A / P \))
D. \(( P / A \))
🟢 Correct Answer: C


Q4. The side slope \(( z = 2 \)) represents:
A. A vertical wall
B. A 2:1 horizontal-to-vertical slope
C. A trapezoidal channel with 2 m bottom width
D. None of the above
🟢 Correct Answer: B


🧪 Try This#

  • Set the discharge to 20 m³/s and explore the impact of increasing Manning’s ( n ) from 0.015 to 0.04.
    What happens to the required normal depth?

  • Fix all parameters and vary side slope ( z ) between 0.5 and 4.0.
    Why does depth increase as the slope flattens (larger ( z ))?


4. Introduction#

Interactive Critical Depth Calculator for Open Channel Flow#

This notebook provides a versatile, geometry-adaptive tool for estimating the critical depth ( y_c ) in open channel flow across three channel types:

  • Rectangular

  • Trapezoidal

  • Triangular

Critical depth is the depth at which specific energy is minimized for a given discharge, marking the transition between subcritical and supercritical flow regimes. Accurately identifying this depth is vital for open channel design, hydraulic jumps, and flow control structures.


🧮 Governing Equation#

For steady, uniform flow, critical depth is found by solving: $\( Q = A(y_c) \cdot \sqrt{g \cdot \frac{A(y_c)}{T(y_c)}} \)$ Where:

  • ( Q ): Discharge (m³/s)

  • ( A ): Cross-sectional area

  • ( T ): Top width

  • ( g ): Acceleration due to gravity

  • ( y_c ): Critical depth (m) This equation is nonlinear and is solved numerically using the bisection method.


🎛 Geometry and Inputs#


This tool handles three channel geometries:

Geometry

Parameters

Rectangular

Bottom width ( b )

Trapezoidal

Bottom width ( b ), side slope ( z )

Triangular

Side slope ( z )

You can interactively adjust:

  • Discharge ( Q )

  • Bottom width ( b ) (if applicable)

  • Side slope ( z ) (if applicable)

  • Channel shape via dropdown menu


📊 Output Visualization#

The plot displays the Specific Energy Curve: $\( E = y + \frac{V^2}{2g} \)\( Where \)( V = Q / A $) is the flow velocity.

The tool marks the computed critical depth ( y_c ) on the energy curve, highlighting the energy minimum point.


Applications#

  • Channel transitions and control sections

  • Weir and sluice gate design

  • Flood routing and natural stream assessment

  • Educational visualization of flow regimes

5. Simulation: Critical_Depths#

import numpy as np
from scipy.optimize import root_scalar
from ipywidgets import interact, FloatSlider, Dropdown

g = 9.81  # Acceleration due to gravity (m/s²)

# --- Geometry Functions ---
def area_rect(b, y): return b * y
def top_width_rect(b): return b

def area_trap(b, y, z): return y * (b + z * y)
def top_width_trap(b, y, z): return b + 2 * z * y

def area_tri(y, z): return 0.5 * z * y**2
def top_width_tri(y, z): return z * y

def area_circ(r, y): return np.pi * y * (r - y / 2)
def top_width_circ(r, y):
    term = r * y - y**2 / 4
    return 2 * np.sqrt(term) if term > 0 else np.nan

def area_parab(y, z): return z * y**2
def top_width_parab(y, z): return 2 * z * y

# --- Solve Critical Depth ---
def solve_critical_depth(geom, Q, b=1, z=1, r=1):
    def eqn(y):
        if y <= 0:
            return np.inf
        if geom == "Rectangular":
            A = area_rect(b, y)
            T = top_width_rect(b)
        elif geom == "Trapezoidal":
            A = area_trap(b, y, z)
            T = top_width_trap(b, y, z)
        elif geom == "Triangular":
            A = area_tri(y, z)
            T = top_width_tri(y, z)
        elif geom == "Circular":
            A = area_circ(r, y)
            T = top_width_circ(r, y)
            if np.isnan(T): return np.inf
        elif geom == "Parabolic":
            A = area_parab(y, z)
            T = top_width_parab(y, z)
        D = A / T
        return A * np.sqrt(g * D) - Q

    y_max = 2 * r * 0.999 if geom == "Circular" else 50
    f_lo = eqn(1e-3)
    f_hi = eqn(y_max)

    if np.sign(f_lo) == np.sign(f_hi):
        return np.nan  # No root in range

    sol = root_scalar(eqn, bracket=[1e-3, y_max], method='bisect')
    return sol.root if sol.converged else np.nan

# --- Output Logic ---
def calculate_critical_depth(geometry, Q, b, z, r):
    y_c = solve_critical_depth(geometry, Q, b, z, r)

    print(f"⚙️ Geometry: {geometry}")
    print(f"🌊 Discharge Q = {Q:.2f} m³/s")
    if geometry not in ["Triangular", "Circular", "Parabolic"]:
        print(f"📏 Bottom Width b = {b:.2f} m")
    if geometry not in ["Rectangular", "Circular", "Parabolic"]:
        print(f"📐 Side Slope z = {z:.2f} H:1V")
    if geometry == "Circular":
        print(f"🔵 Radius r = {r:.2f} m")

    if np.isnan(y_c):
        print("❌ Unable to compute critical depth.")
        print("   Try adjusting discharge or geometry.")
    else:
        print(f"✅ Critical Depth yₛ = {y_c:.3f} m")

# --- Interactive Controls ---
interact(
    calculate_critical_depth,
    geometry=Dropdown(
        options=["Rectangular", "Trapezoidal", "Triangular", "Circular", "Parabolic"],
        value="Rectangular",
        description="Geometry:"
    ),
    Q=FloatSlider(value=5, min=0.1, max=50, step=0.5, description="Discharge Q"),
    b=FloatSlider(value=2, min=0.1, max=10, step=0.1, description="Width b (m)"),
    z=FloatSlider(value=1, min=0.0, max=4.0, step=0.1, description="Side Slope z"),
    r=FloatSlider(value=1, min=0.1, max=5, step=0.1, description="Radius r (m)")
)
<function __main__.calculate_critical_depth(geometry, Q, b, z, r)>

6. Self-Assessment#

Conceptual Questions#

  1. What is critical depth, and how is it different from normal depth in open channel flow?

  2. Why does a unique critical depth exist for a given discharge and channel geometry? What physical condition defines it?

  3. Explain how critical depth relates to specific energy. What does the specific energy diagram look like near the critical point?

  4. How does the top width of a channel (T) influence the critical depth for a given discharge?

  5. Why can’t the critical depth in a circular conduit exceed the pipe diameter?


Reflective Questions#

  1. Try increasing discharge for a rectangular channel. How does this affect the critical depth? Why?

  2. If you were designing a culvert, why might it be important to know the critical depth inside the pipe?

  3. Which parameter—bottom width, side slope, or pipe radius—had the most sensitive impact on critical depth in your explorations?

  4. Describe a real-world situation where incorrectly estimating critical depth could cause hydraulic design failure.

  5. How would you explain the concept of critical depth to someone using a visual analogy (e.g., a river, bathtub, or funnel)?


Self-Check Quiz#

Q1. In open channel flow, critical depth is the depth at which:
A. Velocity is maximum
B. Discharge is minimum
C. Specific energy is minimized
D. Friction is zero
🟢 Answer: C


Q2. For a circular pipe, critical depth must be:
A. Greater than the pipe diameter
B. Equal to twice the radius
C. Less than the diameter
D. Unaffected by discharge
🟢 Answer: C


Q3. If a channel has high velocity and shallow depth, it is most likely:
A. At critical flow
B. In supercritical flow
C. In subcritical flow
D. Flowing uphill
🟢 Answer: B


Q4. Which of the following affects hydraulic depth ( D = A/T )?
A. Flow rate
B. Channel slope
C. Shape and depth of the channel
D. Gravity alone
🟢 Answer: C


Q5. Why do we solve for critical depth numerically using methods like bisection?
A. The equations are exponential
B. Hydraulic depth is constant
C. It’s an implicit equation with no closed form
D. It’s computationally easier
🟢 Answer: C

6. Simulation: Mannings coefficient#

import numpy as np
import ipywidgets as widgets
from IPython.display import display, clear_output

g = 9.81  # gravitational acceleration

# --- Method 1: Solve for Manning's n ---
def mannings_n_from_flow(Q, A, R, S):
    return (A * R**(2/3) * S**0.5) / Q

# --- Method 2: Lookup roughness based on surface
def mannings_n_lookup(surface_type):
    surface_table = {
        "Concrete (smooth)": 0.012,
        "Concrete (rough)": 0.017,
        "Earth (clean, straight)": 0.018,
        "Earth (weedy, winding)": 0.030,
        "Gravel-bed stream": 0.035,
        "Natural stream (clean)": 0.030,
        "Natural stream (stony)": 0.040,
        "Dense vegetation": 0.050
    }
    return surface_table.get(surface_type, None)

# --- Method 3: Cowan’s Equation
def mannings_n_cowan(n0, n1, n2, n3, n4):
    return n0 * (1 + n1 + n2 + n3 + n4)

# --- Output handler
def update_estimates(Q, A, R, S, surface_type, n0, n1, n2, n3, n4):
    clear_output(wait=True)

    print("🧮 Manning’s Roughness Estimation")
    print("–––––––––––––––––––––––––––––––––––––––––")

    # Method 1
    n_flow = mannings_n_from_flow(Q, A, R, S)
    print(f"1️⃣ From Manning's equation: n = {n_flow:.4f}")

    # Method 2
    n_lookup = mannings_n_lookup(surface_type)
    print(f"2️⃣ Empirical lookup (\"{surface_type}\"): n = {n_lookup:.4f}")

    # Method 3
    n_cowan = mannings_n_cowan(n0, n1, n2, n3, n4)
    print(f"3️⃣ Cowan’s composite estimate: n = {n_cowan:.4f}")

# --- Widget controls
Q_slider = widgets.FloatSlider(value=5, min=0.1, max=50, step=0.5, description="Q (m³/s)")
A_slider = widgets.FloatSlider(value=2.0, min=0.1, max=20, step=0.1, description="Area A (m²)")
R_slider = widgets.FloatSlider(value=0.5, min=0.01, max=2.0, step=0.01, description="Hydraulic Radius R (m)")
S_slider = widgets.FloatSlider(value=0.001, min=0.0001, max=0.01, step=0.0001, description="Slope S", readout_format=".4f")

surface_dropdown = widgets.Dropdown(
    options=[
        "Concrete (smooth)", "Concrete (rough)",
        "Earth (clean, straight)", "Earth (weedy, winding)",
        "Gravel-bed stream", "Natural stream (clean)",
        "Natural stream (stony)", "Dense vegetation"
    ],
    value="Natural stream (clean)",
    description="Surface Type"
)

n0_slider = widgets.FloatSlider(value=0.022, min=0.01, max=0.05, step=0.001, description="Base n₀")
n1_slider = widgets.FloatSlider(value=0.1, min=0, max=0.4, step=0.01, description="n₁: Irregularity")
n2_slider = widgets.FloatSlider(value=0.1, min=0, max=0.4, step=0.01, description="n₂: Cross-section")
n3_slider = widgets.FloatSlider(value=0.1, min=0, max=0.4, step=0.01, description="n₃: Obstructions")
n4_slider = widgets.FloatSlider(value=0.1, min=0, max=0.4, step=0.01, description="n₄: Vegetation")

ui = widgets.VBox([
    Q_slider, A_slider, R_slider, S_slider,
    surface_dropdown,
    n0_slider, n1_slider, n2_slider, n3_slider, n4_slider
])

out = widgets.interactive_output(update_estimates, {
    'Q': Q_slider, 'A': A_slider, 'R': R_slider, 'S': S_slider,
    'surface_type': surface_dropdown,
    'n0': n0_slider, 'n1': n1_slider,
    'n2': n2_slider, 'n3': n3_slider, 'n4': n4_slider
})

display(ui, out)

7. Self-Assessment: Mannings Coeff.#

Interactive Manning’s Roughness Estimator#

This interactive tool enables users to estimate the Manning’s roughness coefficient ( n ) using three different methods: numerical calculation from flow data, empirical lookup based on channel material, and Cowan’s composite method. This is especially useful in hydrology and open channel flow design.


🧮 What Is Manning’s Roughness?#

Manning’s ( n ) is a dimensionless coefficient that quantifies the frictional resistance to flow in open channels. It depends on channel material, shape, vegetation, obstructions, and surface irregularities.


📐 Methods Available#

1️⃣ From Flow Measurements#

Rearranged Manning’s equation: $\( n = \frac{A \cdot R^{2/3} \cdot \sqrt{S}}{Q} \)$ Where:

  • ( Q ): discharge [m³/s]

  • ( A ): cross-sectional area of flow [m²]

  • ( R ): hydraulic radius (A/P) [m]

  • ( S ): slope of the energy grade line (dimensionless) Use this method when real-world measurements of flow and geometry are available.


2️⃣ Empirical Lookup Table#

Select a channel surface type from a predefined dropdown to retrieve standard ( n ) values commonly used in engineering design based on published tables.

Examples:

Surface Type

Typical n

Concrete (smooth)

0.012

Earth (weedy, winding)

0.030

Natural stream (stony)

0.040

Dense vegetation

0.050

3️⃣ Cowan’s Method (Composite Estimate) Cowan’s empirical formula:

\[ n = n_0 \cdot (1 + n_1 + n_2 + n_3 + n_4) \]

Where:

  • ( n_0 ): base roughness for the material

  • ( n_1 ): surface irregularity correction

  • ( n_2 ): cross-sectional shape

  • ( n_3 ): obstructions like logs or piers

  • ( n_4 ): vegetation growth or alignment variation

Use this method for natural channels with diverse characteristics.#


🎛 Interactive Controls#

  • Flow parameters: discharge ( Q ), area ( A ), radius ( R ), slope ( S )

  • Dropdown: select channel surface for empirical ( n )

  • Sliders: adjust Cowan’s modifiers for vegetation, obstructions, shape, etc.


✅ Output#

The tool prints three estimates side-by-side to encourage comparison and judgment:

  • Estimated ( n ) from measured or assumed conditions

  • Roughness from reference tables

  • Composite Cowan’s ( n ) based on detailed channel descriptors

💡 Tip: Use this tool to calibrate models, check assumptions in hydraulic design, or teach roughness estimation in open channel hydraulics.