| name | fluids-package |
| description | Pipe flow, pump sizing, friction factor, and compressible flow calculations |
| category | packages |
| domain | fluids |
| complexity | intermediate |
| dependencies | ["fluids","scipy"] |
Fluids Package Skill
Overview
The fluids library is a comprehensive Python package for mechanical and chemical engineers working with fluid flow problems. It provides validated correlations and functions for:
- Pipe flow and friction factor calculations
- Pump sizing and performance analysis
- Compressible and incompressible flow
- Heat exchanger design
- Two-phase flow
- Pressure drop calculations
- Fluid properties
The library implements over 100 correlations from the literature with extensive validation against published test cases.
Installation
pip install fluids
For full functionality including optimization routines:
pip install fluids[complete]
Key Modules
fluids.core
Core utilities and dimensional analysis functions.
fluids.friction
Friction factor calculations for pipe flow including:
- Darcy-Weisbach equation
- Colebrook-White correlation
- Moody diagram implementations
- Turbulent and laminar flow regimes
fluids.pump
Pump performance calculations:
- Affinity laws
- Specific speed
- NPSH calculations
- Pump curves and efficiency
fluids.compressible
Compressible flow calculations:
- Mach number relationships
- Choked flow conditions
- Isentropic flow
- Normal shock waves
fluids.fittings
Pressure drop through valves, fittings, and pipe components.
Common Functions with Engineering Context
Reynolds Number Calculation
The Reynolds number (Re) determines flow regime and is fundamental to all pipe flow calculations.
from fluids.core import Reynolds
Re = Reynolds(V=2.5, D=0.05, rho=1000, mu=0.001)
Friction Factor (Darcy-Weisbach)
The friction factor (f) is used in the Darcy-Weisbach equation: ΔP = f(L/D)(ρV²/2)
from fluids.friction import friction_factor
f = friction_factor(Re=125000, eD=0.0001)
from fluids.friction import friction_factor_Moody
f_moody = friction_factor_Moody(Re=125000, eD=0.0001)
f_laminar = friction_factor(Re=1500, eD=0.0001)
Head Loss in Pipes
Calculate pressure drop and head loss in piping systems.
from fluids.friction import friction_factor, head_from_P
from fluids.core import Reynolds
D = 0.1
L = 100
V = 2.0
rho = 1000
mu = 0.001
epsilon = 0.000045
Re = Reynolds(V=V, D=D, rho=rho, mu=mu)
eD = epsilon / D
f = friction_factor(Re=Re, eD=eD)
dP = f * (L/D) * (rho * V**2 / 2)
h_loss = head_from_P(dP, rho)
print(f"Reynolds: {Re:.0f}")
print(f"Friction factor: {f:.5f}")
print(f"Pressure drop: {dP:.0f} Pa")
print(f"Head loss: {h_loss:.2f} m")
Pump Affinity Laws
Relate pump performance at different speeds and impeller diameters.
from fluids.pump import affinity_law_volume, affinity_law_head, affinity_law_power
Q1 = 100
H1 = 50
P1 = 20
N1 = 1450
D1 = 0.3
N2 = 1750
Q2 = affinity_law_volume(Q1, N1, N2)
H2 = affinity_law_head(H1, N1, N2)
P2 = affinity_law_power(P1, N1, N2)
print(f"New flow: {Q2:.1f} m³/h")
print(f"New head: {H2:.1f} m")
print(f"New power: {P2:.1f} kW")
Specific Speed Calculations
Specific speed (Ns) characterizes pump type and efficiency.
from fluids.pump import specific_speed
Q = 0.05
H = 40
N = 1450
Ns = specific_speed(Q, H, N)
print(f"Specific speed: {Ns:.2f}")
if Ns < 0.5:
pump_type = "Centrifugal (radial flow)"
elif Ns < 1.0:
pump_type = "Francis (mixed flow)"
else:
pump_type = "Propeller (axial flow)"
print(f"Recommended pump type: {pump_type}")
Compressible Flow - Mach Number
For gas flow in pipes and nozzles.
from fluids.compressible import Mach
V = 200
c = 340
Ma = Mach(V, c)
Compressible Flow - Choked Flow
Determine if flow is choked in a nozzle or orifice.
from fluids.compressible import P_critical_flow
P_upstream = 500000
k = 1.4
P_crit = P_critical_flow(P=P_upstream, k=k)
P_downstream = 200000
if P_downstream < P_crit:
print("Flow is choked - mass flow is at maximum")
print(f"Critical pressure: {P_crit:.0f} Pa")
else:
print("Flow is not choked")
Complete Engineering Examples
Example 1: Pump Selection and System Curve
import numpy as np
from fluids.friction import friction_factor
from fluids.core import Reynolds
import matplotlib.pyplot as plt
def system_curve(Q_range, static_head, pipe_specs):
"""
Calculate system head curve for a piping system.
Parameters:
-----------
Q_range : array, flow rates (m³/s)
static_head : float, static lift (m)
pipe_specs : dict with keys:
- L: pipe length (m)
- D: pipe diameter (m)
- epsilon: roughness (m)
- rho: fluid density (kg/m³)
- mu: fluid viscosity (Pa·s)
Returns:
--------
H_system : array, required head at each flow rate (m)
"""
L = pipe_specs['L']
D = pipe_specs['D']
rho = pipe_specs['rho']
mu = pipe_specs['mu']
epsilon = pipe_specs['epsilon']
A = np.pi * D**2 / 4
H_system = np.zeros_like(Q_range)
for i, Q in enumerate(Q_range):
if Q == 0:
H_system[i] = static_head
continue
V = Q / A
Re = Reynolds(V=V, D=D, rho=rho, mu=mu)
eD = epsilon / D
f = friction_factor(Re=Re, eD=eD)
h_friction = f * (L/D) * (V**2 / (2*9.81))
H_system[i] = static_head + h_friction
return H_system
pipe_specs = {
'L': 200,
'D': 0.15,
'epsilon': 0.000045,
'rho': 1000,
'mu': 0.001
}
static_head = 30
Q_range = np.linspace(0, 0.1, 50)
H_system = system_curve(Q_range, static_head, pipe_specs)
H0 = 80
A = 200
B = 3000
H_pump = H0 - A*Q_range - B*Q_range**2
idx = np.argmin(np.abs(H_pump - H_system))
Q_op = Q_range[idx]
H_op = H_system[idx]
print(f"Operating Point:")
print(f" Flow rate: {Q_op*3600:.1f} m³/h ({Q_op:.4f} m³/s)")
print(f" Head: {H_op:.1f} m")
Example 2: Parallel Pump Configuration
from fluids.pump import affinity_law_volume, affinity_law_head
def parallel_pumps(Q_total, n_pumps, single_pump_curve):
"""
Calculate operating point for parallel pump configuration.
For pumps in parallel:
- Flow rates add: Q_total = n * Q_single
- Head remains the same: H_total = H_single
"""
Q_single = Q_total / n_pumps
H = single_pump_curve(Q_single)
return Q_single, H
def pump_curve(Q):
return 60 - 500*Q**2
Q_required = 150/3600
n_pumps = 2
Q_single, H_operating = parallel_pumps(Q_required, n_pumps, pump_curve)
print(f"Parallel Pump Configuration ({n_pumps} pumps):")
print(f" Total flow: {Q_required*3600:.1f} m³/h")
print(f" Flow per pump: {Q_single*3600:.1f} m³/h")
print(f" Operating head: {H_operating:.1f} m")
Example 3: Friction Factor Validation
from fluids.friction import friction_factor, friction_factor_laminar
Re_laminar = 1000
f_calculated = friction_factor(Re=Re_laminar, eD=0)
f_analytical = 64/Re_laminar
print("Test 1: Laminar Flow")
print(f" Re = {Re_laminar}")
print(f" f (calculated) = {f_calculated:.6f}")
print(f" f (analytical) = {f_analytical:.6f}")
print(f" Error = {abs(f_calculated - f_analytical):.9f}")
assert abs(f_calculated - f_analytical) < 1e-9, "Laminar flow test failed"
print(" ✓ PASSED\n")
Re_turbulent = 1e5
f_smooth = friction_factor(Re=Re_turbulent, eD=0)
print("Test 2: Turbulent Flow (Smooth Pipe)")
print(f" Re = {Re_turbulent:.0f}")
print(f" f (calculated) = {f_smooth:.6f}")
print(f" f (Moody chart) ≈ 0.0183")
print(f" Error = {abs(f_smooth - 0.0183):.6f}")
assert abs(f_smooth - 0.0183) < 0.0005, "Smooth pipe test failed"
print(" ✓ PASSED\n")
Re_rough = 1e6
eD_rough = 0.0002
f_rough = friction_factor(Re=Re_rough, eD=eD_rough)
print("Test 3: Turbulent Flow (Rough Pipe)")
print(f" Re = {Re_rough:.0f}")
print(f" ε/D = {eD_rough}")
print(f" f (calculated) = {f_rough:.6f}")
print(f" f (Moody chart) ≈ 0.0144")
print(f" Error = {abs(f_rough - 0.0144):.6f}")
assert abs(f_rough - 0.0144) < 0.0005, "Rough pipe test failed"
print(" ✓ PASSED\n")
D = 0.1541
V = 3.05
rho = 998
mu = 0.001
epsilon = 0.000045
Re_crane = Reynolds(V=V, D=D, rho=rho, mu=mu)
eD_crane = epsilon/D
f_crane = friction_factor(Re=Re_crane, eD=eD_crane)
print("Test 4: Crane TP-410 Example 4-9")
print(f" Re = {Re_crane:.0f}")
print(f" ε/D = {eD_crane:.6f}")
print(f" f (calculated) = {f_crane:.6f}")
print(f" f (Crane TP-410) ≈ 0.0172")
print(f" Error = {abs(f_crane - 0.0172):.6f}")
assert abs(f_crane - 0.0172) < 0.0003, "Crane TP-410 test failed"
print(" ✓ PASSED\n")
print("All friction factor tests passed! ✓")
Example 4: Compressible Flow in Pipe
from fluids.compressible import isothermal_gas
P1 = 5e6
T = 288.15
L = 50000
D = 0.5
m = 10
MW = 16.04
k = 1.31
from fluids.compressible import isothermal_gas
P2 = isothermal_gas(rho=None, P1=P1, P2=None, L=L, D=D, m=m,
T=T, Z=1, fd=0.012)
print("Gas Pipeline Calculation:")
print(f" Inlet pressure: {P1/1e6:.2f} MPa")
print(f" Outlet pressure: {P2/1e6:.2f} MPa")
print(f" Pressure drop: {(P1-P2)/1e6:.2f} MPa")
print(f" Length: {L/1000:.0f} km")
print(f" Mass flow: {m:.1f} kg/s")
Best Practices
- Always check Reynolds number before selecting friction factor correlation
- Validate results against known test cases or handbook values
- Use consistent units - fluids uses SI units throughout
- Consider safety factors when sizing pumps (typically 10-15% margin)
- Check physical limits - verify Mach number < 0.3 for incompressible assumption
- Use appropriate roughness values from literature (Moody, Crane TP-410)
Common Pipe Roughness Values
| Material | Roughness ε (m) |
|---|
| Drawn tubing | 0.0000015 |
| Commercial steel | 0.000045 |
| Galvanized iron | 0.00015 |
| Cast iron | 0.00026 |
| Concrete | 0.0003 to 0.003 |
| Riveted steel | 0.0009 to 0.009 |
Troubleshooting
Issue: Friction factor doesn't converge
- Cause: Invalid Reynolds number or ε/D ratio
- Solution: Check that Re > 0 and 0 ≤ ε/D < 0.5
Issue: Pump curves don't intersect system curve
- Cause: Pump undersized or oversized
- Solution: Adjust pump speed using affinity laws or select different pump
Issue: Compressible flow results unrealistic
- Cause: Mach number > 0.3 but using incompressible equations
- Solution: Use compressible flow functions from fluids.compressible
References
- Crane Technical Paper 410 (TP-410): "Flow of Fluids Through Valves, Fittings, and Pipe"
- Moody, L.F. (1944): "Friction factors for pipe flow"
- Colebrook, C.F. (1939): "Turbulent flow in pipes"
- Karassik's Pump Handbook (4th Edition)
- GPSA Engineering Data Book (14th Edition)
Further Reading