Chapter 3 Hydraulics: GVF profile#
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#
🧮 Solution Steps#
Express \(( S_f \)) and \(( Fr \)) as functions of \(( y \))
Rearrange and integrate: $\( x = \int_{y_1}^{y_2} \frac{1 - Fr^2}{S_0 - S_f(y)} \, dy \)$
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#
Where:
\(( E = y + \frac{V^2}{2g} \)): specific energy
\(( \bar{S_f} \)): average friction slope between two sections
🧮 Solution Steps#
Choose two depths \(( y_1 \)) and \(( y_2 \))
Compute velocities \(( V_1, V_2 \)) and energies \(( E_1, E_2 \))
Calculate friction slopes \(( S_{f1}, S_{f2} \))
Compute average slope \(( \bar{S_f} = \frac{S_{f1} + S_{f2}}{2} \))
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#
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#
Assume downstream depth \(( y_2 \))
Compute velocity \(( V_2 \)), energy \(( E_2 \))
Estimate upstream depth \(( y_1 \))
Compute \(( V_1, E_1 \)), and head loss \(( h_L \))
Check energy balance: $\( E_1 + z_1 \overset{?}{=} E_2 + z_2 + h_L \)$
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 downstreamEstimated Distance:
Length of channel required for flow to adjust from starting to target depthUse 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#
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
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
If the normal depth is greater than the critical depth, the slope is classified as:
A. Steep
B. Mild
C. Critical
D. Horizontal
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
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#
How does increasing Manning’s \(( n \)) affect the normal depth and flow resistance?
What happens to the estimated distance when the target depth is much lower than the starting depth on a mild slope?
Why is it important to classify the slope type before applying the Direct Step Method?
How would the results differ in a natural channel with variable width and roughness?
What are the limitations of using a fixed step size in the Direct Step Method?
Reflection Questions#
How does the Direct Step Method help visualize flow transitions in open channels?
What physical processes are captured by the gradually varied flow equations that uniform flow neglects?
Why is critical depth a key reference point in classifying flow regimes?
How would you modify this model to handle non-prismatic or compound channels?
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.”