Standard Step 1D Solver

Overview

The standard step 1D solver performs steady-state water surface profile computations for open channel flow.

Theory

The standard step (normal depth) method solves the energy equation:

\[z_1 + \frac{V_1^2}{2g} = z_2 + \frac{V_2^2}{2g} + h_f\]

Where:

  • \(z\) = channel bed elevation

  • \(V\) = velocity

  • \(g\) = gravitational acceleration

  • \(h_f\) = friction loss

Assumptions

  • Quasi-steady flow

  • Hydrostatic pressure

  • Negligible channel curvature

  • Uniform cross-section properties

Limitations

  • Not suitable for rapidly varying flow (use unsteady for that)

  • Assumes single-valued water surface (not valid in hydraulic jumps)

  • Requires regular cross-section spacing for accuracy

Key Parameters

Discharge (Q)

Flow rate in cubic feet per second (cfs)

Manning’s Roughness (n)

Friction coefficient. Typical values:

  • Smooth concrete: 0.012-0.015

  • Natural channels: 0.025-0.035

  • Rough/vegetated: 0.035-0.050

Cross-section Station

Distance along channel centerline

Elevation

Channel bed elevation (relative datum)

Coordinates

Cross-section geometry as (x, z) pairs

Using the Solver

Python API

from pyhnhtools import load_input, run_backwater

# Load model
model = load_input('model.json')

# Run solver
results = run_backwater(model)

# Access results
profile = results.wse  # Water surface elevation
velocity = results.velocity

GUI Interface

  1. Load or create model

  2. Set discharge and Manning’s n

  3. Add cross-sections

  4. Click “Run Solver”

  5. View profile plots and results table

Model Requirements

Minimum model needs:

  • 2+ cross-sections

  • Discharge > 0

  • Manning’s n in reasonable range (0.02-0.08)

  • Cross-section coordinates defining geometry

Interpreting Results

Water Surface Elevation (WSE)

Elevation of water surface at each section

Velocity

Average cross-section velocity

Depth

WSE - channel bed elevation

Froude Number

\(Fr = V / \sqrt{g*d}\)

  • Fr < 1: Subcritical flow

  • Fr > 1: Supercritical flow

  • Fr ≈ 1: Critical flow

Friction Slope

\(S_f = (n^2 * V^2) / (R^{2/3})\)

Workflow

Step 1: Prepare Geometry

Gather surveyed cross-sections or extract from HEC-RAS:

{
  "reach_name": "Example Reach",
  "discharge": 500,
  "manning_n": 0.035,
  "cross_sections": [
    {
      "station": 0.0,
      "elevation": 100.0,
      "coordinates": [[0, 100], [10, 105], [20, 100]]
    }
  ]
}

Step 2: Set Boundary Conditions

  • Upstream: Discharge

  • Downstream: Elevation or stage (for subcritical)

Step 3: Run Analysis

Execute solver via GUI or API

Step 4: Review Results

  • Check plot reasonableness

  • Verify no unstable solutions

  • Compare to field observations if available

Step 5: Sensitivity Analysis (optional)

Run with varying Manning’s n or discharge to understand sensitivity

Troubleshooting

No Solution Found

Check:

  • Manning’s n reasonable (0.02-0.08)

  • Cross-sections properly ordered

  • Discharge and geometry consistent

Unrealistic Profile

Verify:

  • Cross-section coordinates correct

  • Elevations in consistent units

  • Channel geometry reasonable

Solver Won’t Converge

Try:

  • Reduce discharge

  • Increase Manning’s n slightly

  • Add more cross-sections

  • Check for data errors

Advanced Topics

Compound Channels

Use high Manning’s n for floodplain areas:

"cross_sections": [
  {
    "station": 0.0,
    "elevation": 100.0,
    "coordinates": [[0, 100], [5, 103], [10, 105], [15, 103], [20, 100]],
    "manning_n": [0.035, 0.035, 0.04, 0.035, 0.035]
  }
]

Reach Subdivision

For accuracy with variable geometry, use small station increments (e.g., 50 feet)

Calibration

Adjust Manning’s n to match observed water surfaces:

# Try different Manning's n values
for n in [0.030, 0.035, 0.040]:
    model.manning_n = n
    results = run_backwater(model)
    # Compare results.wse to observed WSE

Examples

Simple Trapezoidal Channel

from pyhnhtools import load_input, run_backwater

model = load_input('trapezoid_channel.json')
results = run_backwater(model)

print(f"Water surface range: {min(results.wse):.2f} - {max(results.wse):.2f}")
print(f"Velocity range: {min(results.velocity):.2f} - {max(results.velocity):.2f}")

Batch Analysis

# Run for multiple discharges
for Q in [100, 250, 500, 1000]:
    model.discharge = Q
    results = run_backwater(model)
    print(f"Q={Q}: WSE={results.wse[0]:.2f}")

See Also