Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Buckingham’s Pi theorem (1914)#
Edgar Buckingham, at the US Bureau of Standards, published in 1914 the
theorem that turned dimensional analysis into a method: a physical
relation among \(n\) variables whose dimensions involve \(r\)
independent base units can be rewritten as a relation among \(n - r\)
dimensionless products. The products are the null space of the dimension
matrix, which
buckingham_pi() finds by exact
row reduction. This example derives the groups of pipe friction and of
droplet break-up, then shows that pipes of different size and fluid with
the same groups have the same Euler number
(euler_number()).
import matplotlib.pyplot as plt
import numpy as np
from engineeringkit.fluid_engineering import (
buckingham_pi,
colebrook_friction_factor,
darcy_head_loss,
euler_number,
reynolds_number,
weber_number,
)
Pressure drop in a pipe#
Seven variables (pressure drop, density, speed, diameter, viscosity, roughness, length) in three base units give four groups. With density, speed and diameter repeating, they are the Euler number, the inverse Reynolds number, the relative roughness and the length ratio.
pipe = buckingham_pi(
{
"dp": {"M": 1, "L": -1, "T": -2},
"rho": {"M": 1, "L": -3},
"V": {"L": 1, "T": -1},
"D": {"L": 1},
"mu": {"M": 1, "L": -1, "T": -1},
"eps": {"L": 1},
"L": {"L": 1},
},
repeating=["rho", "V", "D"],
)
print(pipe.summary())
fig, ax = pipe.plot()
fig.set_size_inches(6, 3.2)
fig.tight_layout()

{'variables': 7, 'rank': 3, 'groups': 4, 'pi': ['rho^-1 V^-2 dp^1', 'rho^-1 V^-1 D^-1 mu^1', 'D^-1 eps^1', 'D^-1 L^1']}
Similar pipes, equal Euler numbers#
A water main, an oil line and a small air duct, each at \(Re = 10^5\), \(\varepsilon/D = 10^{-4}\) and \(L/D = 500\). The pressure drops differ by orders of magnitude; the Euler numbers agree.
cases = {"water": (998.0, 1.0e-3, 0.3), "oil": (870.0, 0.03, 0.5), "air": (1.2, 1.8e-5, 0.05)}
eu = []
for name, (rho, mu, D) in cases.items():
V = 1e5 * mu / (rho * D)
Re = reynolds_number(rho, V, D, mu)
dp = rho * 9.80665 * darcy_head_loss(colebrook_friction_factor(Re, 1e-4), 500 * D, D, V)
eu.append(euler_number(dp, rho, V))
print(f"{name:>5}: V = {V:6.3f} m/s, dp = {dp:10.1f} Pa, Eu = {eu[-1]:.4f}")
water: V = 0.334 m/s, dp = 515.3 Pa, Eu = 4.6285
oil: V = 6.897 m/s, dp = 191522.8 Pa, Eu = 4.6285
air: V = 30.000 m/s, dp = 4998.7 Pa, Eu = 4.6285
Droplet break-up#
A drop of diameter \(d\) in a gas stream: drop and gas densities, speed, surface tension and the drop viscosity. The groups include the Weber number, which must exceed about 12 for the drop to shatter.
drop = buckingham_pi(
{
"rho_g": {"M": 1, "L": -3},
"V": {"L": 1, "T": -1},
"d": {"L": 1},
"sigma": {"M": 1, "T": -2},
"rho_l": {"M": 1, "L": -3},
"mu_l": {"M": 1, "L": -1, "T": -1},
}
)
print(drop.groups())
We = weber_number(1.2, 40.0, 1e-3, 0.072)
print(f"a 1 mm water drop in air at 40 m/s: We = {We:.1f}, {'breaks up' if We > 12 else 'survives'}")
assert not np.any(pipe.dimension_matrix @ pipe.exponents.T)
assert pipe.summary()["groups"] == 4 and len(drop.groups()) == 3
assert np.allclose(eu, eu[0])
assert "rho_g^-1 V^-2 d^-1 sigma^1" in drop.groups()
plt.show()
['rho_g^-1 V^-2 d^-1 sigma^1', 'rho_g^-1 rho_l^1', 'rho_g^-1 V^-1 d^-1 mu_l^1']
a 1 mm water drop in air at 40 m/s: We = 26.7, breaks up
Total running time of the script: (0 minutes 0.024 seconds)