River Water-Quality Modelling: The Oxygen Sag

Predicting what a discharge does to a river. Learn deoxygenation and reaeration, the Streeter–Phelps model, the dissolved-oxygen sag curve, critical time and deficit, reaeration formulas (O'Connor–Dobbins), temperature correction, nutrients and eutrophication, and modern models (QUAL2K, WASP) — with Python computing a DO sag.

When organic waste enters a river, bacteria consume oxygen while degrading it, and the atmosphere slowly replenishes oxygen through the surface. The balance produces a characteristic 'sag': oxygen falls downstream, reaches a minimum, and then recovers.

The Streeter–Phelps model (1925, Ohio River) was the first mathematical water-quality model and is still used to set discharge limits and protect aquatic life.

An analogy

The oxygen sag is like a bank account with a large one-off bill (BOD) and a steady salary (reaeration): the balance dips, hits a low point, and then recovers as the salary keeps coming in.

Two competing processes

Deoxygenation: bacteria consume oxygen at a rate proportional to remaining BOD (k_d L). Reaeration: oxygen dissolves from the air at a rate proportional to the deficit (k_a D). Fast, shallow, turbulent streams reaerate quickly; slow, deep rivers slowly.

The sag curve

Just below the outfall deoxygenation dominates and DO drops; as BOD is used up and the deficit grows, reaeration catches up. The minimum (critical point) occurs where both rates are equal. Stream zones: degradation, active decomposition, recovery, clean water — each with characteristic organisms.

Using the model for permits

Waste-load allocation: work backwards from the DO standard to the maximum allowable BOD load, usually at critical low-flow (7Q10) and high-temperature conditions. Temperature raises k_d (θ ≈ 1.047) more than k_a (θ ≈ 1.024) and lowers DO_sat — the worst case is a hot, dry summer.

Beyond Streeter–Phelps

Real rivers add nitrogenous BOD, sediment oxygen demand, photosynthesis/respiration (diurnal DO swings), multiple point and non-point sources, and eutrophication dynamics (algae, nutrients). Models like QUAL2K, WASP and MIKE HYDRO simulate these, calibrated with monitoring data. Total maximum daily loads (TMDLs) use them to allocate loads across polluters.

Formulas

Worked example: Reaeration rate

Given: u = 0.3 m/s, H = 2 m

Find: k_a (O'Connor–Dobbins).

Answer: 0.76/day

Worked example: Temperature correction

Given: k_d,20 = 0.35/d, T = 28 °C, θ = 1.047

Find: k_d,28.

Answer: 0.51/day

Worked example: Critical distance

Given: t_c = 1.76 d, u = 0.3 m/s

Find: Distance.

Answer: ≈ 46 km

Streeter–Phelps DO sag

import math
# Streeter-Phelps dissolved-oxygen sag downstream of a discharge
kd, ka = 0.35, 0.70        # deoxygenation and reaeration, 1/day
L0, D0 = 20.0, 1.5         # initial ultimate BOD and deficit, mg/L
DOs = 9.02                 # saturation at 20 C (from the fit above)
u = 0.3 * 86400 / 1000     # river velocity km/day (0.3 m/s)
tc = (1 / (ka - kd)) * math.log((ka / kd) * (1 - D0 * (ka - kd) / (kd * L0)))
Dc = (kd / ka) * L0 * math.exp(-kd * tc)
print(f"critical time {tc:.2f} days -> {tc*u:.0f} km downstream")
print(f"maximum deficit {Dc:.2f} mg/L -> minimum DO {DOs - Dc:.2f} mg/L")
for t in (0.5, 1, 3, 6):
    D = kd * L0 / (ka - kd) * (math.exp(-kd * t) - math.exp(-ka * t)) + D0 * math.exp(-ka * t)
    print(f"t = {t} d ({t*u:.0f} km): DO = {DOs - D:.2f} mg/L")
# critical time 1.76 days -> 46 km downstream
# maximum deficit 5.41 mg/L -> minimum DO 3.61 mg/L
# t = 0.5 d (13 km): DO = 5.27 mg/L
# t = 1 d (26 km): DO = 4.11 mg/L
# t = 3 d (78 km): DO = 4.29 mg/L
# t = 6 d (156 km): DO = 6.85 mg/L

The DO minimum of 3.6 mg/L occurs 46 km downstream — below the ~5 mg/L needed by many fish. To meet a 5 mg/L standard, the discharge BOD must be reduced (better treatment) or the river's reaeration must be higher (in reality you can't change the river).

Common mistakes

Applications

Key takeaways

Going further