DEV Community

Cover image for Well Pump TDH in Python: The Pressure Switch Is Half the Head
Evgenii Konkin
Evgenii Konkin

Posted on

Well Pump TDH in Python: The Pressure Switch Is Half the Head

Most well pump questions start with "my well is 200 feet deep." Depth is not what sizes the pump. A pump is selected by flow (gpm) and total dynamic head (TDH, in feet). Here is a small Python model that builds TDH from its parts, so you can see which part dominates.

The model

TDH has four components:

  • Lift: static water level + drawdown (the pumping water level, not the well depth)
  • Elevation rise: wellhead to the highest fixture
  • Pressure head: switch cut-out pressure × 2.31 ft/psi
  • Friction: Hazen-Williams loss over drop pipe + service line, plus a fitting allowance
PIPE_ID_IN = {"1": 1.049, "1-1/4": 1.380, "1-1/2": 1.610}  # PVC Sch 40 inside diameters

def friction_per_100ft(gpm, pipe_id_in, c=150):
    """Hazen-Williams head loss, ft per 100 ft of pipe."""
    return 0.2083 * (100 / c) ** 1.852 * gpm ** 1.852 / pipe_id_in ** 4.8655

def tdh(gpm, static_ft, drawdown_ft, rise_ft, cutout_psi,
        drop_pipe_ft, service_ft, fittings=0.10, pipe="1-1/4"):
    lift = static_ft + drawdown_ft          # pumping water level, not well depth
    pressure = cutout_psi * 2.31            # psi -> ft of water
    length = (drop_pipe_ft + service_ft) * (1 + fittings)
    friction = friction_per_100ft(gpm, PIPE_ID_IN[pipe]) * length / 100
    total = lift + rise_ft + pressure + friction
    return {"lift": lift, "rise": rise_ft, "pressure": pressure,
            "friction": friction, "tdh": total}

def brake_hp(gpm, tdh_ft, efficiency):
    return gpm * tdh_ft / 3960 / efficiency
Enter fullscreen mode Exit fullscreen mode

Running an example

Illustrative inputs: 12 gpm, 80 ft static level, 40 ft drawdown, 15 ft rise, 40/60 psi switch, 160 ft drop pipe, 100 ft service line, 10% fittings, 1¼ in PVC.

base = dict(static_ft=80, drawdown_ft=40, rise_ft=15, cutout_psi=60,
            drop_pipe_ft=160, service_ft=100)
r = tdh(12, **base)
for k, v in r.items():
    print(f"{k:>9}: {v:6.1f} ft  ({v / r['tdh']:.0%})")
print(f"BHP range: {brake_hp(12, r['tdh'], 0.55):.2f}-{brake_hp(12, r['tdh'], 0.40):.2f}")
Enter fullscreen mode Exit fullscreen mode

Output:

     lift:  120.0 ft  (43%)
     rise:   15.0 ft  (5%)
 pressure:  138.6 ft  (50%)
 friction:    5.8 ft  (2%)
      tdh:  279.4 ft  (100%)
BHP range: 1.54-2.12
Enter fullscreen mode Exit fullscreen mode

The pressure switch contributes half the head. Friction, the term people often worry about most, is 2%.

Three one-line experiments

print(round(tdh(12, **{**base, "cutout_psi": 40})["tdh"], 1))  # cut-in: 233.2
print(round(tdh(12, **base, pipe="1")["friction"], 1))         # 1 in pipe: 22.2
print(round(tdh(10, **base)["tdh"], 1))                         # 10 gpm: 277.8
Enter fullscreen mode Exit fullscreen mode
  1. Cut-in instead of cut-out: TDH drops by 46.2 ft. A pump picked at 233 ft may never reach the 60 psi cut-out.
  2. 1 in instead of 1¼ in pipe: friction rises about 3.8× at the same flow.
  3. Yield limit: if the well sustains only 10 gpm, sizing to 12 gpm overpumps it. Size to the yield and add storage for peaks; brake HP falls to roughly 1.3–1.75.

Limits

  • Hazen-Williams applies to water at ordinary temperatures in full pipes.
  • The efficiency band (40–55% here) is a placeholder; real selection reads the manufacturer's pump curve at your flow and TDH.
  • Check submergence: the pump must sit below the pumping water level.

The useful habit is the dictionary of components, not the total. When one term is half the head, that is where design changes pay off.

Top comments (0)