Weisbach and Darcy: head loss in pipes (1845-1857)#

Julius Weisbach wrote the friction loss in a pipe in 1845 as \(h_f = f\,(L/D)\,v^2/(2g)\), with a coefficient that he fitted to experiments. Henry Darcy’s tests on new and incrusted cast-iron mains in Paris, published in 1857, showed that the coefficient depends on the diameter and the state of the wall. The Darcy-Weisbach equation (darcy_head_loss()), with loss coefficients for the fittings (minor_head_loss()), is still how pipelines are sized. This example follows the energy and hydraulic grade lines of water flowing from a reservoir through two pipes to a nozzle.

import matplotlib.pyplot as plt
import numpy as np

from engineeringkit.fluid_engineering import (
    colebrook_friction_factor,
    darcy_head_loss,
    minor_head_loss,
    reynolds_number,
    velocity_head,
)
from engineeringkit.fluid_engineering.visualizers import plot_grade_lines

The system#

A reservoir surface stands 25 m above the outlet. 200 m of 150 mm pipe lead to a contraction and 100 m of 100 mm pipe, ending in a free jet. Water flows at 25 L/s; the entrance has \(K = 0.5\) and the contraction \(K = 0.3\) on the downstream velocity.

rho, mu, eps, Q, z_res = 998.0, 1.0e-3, 0.045e-3, 0.025, 25.0
pipes = [(200.0, 0.15), (100.0, 0.10)]
v = [Q / (np.pi * D**2 / 4) for _, D in pipes]
f = [colebrook_friction_factor(reynolds_number(rho, vi, D, mu), eps / D) for vi, (_, D) in zip(v, pipes)]

losses = {
    "entrance": minor_head_loss(0.5, v[0]),
    "pipe 1": darcy_head_loss(f[0], pipes[0][0], pipes[0][1], v[0]),
    "contraction": minor_head_loss(0.3, v[1]),
    "pipe 2": darcy_head_loss(f[1], pipes[1][0], pipes[1][1], v[1]),
}
for name, h in losses.items():
    print(f"{name:>11}: {h:5.2f} m")
   entrance:  0.05 m
     pipe 1:  2.40 m
contraction:  0.15 m
     pipe 2:  9.22 m

Grade lines#

The energy grade line starts at the reservoir surface and drops at each loss; the hydraulic grade line sits one velocity head below it. The pipe runs along the ground at 0 m.

x = np.array([0, 0, 200, 200, 300])
egl = z_res - np.cumsum([losses["entrance"], 0, losses["pipe 1"], losses["contraction"], losses["pipe 2"]])
hv = velocity_head(np.array([v[0], v[0], v[0], v[1], v[1]]))
ax = plot_grade_lines(x, np.zeros(5), egl - hv, hv)
ax.set_title("Reservoir to free jet")
ax.figure.tight_layout()
Reservoir to free jet

The energy left at the outlet is the jet’s velocity head; the rest went to friction and fittings.

jet = velocity_head(v[1])
print(f"jet velocity head {jet:.2f} m + losses {sum(losses.values()):.2f} m = {jet + sum(losses.values()):.2f} m available")
print(f"friction share of the losses: {(losses['pipe 1'] + losses['pipe 2']) / sum(losses.values()):.0%}")

# Head loss in fully rough flow grows as v²: doubling the flow roughly quadruples it.
h2 = darcy_head_loss(colebrook_friction_factor(reynolds_number(rho, 2 * v[1], 0.1, mu), eps / 0.1), 100.0, 0.1, 2 * v[1])
print(f"doubling the flow multiplies the pipe-2 loss by {h2 / losses['pipe 2']:.2f}")

assert z_res - sum(losses.values()) > jet  # the pipe can carry this flow with head to spare
assert 3.6 < h2 / losses["pipe 2"] < 4.0
assert np.all(np.diff(egl) <= 0)

plt.show()
jet velocity head 0.52 m + losses 11.82 m = 12.34 m available
friction share of the losses: 98%
doubling the flow multiplies the pipe-2 loss by 3.84

Total running time of the script: (0 minutes 0.032 seconds)

Gallery generated by Sphinx-Gallery