By Saad Iqbal
An ESP vendor asks three questions before they’ll quote a pump: how deep, how much fluid, and what head do you need? The first two are easy. The third — total dynamic head (TDH) — is where a lot of artificial lift designs go wrong, because it isn’t one number you look up, it’s three separate calculations added together: how far you’re lifting the fluid, how much pressure friction eats on the way up, and how much pressure you need left over at surface. Undersize it and the pump never meets its target rate; oversize it and you’re running an ESP against its performance curve in a zone that burns out bearings early. Here’s how to calculate ESP total dynamic head by hand, with real numbers, then automate it so you can re-run it for every well on a pad in seconds.
What ESP Total Dynamic Head (TDH) Actually Is
Total dynamic head is the total energy, expressed in feet of fluid, that an ESP must add to move produced fluid from the pump to the surface against gravity, friction, and backpressure. It breaks into three additive components:
- Net lift — the vertical distance the pump actually has to lift fluid: pump setting depth minus the dynamic fluid level sitting above the pump.
- Friction loss — pressure lost to turbulence as fluid moves up the tubing ID, calculated from the Darcy-Weisbach equation.
- Discharge head — the wellhead (surface) pressure the pump has to push against, converted from psi into feet using the fluid’s gradient.
TDH (ft) = Net Lift + Friction Loss + Discharge Head
Prerequisites
- Tool: a calculator for the hand steps; Python 3.10+ for the automation step (standard library only, no packages to install).
- Inputs needed: pump setting depth (TVD), dynamic fluid level above the pump, tubing ID, target liquid rate, wellhead pressure, and produced fluid specific gravity.
- Sample values used in this walkthrough: pump setting depth = 6,500 ft, dynamic fluid level = 1,200 ft, 2-7/8″ tubing (2.441 in ID), target rate = 1,500 bbl/d, wellhead pressure = 150 psi, fluid SG = 0.90.

Step 1: Calculate Net Lift
Net lift is the easiest component and the biggest share of TDH on most wells. Why it matters: get the dynamic fluid level wrong (from a stale acoustic shot, say) and every downstream number inherits that error.
Net Lift (ft) = Pump Setting Depth (ft) − Dynamic Fluid Level (ft)
Worked example: Net Lift = 6,500 − 1,200 = 5,300 ft

Step 2: Calculate Friction Loss with the Darcy-Weisbach Equation
Friction loss depends on flow velocity inside the tubing, which depends on rate and tubing ID. Why it matters: on high-rate wells or small-ID tubing, friction loss can swing TDH by hundreds of feet — skipping it (or using a rough rule of thumb) is the most common sizing mistake.
hf (ft) = f × (L / D) × (V² / 2g)
Where f is the Darcy friction factor, L is tubing length (ft), D is tubing ID (ft), V is flow velocity (ft/s), and g = 32.174 ft/s². The friction factor f is found from the explicit Swamee-Jain correlation (an accurate, non-iterative stand-in for Colebrook-White):
f = 0.25 / [log10(ε/(3.7D) + 5.74/Re^0.9)]²
Worked example (1,500 bbl/d through 2.441 in ID tubing, steel roughness ε = 0.0006 in, fluid viscosity ≈ 1.0 cSt):
- Flow area: A = π/4 × (0.2034 ft)² = 0.0325 ft²
- Velocity: V = (1,500 × 5.615 ÷ 86,400) ÷ 0.0325 ≈ 3.0 ft/s
- Reynolds number: Re = V·D/ν ≈ 56,700 (turbulent flow)
- Relative roughness: ε/D ≈ 0.000246
- Swamee-Jain friction factor: f ≈ 0.0212
- hf = 0.0212 × (6,500 / 0.2034) × (3.0² / 64.35) ≈ 95 ft

Step 3: Calculate Discharge Head and Total TDH
Discharge head converts the surface wellhead pressure the pump must overcome from psi into feet of the produced fluid, using that fluid’s gradient. Why it matters: a higher-SG fluid needs fewer feet to generate the same psi, so this step must use the actual produced fluid gravity, not a generic water gradient.
Discharge Head (ft) = Wellhead Pressure (psi) / (0.433 × SG)
Worked example: Discharge Head = 150 / (0.433 × 0.90) = 150 / 0.390 ≈ 385 ft
| Component | Value (ft) |
|---|---|
| Net Lift | 5,300 |
| Friction Loss | 95 |
| Discharge Head | 385 |
| Total Dynamic Head (TDH) | ≈ 5,780 |
This well needs a pump rated for roughly 5,780 ft of TDH at 1,500 bbl/d — that’s the exact pair of numbers (rate, head) you plot against a manufacturer’s pump performance curve to pick a stage count and model.
Step 4: Automate It in Python
Re-running this by hand for every well on a pad, or every time the fluid level or rate target changes, doesn’t scale. Here’s a Python function that reproduces every number above exactly:
import math
def esp_tdh(pump_depth_ft, fluid_level_ft, tubing_id_in, rate_bpd,
wellhead_psi, fluid_sg, viscosity_cst=1.0, roughness_in=0.0006):
"""Calculate ESP total dynamic head (TDH) in feet."""
net_lift = pump_depth_ft - fluid_level_ft
id_ft = tubing_id_in / 12
area_ft2 = math.pi / 4 * id_ft ** 2
q_ft3s = rate_bpd * 5.615 / 86400
velocity = q_ft3s / area_ft2
nu_ft2s = viscosity_cst * 1.0764e-5
reynolds = velocity * id_ft / nu_ft2s
rel_rough = (roughness_in / 12) / id_ft
f = 0.25 / (math.log10(rel_rough / 3.7 + 5.74 / reynolds ** 0.9)) ** 2
g = 32.174
friction_ft = f * (pump_depth_ft / id_ft) * (velocity ** 2 / (2 * g))
gradient = 0.433 * fluid_sg
discharge_ft = wellhead_psi / gradient
tdh = net_lift + friction_ft + discharge_ft
return {
"net_lift_ft": round(net_lift, 1),
"velocity_fts": round(velocity, 2),
"reynolds": round(reynolds, 0),
"friction_factor": round(f, 4),
"friction_loss_ft": round(friction_ft, 1),
"discharge_head_ft": round(discharge_ft, 1),
"TDH_ft": round(tdh, 1),
}
result = esp_tdh(
pump_depth_ft=6500,
fluid_level_ft=1200,
tubing_id_in=2.441,
rate_bpd=1500,
wellhead_psi=150,
fluid_sg=0.90,
)
print(result)
Running it should print a TDH of roughly 5,780 ft, matching the hand calculation. Wrap this function in a loop over a pandas DataFrame of well data to size an entire pad at once, or ask an AI assistant like ChatGPT or Claude to extend it to pull pump depth and fluid level straight from your well file database. For tracking TDH and pump performance across a field over time, push the results into Microsoft Power BI.

Sizing the Inflow Side Too
TDH only tells you what the pump has to do — it doesn’t tell you whether the reservoir can actually deliver 1,500 bbl/d at a dynamic fluid level of 1,200 ft above the pump. That’s an inflow performance question. If you haven’t already, work through our companion tutorial on the Vogel IPR equation to check that your target rate is actually achievable before you commit to a pump size.
Expected Result, Verification, and Common Pitfalls
Expected result: a TDH of roughly 5,780 ft at 1,500 bbl/d for this example — the operating point you plot against a manufacturer’s head-vs-rate performance curve.
Sanity check: net lift should always be the dominant term on a deep well; if friction loss or discharge head is larger than net lift, double-check your tubing ID and rate — a transposed decimal in ID is the most common source of a wildly wrong friction number.
Common pitfalls:
- Using a stale fluid level. Dynamic fluid level shifts as drawdown changes; re-shoot it rather than reusing a number from the last workover.
- Ignoring gas in the fluid column. Free gas lightens the fluid gradient above the pump, which changes both net lift and discharge head — this method assumes a largely degassed, single-phase liquid column, so flag high-GOR wells for a multiphase (Beggs-Brill style) review instead.
- Sizing to the target rate alone. Always check TDH against the pump’s full performance curve, not just its rated point — operating too far off the curve’s best efficiency point shortens run life.
Read the related tutorial on the Vogel IPR equation below to confirm the reservoir can deliver the rate you just sized this pump for.

