Chapter 3 Hydraulics: GVF profile#

  1. Introduction: Gradually Varied Flow

  2. Simulation: Direct Step method

  3. Simulation: Standard Step Method

  4. Simulation: GVF Profile

  5. Self-Assessment

1. Introduction#

🌊 Gradually Varied Flow (GVF)#

Gradually Varied Flow (GVF) refers to non-uniform flow in open channels where the depth of water changes slowly over a long distance. Unlike uniform flow (constant depth) or rapidly varied flow (abrupt changes), GVF occurs when flow adjusts gradually due to changes in slope, channel geometry, or boundary conditions.

Mathematically, GVF is governed by the one-dimensional steady flow equation: $\( \frac{dy}{dx} = \frac{S_0 - S_f}{1 - Fr^2} \)$ Where:

  • \(( y \)): flow depth

  • \(( x \)): longitudinal distance

  • \(( S_0 \)): bed slope

  • \(( S_f \)): friction slope

  • \(( Fr \)): Froude number


📐 Importance of GVF in Hydraulic Engineering#

Application Area

Why GVF Matters

Channel Design

Determines water surface profiles and required freeboard

Floodplain Mapping

Predicts inundation extents and backwater effects

Bridge and Culvert Sizing

Ensures accurate headwater and tailwater elevations

Reservoir and Weir Analysis

Models flow transitions and control sections

Environmental Flow Studies

Assesses habitat conditions and flow depth variability

Hydraulic Modeling Tools

Used in HEC-RAS, SWMM, and other open-channel simulation software


🔍 Flow Profile Types in GVF#

  • M1, M2, M3: Mild slope profiles

  • S1, S2, S3: Steep slope profiles

  • C1, C2, C3: Critical slope profiles

  • Each profile type reflects how flow depth compares to normal and critical depth


🧠 Conceptual Insight#

Gradually varied flow is the realistic flow condition in most natural and engineered channels.
Understanding GVF is essential for predicting water surface elevations, designing safe infrastructure,
and managing flood risks.


🌊 Solving Gradually Varied Flow (GVF) Profiles#

Gradually Varied Flow (GVF) occurs when flow depth changes slowly along the channel due to changes in slope, geometry, or boundary conditions. GVF profiles are solved using one of three main methods:


📘 Overview of GVF Solution Methods#

Method

Applicability

What It Solves

Channel Type

Direct Integration

Analytical (limited cases)

Depth as a function of distance

Simple prismatic

Direct Step Method

Numerical

Distance between two known depths

Prismatic channels

Standard Step Method

Numerical

Depth at a given location

Natural/irregular


📐 1. Direct Integration Method#

✅ Applicability#

  • Only for simple prismatic channels with known analytical expressions

  • Assumes friction slope \(( S_f \)) is a function of depth

🔣 Governing Equation#

\[ \frac{dy}{dx} = \frac{S_0 - S_f(y)}{1 - Fr^2} \]

🧮 Solution Steps#

  1. Express \(( S_f \)) and \(( Fr \)) as functions of \(( y \))

  2. Rearrange and integrate: $\( x = \int_{y_1}^{y_2} \frac{1 - Fr^2}{S_0 - S_f(y)} \, dy \)$

  3. Solve analytically or numerically


📐 2. Direct Step Method#

✅ Applicability#

  • Prismatic channels with constant cross-section

  • Used to compute distance between two known depths

🔣 Energy Equation#

\[ \Delta x = \frac{E_2 - E_1}{S_0 - \bar{S_f}} \]

Where:

  • \(( E = y + \frac{V^2}{2g} \)): specific energy

  • \(( \bar{S_f} \)): average friction slope between two sections

🧮 Solution Steps#

  1. Choose two depths \(( y_1 \)) and \(( y_2 \))

  2. Compute velocities \(( V_1, V_2 \)) and energies \(( E_1, E_2 \))

  3. Calculate friction slopes \(( S_{f1}, S_{f2} \))

  4. Compute average slope \(( \bar{S_f} = \frac{S_{f1} + S_{f2}}{2} \))

  5. Solve for \(( \Delta x \))

Applications#

Scenario

Why Use Direct Step Method

Channel Transitions

To find length needed between two depth control points

Backwater Profile Analysis

For flow upstream of dams, weirs, or sluice gates

Subcritical Flow Evaluation

Common in mild slope channels and canals

Flood Routing

Estimate water surface elevation changes with distance


Advantages#

  • Simple and direct for prismatic channels

  • Efficient for computing the profile segment between fixed depths

  • Compatible with manual or spreadsheet implementation


📐 3. Standard Step Method#

✅ Applicability#

  • Natural channels with varying geometry

  • Used to compute depth at a given location

Applications of GVF Using Standard Step Method#

Application

Use Case

River Backwater Analysis

Determine upstream impacts due to dam or obstruction

Channel Design

Predict water surface elevation profile for canal slopes

Floodplain Mapping

Simulate elevated flow profiles for flood risk zones

Hydraulic Jump Location

Identify where critical transitions occur

Irrigation and Drainage Modeling

Optimize slope and depth profiles for efficient flow

Stormwater Infrastructure

Analyze detention basin outflow and flow depth variations

🔣 Energy Equation#

\[ E_1 + z_1 = E_2 + z_2 + h_L \]

Where:

  • \(( E = y + \frac{V^2}{2g} \)): specific energy

  • \(( z \)): bed elevation

  • \(( h_L = \bar{S_f} \cdot \Delta x \)): head loss due to friction

🧮 Solution Steps#

  1. Assume downstream depth \(( y_2 \))

  2. Compute velocity \(( V_2 \)), energy \(( E_2 \))

  3. Estimate upstream depth \(( y_1 \))

  4. Compute \(( V_1, E_1 \)), and head loss \(( h_L \))

  5. Check energy balance: $\( E_1 + z_1 \overset{?}{=} E_2 + z_2 + h_L \)$

  6. Iterate until energy equation is satisfied


🧠 Conceptual Insight#

Each method offers a different approach to solving GVF profiles depending on channel complexity, available data, and modeling goals.
Direct Step is efficient for uniform channels, while Standard Step handles real-world variability.


References#

[Chow, 1959] provides fundamental theory discussing the derivation of the GVF equation, classification of flow profiles (M1, S2, etc.), Assumptions (hydrostatic pressure, prismatic channels, steady flow), and Methods (direct-step, standard-step, graphical integration).[Chanson, 2004] building on the classical approach by [Chow, 1959], provides a detailed and modern treatment of Gradually Varied Flow (GVF) (e..g, momentum and energy correction factor, non-prismatic channel, variable roughness, computational modeling insight)

2. Simulation#

🌊 Direct Step Method – GVF Simulation Tool#

This interactive tool estimates the distance required for flow to transition between two depths in a rectangular open channel using the Direct Step Method. It also computes normal depth, critical depth, and classifies the slope type.


✅ What the Code Does#

Component

Description

Normal Depth

Solves Manning’s equation iteratively to find depth for given flow

Critical Depth

Uses analytical formula for rectangular channels

Slope Classification

Compares normal and critical depth to classify slope as mild, steep, or critical

Direct Step Method

Computes distance between starting and target depths using energy balance

Interactive Controls

Sliders for flow, channel width, Manning’s n, slope, and depth inputs

Output Summary

Displays slope type, depths, flow direction, and estimated distance


▶️ How It Works#

  • Normal Depth:
    Iteratively solves Manning’s equation: $\( Q = \frac{1}{n} A R^{2/3} S_0^{1/2} \)$

  • Critical Depth:
    Uses: $\( h_c = \left( \frac{Q^2}{b^2 g} \right)^{1/3} \)$

  • Direct Step Method:
    Applies energy equation: $\( \Delta x = \frac{E_2 - E_1}{S_0 - \bar{S_f}} \)\( where \)( E = y + \frac{V^2}{2g} $)

  • Flow Direction:
    Determined based on slope type and depth transition


📊 How to Interpret the Results#

  • Slope Type:

    • Mild: ( h_n > h_c )

    • Steep: ( h_n < h_c )

    • Critical: ( h_n = h_c )

  • Flow Direction:
    Indicates whether flow transitions upstream or downstream

  • Estimated Distance:
    Length of channel required for flow to adjust from starting to target depth

  • Use Cases:

    • Channel design

    • Backwater profile estimation

    • Hydraulic structure placement


🧠 Conceptual Insight#

The Direct Step Method links flow depth changes to energy gradients,
helping engineers design channels that safely convey water under varying conditions.

# Direct step method
import numpy as np
import ipywidgets as widgets
from IPython.display import display, clear_output
from ipywidgets import interact

# 📐 Manning's equation for normal depth (rectangular channel)
def compute_normal_depth(Q, b, n, So):
    def area(h): return b * h
    def perimeter(h): return b + 2 * h
    def hydraulic_radius(h): return area(h) / perimeter(h)
    def velocity(h): return (1 / n) * hydraulic_radius(h)**(2/3) * So**0.5
    def discharge(h): return velocity(h) * area(h)

    h = 0.1
    for _ in range(1000):
        f = discharge(h) - Q
        df = (discharge(h + 0.001) - discharge(h)) / 0.001
        h_new = h - f / df
        if abs(h_new - h) < 1e-6:
            break
        h = h_new
    return round(h, 3)

# 📐 Critical depth for rectangular channel
def compute_critical_depth(Q, b):
    g = 9.81
    h = (Q**2 / b**2 / g)**(1/3)
    return round(h, 3)

# 🧮 Direct Step Method to find distance to target depth
def direct_step(Q, b, n, So, h_start, h_target, steps=100):
    g = 9.81
    dx_total = 0
    direction = "downstream" if h_target < h_start else "upstream"
    h = h_start
    dh = (h_target - h_start) / steps

    for _ in range(steps):
        A = b * h
        P = b + 2 * h
        R = A / P
        V = Q / A
        E = h + V**2 / (2 * g)
        Sf = (V * n / R**(2/3))**2
        dx = dh / (So - Sf) if So != Sf else 0
        dx_total += abs(dx)
        h += dh

    return round(dx_total, 1), direction

# 🌊 Main function
def simulate_gvf(Q, b, n, So, h_start, h_target):
    clear_output(wait=True)

    h_normal = compute_normal_depth(Q, b, n, So)
    h_critical = compute_critical_depth(Q, b)

    # 🔍 Classify slope
    slope_type = "Steep" if h_normal < h_critical else "Mild" if h_normal > h_critical else "Critical"

    # 🔁 Decide direction based on slope and flow regime
    if slope_type == "Mild":
        direction = "upstream" if h_target > h_normal else "downstream"
    elif slope_type == "Steep":
        direction = "downstream" if h_target < h_normal else "upstream"
    else:
        direction = "downstream"  # assume normal depth flows downstream

    # 🧮 Compute distance
    dx, flow_dir = direct_step(Q, b, n, So, h_start, h_target)

    # 📋 Output
    print(f"🔎 Slope Type: {slope_type}")
    print(f"📐 Normal Depth: {h_normal:.3f} m")
    print(f"📐 Critical Depth: {h_critical:.3f} m")
    print(f"📍 Starting Depth: {h_start:.3f} m")
    print(f"🎯 Target Depth: {h_target:.3f} m")
    print(f"🧭 Flow Direction: {flow_dir}")
    print(f"📏 Estimated Distance to Target Depth: {dx:.1f} m")

# 🎛️ Interactive controls
style = {'description_width': '160px'}
layout = widgets.Layout(width='400px')

interact(simulate_gvf,
         Q=widgets.FloatSlider(value=20, min=1, max=100, step=1, description='Flow Q (m³/s)', style=style, layout=layout),
         b=widgets.FloatSlider(value=5, min=1, max=20, step=0.5, description='Channel Width (m)', style=style, layout=layout),
         n=widgets.FloatSlider(value=0.03, min=0.01, max=0.06, step=0.001, description='Manning n', style=style, layout=layout),
         So=widgets.FloatSlider(value=0.001, min=0.0001, max=0.01, step=0.0001, description='Bed Slope S₀', style=style, layout=layout),
         h_start=widgets.FloatSlider(value=2.5, min=0.5, max=6.0, step=0.1, description='Starting Depth (m)', style=style, layout=layout),
         h_target=widgets.FloatSlider(value=1.5, min=0.5, max=6.0, step=0.1, description='Target Depth (m)', style=style, layout=layout));

3. Simulation#

🌊 Standard Step Method – Depth Estimation Tool#

This interactive tool estimates the flow depth at a specified distance along a rectangular open channel using the Standard Step Method, simulating gradually varied flow (GVF).


✅ What the Code Does#

Component

Description

Depth Estimation

Computes flow depth at a target location using energy balance

Hydraulic Parameters

Calculates area, velocity, hydraulic radius, energy, and friction slope

Energy Equation

Applies: ( \Delta x = \frac{E_2 - E_1}{S_0 - \bar{S_f}} )

Interactive Inputs

Sliders for flow rate, channel width, slope, Manning’s n, start depth, distance, and direction

Output

Displays estimated depth and flow direction at the specified location


▶️ How It Works#

  • Iteratively adjusts depth in the specified direction (upstream/downstream)

  • Computes energy and friction slope at each step

  • Accumulates distance until target is reached

  • Returns final depth estimate


📊 How to Interpret the Result#

Output Parameter

Meaning

Estimated Depth

Flow depth at the specified distance

Direction

Indicates whether flow is simulated upstream or downstream

Use Cases

Channel design, backwater analysis, hydraulic structure placement


🧠 Conceptual Insight#

The Standard Step Method models how flow depth evolves along a channel,
helping engineers design safe and efficient hydraulic systems under non-uniform flow conditions.

import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import FloatSlider, IntSlider, interact

g = 9.81  # gravitational acceleration (m/s²)

# ⚙️ Rectangular channel hydraulics
def area(h, b): return b * h
def wetted_perimeter(h, b): return b + 2 * h
def hydraulic_radius(h, b): return area(h, b) / wetted_perimeter(h, b)
def velocity(h, b, Q): return Q / area(h, b)
def manning_slope(h, b, Q, n): return (Q * n / (area(h, b) * hydraulic_radius(h, b)**(2/3)))**2
def energy(h, b, Q): return h + velocity(h, b, Q)**2 / (2 * g)

# 📍 Compute depth at specified distance using standard step method
def compute_depth_at_distance(Q, b, So, n, h_start, distance_target, direction='upstream', dx=5):
    h = h_start
    x = 0

    while x < distance_target:
        h_trial = h + 0.1 if direction == 'upstream' else h - 0.1

        Sf1 = manning_slope(h, b, Q, n)
        Sf2 = manning_slope(h_trial, b, Q, n)
        E1 = energy(h, b, Q)
        E2 = energy(h_trial, b, Q)
        delta_E = E2 - E1
        S_avg = (Sf1 + Sf2) / 2

        delta_x = delta_E / (So - S_avg) if (So - S_avg) != 0 else dx
        dx = abs(delta_x)

        h = h_trial
        x += dx

        if x >= distance_target:
            return round(h, 4)

    return round(h, 4)

# 🖱️ Interactive tool
def interactive_depth(Q, b, So, n, h_start, distance, direction):
    depth = compute_depth_at_distance(Q, b, So, n, h_start, distance, direction)
    print(f"📏 Estimated Depth at {distance:.1f} m ({direction}): {depth:.2f} m")

# 🎛️ Sliders
interact(interactive_depth,
         Q=FloatSlider(value=20, min=1, max=100, step=1, description='Flow Q (m³/s)', style={'description_width': '150px'}),
         b=FloatSlider(value=5, min=1, max=20, step=0.5, description='Channel Width (m)', style={'description_width': '150px'}),
         So=FloatSlider(value=0.001, min=0.0001, max=0.01, step=0.0001, description='Bed Slope S₀', style={'description_width': '150px'}),
         n=FloatSlider(value=0.03, min=0.01, max=0.06, step=0.001, description='Manning n', style={'description_width': '150px'}),
         h_start=FloatSlider(value=2.5, min=0.5, max=5.0, step=0.1, description='Start Depth (m)', style={'description_width': '150px'}),
         distance=FloatSlider(value=100, min=1, max=1000, step=5, description='Distance (m)', style={'description_width': '150px'}),
         direction=['upstream', 'downstream']);

4. Simulation#

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

# 📐 Normal depth using Manning’s equation
def compute_normal_depth(Q, b, n, S0):
    def area(h): return b * h
    def perimeter(h): return b + 2 * h
    def hydraulic_radius(h): return area(h) / perimeter(h)
    def velocity(h): return (1 / n) * hydraulic_radius(h)**(2/3) * S0**0.5
    def discharge(h): return velocity(h) * area(h)

    h = 0.1
    for _ in range(1000):
        f = discharge(h) - Q
        df = (discharge(h + 0.001) - discharge(h)) / 0.001
        h_new = h - f / df
        if abs(h_new - h) < 1e-6:
            break
        h = h_new
    return round(h, 3)

# 📐 Critical depth for rectangular channel
def compute_critical_depth(Q, b):
    g = 9.81
    h = (Q**2 / b**2 / g)**(1/3)
    return round(h, 3)

# 🧮 Direct Step Method for GVF
def compute_gvf(Q, b, n, S0, L, steps, h_start, flow_direction):
    g = 9.81
    dx = L / steps
    x = np.zeros(steps)
    h = np.zeros(steps)
    h[0] = h_start

    for i in range(1, steps):
        A = b * h[i-1]
        P = b + 2 * h[i-1]
        R = A / P
        V = Q / A
        Sf = (V * n / R**(2/3))**2
        E = h[i-1] + V**2 / (2 * g)

        dE_dh = 1 + (-Q**2 / (g * A**3)) * (b**2)
        dh = 0.01 if flow_direction == "downstream" else -0.01
        h_trial = h[i-1] + dh
        A_trial = b * h_trial
        V_trial = Q / A_trial
        E_trial = h_trial + V_trial**2 / (2 * g)
        dE = E_trial - E
        dx_step = dE / (S0 - Sf) if S0 != Sf else dx

        x[i] = x[i-1] + abs(dx_step)
        h[i] = h[i-1] + dh

        if x[i] > L:
            x = x[:i+1]
            h = h[:i+1]
            break

    return x, h

# 📊 Plotting function
def plot_gvf(Q, b, n, S0, L, steps, h_start, flow_direction):
    h_normal = compute_normal_depth(Q, b, n, S0)
    h_critical = compute_critical_depth(Q, b)

    # 🧭 Slope classification
    if h_normal > h_critical:
        slope_type = "Mild"
    elif h_normal < h_critical:
        slope_type = "Steep"
    else:
        slope_type = "Critical"

    x, h = compute_gvf(Q, b, n, S0, L, steps, h_start, flow_direction)

    plt.figure(figsize=(10, 4))
    plt.plot(x, h, label="Water Surface Profile", color="blue")
    plt.axhline(h_normal, color="green", linestyle="--", label=f"Normal Depth = {h_normal:.2f} m")
    plt.axhline(h_critical, color="red", linestyle="--", label=f"Critical Depth = {h_critical:.2f} m")
    plt.xlabel("Distance Along Channel (m)")
    plt.ylabel("Water Depth h (m)")
    plt.title(f"GVF Profile — {flow_direction.capitalize()} | Slope Type: {slope_type}")
    plt.grid(True)
    plt.legend()
    plt.tight_layout()
    plt.show()

    print(f"📐 Normal Depth: {h_normal:.2f} m")
    print(f"📐 Critical Depth: {h_critical:.2f} m")
    print(f"🧭 Slope Type: {slope_type}")

# 🎛️ Interactive controls
Q_slider = widgets.FloatSlider(value=20, min=1, max=100, step=1, description='Flow Q (m³/s)')
b_slider = widgets.FloatSlider(value=5, min=1, max=20, step=0.5, description='Channel Width b (m)')
n_slider = widgets.FloatSlider(value=0.03, min=0.01, max=0.06, step=0.001, description='Manning n')
S0_slider = widgets.FloatSlider(value=0.001, min=0.0001, max=0.01, step=0.0001, description='Bed Slope S₀')
L_slider = widgets.FloatSlider(value=100, min=10, max=1000, step=10, description='Channel Length L (m)')
steps_slider = widgets.IntSlider(value=50, min=10, max=200, step=10, description='Steps')
h_start_slider = widgets.FloatSlider(value=2.0, min=0.5, max=6.0, step=0.1, description='Starting Depth h₀ (m)')
direction_dropdown = widgets.Dropdown(options=["upstream", "downstream"], value="downstream", description='Flow Direction')

ui = widgets.VBox([
    Q_slider, b_slider, n_slider, S0_slider,
    L_slider, steps_slider, h_start_slider, direction_dropdown
])

out = widgets.interactive_output(plot_gvf, {
    'Q': Q_slider,
    'b': b_slider,
    'n': n_slider,
    'S0': S0_slider,
    'L': L_slider,
    'steps': steps_slider,
    'h_start': h_start_slider,
    'flow_direction': direction_dropdown
})

display(ui, out)

5. Self-Assessment#

✅ Conceptual Questions#

  1. What does the Direct Step Method compute in GVF analysis?

    • A. Flow velocity at critical depth

    • B. Distance between two flow depths

    • C. Channel slope required for uniform flow

    • D. Hydraulic jump location

  2. In a rectangular channel, the normal depth is determined by:

    • A. Flow rate and critical slope

    • B. Manning’s equation and channel geometry

    • C. Energy equation and tailwater depth

    • D. Froude number and sediment load

  3. If the normal depth is greater than the critical depth, the slope is classified as:

    • A. Steep

    • B. Mild

    • C. Critical

    • D. Horizontal

  4. Which of the following increases the friction slope \(( S_f \))?

    • A. Increasing Manning’s \(( n \))

    • B. Increasing hydraulic radius

    • C. Decreasing velocity

    • D. Reducing bed slope

  5. In GVF analysis, flow direction is determined by:

    • A. Channel curvature

    • B. Depth gradient and slope type

    • C. Sediment transport rate

    • D. Water temperature


Parametric Exploration Prompts#

  1. How does increasing Manning’s \(( n \)) affect the normal depth and flow resistance?

  2. What happens to the estimated distance when the target depth is much lower than the starting depth on a mild slope?

  3. Why is it important to classify the slope type before applying the Direct Step Method?

  4. How would the results differ in a natural channel with variable width and roughness?

  5. What are the limitations of using a fixed step size in the Direct Step Method?


Reflection Questions#

  1. How does the Direct Step Method help visualize flow transitions in open channels?

  2. What physical processes are captured by the gradually varied flow equations that uniform flow neglects?

  3. Why is critical depth a key reference point in classifying flow regimes?

  4. How would you modify this model to handle non-prismatic or compound channels?

  5. What insights can engineers gain by interactively adjusting flow, slope, and depth parameters in real-time?


Design Insight#

“Understanding gradually varied flow is essential for designing channels, culverts, and floodplains. It bridges the gap between idealized uniform flow and real-world hydraulic transitions.”