Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/mechanical-engineering/fluid_flow.tex
51 views
unlisted
1
\documentclass[11pt,a4paper]{article}
2
3
% Document Setup
4
\usepackage[utf8]{inputenc}
5
\usepackage[T1]{fontenc}
6
\usepackage{lmodern}
7
\usepackage[margin=1in]{geometry}
8
\usepackage{amsmath,amssymb}
9
\usepackage{siunitx}
10
\usepackage{booktabs}
11
\usepackage{float}
12
\usepackage{caption}
13
\usepackage{hyperref}
14
15
% PythonTeX Setup
16
\usepackage[makestderr]{pythontex}
17
18
\title{Pipe Flow Analysis: Darcy-Weisbach and Friction Factors}
19
\author{Mechanical Engineering Laboratory}
20
\date{\today}
21
22
\begin{document}
23
\maketitle
24
25
\begin{abstract}
26
This report presents computational analysis of pipe flow using the Darcy-Weisbach equation. We examine Reynolds number regimes, friction factor correlations including the Colebrook-White equation, the Moody diagram, minor losses, and pipe network analysis. Python-based computations provide quantitative analysis with dynamic visualization.
27
\end{abstract}
28
29
\tableofcontents
30
\newpage
31
32
\section{Introduction to Pipe Flow}
33
34
Internal flow through pipes is fundamental to hydraulic system design. Key applications include:
35
\begin{itemize}
36
\item Water distribution networks
37
\item Oil and gas pipelines
38
\item HVAC systems
39
\item Process piping in chemical plants
40
\end{itemize}
41
42
% Initialize Python environment
43
\begin{pycode}
44
import numpy as np
45
import matplotlib.pyplot as plt
46
from scipy.optimize import fsolve
47
48
plt.rcParams['figure.figsize'] = (8, 5)
49
plt.rcParams['font.size'] = 10
50
plt.rcParams['text.usetex'] = True
51
52
def save_fig(filename):
53
plt.savefig(filename, dpi=150, bbox_inches='tight')
54
plt.close()
55
\end{pycode}
56
57
\section{Fundamental Equations}
58
59
\subsection{Reynolds Number}
60
61
The Reynolds number characterizes flow regime:
62
\begin{equation}
63
Re = \frac{\rho V D}{\mu} = \frac{V D}{\nu}
64
\end{equation}
65
where $\rho$ is density, $V$ is velocity, $D$ is diameter, and $\mu$ is dynamic viscosity.
66
67
\begin{pycode}
68
# Flow regime visualization
69
Re_range = np.logspace(2, 6, 500)
70
71
fig, ax = plt.subplots(figsize=(10, 5))
72
73
# Laminar regime
74
ax.axvspan(100, 2300, alpha=0.3, color='blue', label='Laminar')
75
# Transition regime
76
ax.axvspan(2300, 4000, alpha=0.3, color='yellow', label='Transition')
77
# Turbulent regime
78
ax.axvspan(4000, 1e6, alpha=0.3, color='red', label='Turbulent')
79
80
ax.axvline(2300, color='black', linestyle='--', linewidth=2)
81
ax.axvline(4000, color='black', linestyle='--', linewidth=2)
82
83
ax.set_xscale('log')
84
ax.set_xlabel('Reynolds Number')
85
ax.set_ylabel('Flow Characteristic')
86
ax.set_title('Flow Regime Classification')
87
ax.legend(loc='upper left')
88
ax.set_xlim(100, 1e6)
89
ax.set_yticks([])
90
91
# Add annotations
92
ax.text(500, 0.5, 'Laminar\\n$Re < 2300$', ha='center', fontsize=12, transform=ax.get_xaxis_transform())
93
ax.text(3100, 0.5, 'Trans.', ha='center', fontsize=10, transform=ax.get_xaxis_transform())
94
ax.text(50000, 0.5, 'Turbulent\\n$Re > 4000$', ha='center', fontsize=12, transform=ax.get_xaxis_transform())
95
96
save_fig('flow_regimes.pdf')
97
\end{pycode}
98
99
\begin{figure}[H]
100
\centering
101
\includegraphics[width=\textwidth]{flow_regimes.pdf}
102
\caption{Flow regime classification based on Reynolds number.}
103
\end{figure}
104
105
\subsection{Darcy-Weisbach Equation}
106
107
Head loss in pipe flow:
108
\begin{equation}
109
h_f = f \frac{L}{D} \frac{V^2}{2g}
110
\end{equation}
111
or in terms of pressure drop:
112
\begin{equation}
113
\Delta P = f \frac{L}{D} \frac{\rho V^2}{2}
114
\end{equation}
115
116
\section{Friction Factor Correlations}
117
118
\subsection{Laminar Flow}
119
120
For laminar flow ($Re < 2300$):
121
\begin{equation}
122
f = \frac{64}{Re}
123
\end{equation}
124
125
\subsection{Turbulent Flow - Colebrook-White Equation}
126
127
For turbulent flow:
128
\begin{equation}
129
\frac{1}{\sqrt{f}} = -2\log_{10}\left(\frac{\epsilon/D}{3.7} + \frac{2.51}{Re\sqrt{f}}\right)
130
\end{equation}
131
132
\begin{pycode}
133
# Friction factor calculation functions
134
def f_laminar(Re):
135
return 64 / Re
136
137
def f_turbulent(Re, eps_D):
138
"""Solve Colebrook-White equation iteratively"""
139
if Re < 2300:
140
return 64 / Re
141
142
# Swamee-Jain initial guess
143
f0 = 0.25 / (np.log10(eps_D/3.7 + 5.74/Re**0.9))**2
144
145
# Newton-Raphson iteration
146
for _ in range(50):
147
sqrt_f = np.sqrt(f0)
148
LHS = 1/sqrt_f
149
RHS = -2 * np.log10(eps_D/3.7 + 2.51/(Re*sqrt_f))
150
f_new = 1/(RHS)**2
151
if abs(f_new - f0) < 1e-10:
152
break
153
f0 = f_new
154
155
return f0
156
157
# Calculate friction factors for various Reynolds numbers and roughness
158
Re_range = np.logspace(3, 8, 200)
159
eps_D_values = [0, 1e-6, 1e-5, 1e-4, 1e-3, 0.01, 0.05]
160
161
fig, ax = plt.subplots(figsize=(12, 8))
162
163
# Laminar line
164
Re_lam = np.linspace(600, 2300, 100)
165
f_lam = [f_laminar(Re) for Re in Re_lam]
166
ax.loglog(Re_lam, f_lam, 'b-', linewidth=2, label='Laminar')
167
168
# Turbulent lines
169
colors = plt.cm.viridis(np.linspace(0, 1, len(eps_D_values)))
170
for eps_D, color in zip(eps_D_values, colors):
171
Re_turb = Re_range[Re_range > 2300]
172
f_turb = [f_turbulent(Re, eps_D) for Re in Re_turb]
173
if eps_D == 0:
174
label = 'Smooth'
175
else:
176
label = f'$\\epsilon/D$ = {eps_D}'
177
ax.loglog(Re_turb, f_turb, color=color, linewidth=1.5, label=label)
178
179
ax.axvline(2300, color='gray', linestyle='--', alpha=0.5)
180
ax.set_xlabel('Reynolds Number, Re')
181
ax.set_ylabel('Friction Factor, f')
182
ax.set_title('Moody Diagram')
183
ax.legend(loc='upper right', fontsize=8)
184
ax.grid(True, which='both', alpha=0.3)
185
ax.set_xlim(600, 1e8)
186
ax.set_ylim(0.008, 0.1)
187
188
save_fig('moody_diagram.pdf')
189
\end{pycode}
190
191
\begin{figure}[H]
192
\centering
193
\includegraphics[width=\textwidth]{moody_diagram.pdf}
194
\caption{Moody diagram showing friction factor vs Reynolds number for various relative roughness values.}
195
\end{figure}
196
197
\section{Pipe Flow Analysis}
198
199
\begin{pycode}
200
# Design problem: water flow in commercial steel pipe
201
# Properties
202
rho = 998 # kg/m^3 (water)
203
mu = 0.001 # Pa*s
204
nu = mu / rho
205
206
# Pipe parameters
207
D = 0.1 # m (100 mm diameter)
208
L = 100 # m
209
epsilon = 0.045e-3 # m (commercial steel)
210
eps_D = epsilon / D
211
212
# Flow rates
213
Q_range = np.linspace(0.001, 0.05, 50) # m^3/s
214
V_range = Q_range / (np.pi * D**2 / 4)
215
Re_range = V_range * D / nu
216
217
# Calculate friction factors and pressure drops
218
f_range = [f_turbulent(Re, eps_D) for Re in Re_range]
219
dP_range = np.array(f_range) * L/D * rho * V_range**2 / 2 # Pa
220
h_f_range = dP_range / (rho * 9.81) # m
221
222
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
223
224
# Velocity vs flow rate
225
axes[0, 0].plot(Q_range*1000, V_range, 'b-', linewidth=2)
226
axes[0, 0].set_xlabel('Flow Rate (L/s)')
227
axes[0, 0].set_ylabel('Velocity (m/s)')
228
axes[0, 0].set_title('Flow Velocity')
229
axes[0, 0].grid(True, alpha=0.3)
230
231
# Reynolds number
232
axes[0, 1].plot(Q_range*1000, Re_range/1000, 'r-', linewidth=2)
233
axes[0, 1].axhline(2.3, color='k', linestyle='--', alpha=0.5, label='Re = 2300')
234
axes[0, 1].set_xlabel('Flow Rate (L/s)')
235
axes[0, 1].set_ylabel('Reynolds Number ($\\times 10^3$)')
236
axes[0, 1].set_title('Reynolds Number')
237
axes[0, 1].legend()
238
axes[0, 1].grid(True, alpha=0.3)
239
240
# Pressure drop
241
axes[1, 0].plot(Q_range*1000, dP_range/1000, 'g-', linewidth=2)
242
axes[1, 0].set_xlabel('Flow Rate (L/s)')
243
axes[1, 0].set_ylabel('Pressure Drop (kPa)')
244
axes[1, 0].set_title('Pressure Drop')
245
axes[1, 0].grid(True, alpha=0.3)
246
247
# System curve (head loss vs flow rate)
248
axes[1, 1].plot(Q_range*1000, h_f_range, 'm-', linewidth=2, label='System curve')
249
axes[1, 1].set_xlabel('Flow Rate (L/s)')
250
axes[1, 1].set_ylabel('Head Loss (m)')
251
axes[1, 1].set_title('System Curve')
252
axes[1, 1].grid(True, alpha=0.3)
253
254
plt.tight_layout()
255
save_fig('pipe_flow_analysis.pdf')
256
257
# Design point calculations
258
Q_design = 0.02 # m^3/s (20 L/s)
259
V_design = Q_design / (np.pi * D**2 / 4)
260
Re_design = V_design * D / nu
261
f_design = f_turbulent(Re_design, eps_D)
262
dP_design = f_design * L/D * rho * V_design**2 / 2
263
h_f_design = dP_design / (rho * 9.81)
264
\end{pycode}
265
266
\begin{figure}[H]
267
\centering
268
\includegraphics[width=\textwidth]{pipe_flow_analysis.pdf}
269
\caption{Pipe flow analysis showing velocity, Reynolds number, pressure drop, and system curve.}
270
\end{figure}
271
272
\subsection{Design Point Results}
273
274
For a design flow rate of $Q = 20$ L/s:
275
276
\begin{table}[H]
277
\centering
278
\caption{Pipe Flow Design Calculations}
279
\begin{tabular}{lcc}
280
\toprule
281
Parameter & Value & Units \\
282
\midrule
283
Velocity & \py{f"{V_design:.2f}"} & m/s \\
284
Reynolds number & \py{f"{Re_design:.0f}"} & -- \\
285
Friction factor & \py{f"{f_design:.4f}"} & -- \\
286
Pressure drop & \py{f"{dP_design/1000:.2f}"} & kPa \\
287
Head loss & \py{f"{h_f_design:.2f}"} & m \\
288
\bottomrule
289
\end{tabular}
290
\end{table}
291
292
\section{Minor Losses}
293
294
Minor (local) losses from fittings and valves:
295
\begin{equation}
296
h_m = K \frac{V^2}{2g}
297
\end{equation}
298
299
\begin{pycode}
300
# Minor loss coefficients
301
fittings = {
302
'90 elbow (regular)': 0.9,
303
'90 elbow (long radius)': 0.6,
304
'45 elbow': 0.4,
305
'Tee (branch)': 1.8,
306
'Gate valve (full open)': 0.2,
307
'Globe valve (full open)': 10.0,
308
'Check valve': 2.5,
309
'Entrance (sharp)': 0.5,
310
'Exit': 1.0
311
}
312
313
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
314
315
# Bar chart of K values
316
names = list(fittings.keys())
317
K_vals = list(fittings.values())
318
y_pos = np.arange(len(names))
319
320
ax1.barh(y_pos, K_vals, color='steelblue', alpha=0.7)
321
ax1.set_yticks(y_pos)
322
ax1.set_yticklabels(names)
323
ax1.set_xlabel('Loss Coefficient K')
324
ax1.set_title('Minor Loss Coefficients')
325
ax1.grid(True, alpha=0.3, axis='x')
326
327
# Total system losses with fittings
328
# Example system: entrance + 4 elbows + gate valve + exit
329
system_fittings = [
330
('Entrance', 0.5),
331
('4x 90 elbows', 4*0.9),
332
('Gate valve', 0.2),
333
('Exit', 1.0)
334
]
335
336
V = V_design
337
g = 9.81
338
minor_losses = []
339
labels = []
340
for name, K in system_fittings:
341
h_m = K * V**2 / (2*g)
342
minor_losses.append(h_m)
343
labels.append(name)
344
345
# Add major loss
346
major_loss = h_f_design
347
labels.append('Major loss')
348
minor_losses.append(major_loss)
349
350
colors = ['lightblue']*4 + ['salmon']
351
ax2.bar(labels, minor_losses, color=colors, alpha=0.7)
352
ax2.set_ylabel('Head Loss (m)')
353
ax2.set_title('System Head Loss Breakdown')
354
ax2.grid(True, alpha=0.3, axis='y')
355
356
total_loss = sum(minor_losses)
357
ax2.axhline(total_loss/len(minor_losses), color='red', linestyle='--',
358
label=f'Total = {total_loss:.2f} m')
359
ax2.legend()
360
361
plt.tight_layout()
362
save_fig('minor_losses.pdf')
363
364
K_total_minor = sum([k for _, k in system_fittings])
365
h_minor_total = K_total_minor * V_design**2 / (2*g)
366
\end{pycode}
367
368
\begin{figure}[H]
369
\centering
370
\includegraphics[width=\textwidth]{minor_losses.pdf}
371
\caption{Minor loss coefficients and system head loss breakdown.}
372
\end{figure}
373
374
Total minor losses: $h_m = \py{f"{h_minor_total:.2f}"}$ m
375
376
\section{Pipe Diameter Effect}
377
378
\begin{pycode}
379
# Effect of pipe diameter on pressure drop
380
diameters = np.linspace(0.05, 0.3, 100) # m
381
Q_fixed = 0.02 # m^3/s
382
383
dP_diam = []
384
V_diam = []
385
386
for D in diameters:
387
A = np.pi * D**2 / 4
388
V = Q_fixed / A
389
Re = V * D / nu
390
eps_D = epsilon / D
391
f = f_turbulent(Re, eps_D)
392
dP = f * L/D * rho * V**2 / 2
393
dP_diam.append(dP)
394
V_diam.append(V)
395
396
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
397
398
ax1.semilogy(diameters*1000, np.array(dP_diam)/1000, 'b-', linewidth=2)
399
ax1.axvline(100, color='r', linestyle='--', label='D = 100 mm')
400
ax1.set_xlabel('Pipe Diameter (mm)')
401
ax1.set_ylabel('Pressure Drop (kPa)')
402
ax1.set_title('Pressure Drop vs Diameter (Q = 20 L/s)')
403
ax1.legend()
404
ax1.grid(True, alpha=0.3)
405
406
ax2.plot(diameters*1000, V_diam, 'g-', linewidth=2)
407
ax2.axhline(3, color='r', linestyle='--', alpha=0.5, label='Typical max V')
408
ax2.set_xlabel('Pipe Diameter (mm)')
409
ax2.set_ylabel('Flow Velocity (m/s)')
410
ax2.set_title('Velocity vs Diameter')
411
ax2.legend()
412
ax2.grid(True, alpha=0.3)
413
414
plt.tight_layout()
415
save_fig('diameter_effect.pdf')
416
\end{pycode}
417
418
\begin{figure}[H]
419
\centering
420
\includegraphics[width=\textwidth]{diameter_effect.pdf}
421
\caption{Effect of pipe diameter on pressure drop and velocity for constant flow rate.}
422
\end{figure}
423
424
\section{Pipe Network Analysis}
425
426
\subsection{Pipes in Series}
427
428
For pipes in series, flow rate is constant and head losses add:
429
\begin{equation}
430
h_{f,total} = \sum_{i=1}^{n} h_{f,i}
431
\end{equation}
432
433
\subsection{Pipes in Parallel}
434
435
For pipes in parallel, head loss is equal and flow rates add:
436
\begin{equation}
437
Q_{total} = \sum_{i=1}^{n} Q_i \quad \text{with} \quad h_{f,1} = h_{f,2} = \cdots
438
\end{equation}
439
440
\begin{pycode}
441
# Parallel pipe analysis
442
# Two pipes with different diameters
443
D1 = 0.1 # m
444
D2 = 0.08 # m
445
L_both = 100 # m
446
447
# Find flow distribution for given total head loss
448
h_f_target = 5 # m target head loss
449
450
def flow_rate_from_head(h_f, D, L, eps):
451
"""Calculate flow rate given head loss using iteration"""
452
eps_D = eps / D
453
A = np.pi * D**2 / 4
454
455
# Initial guess using Hazen-Williams approximation
456
V = np.sqrt(2 * 9.81 * h_f * D / (0.02 * L))
457
458
for _ in range(50):
459
Re = V * D / nu
460
f = f_turbulent(Re, eps_D)
461
V_new = np.sqrt(2 * 9.81 * h_f * D / (f * L))
462
if abs(V_new - V) < 1e-6:
463
break
464
V = V_new
465
466
return V * A
467
468
h_range = np.linspace(1, 10, 50)
469
Q1_range = [flow_rate_from_head(h, D1, L_both, epsilon) for h in h_range]
470
Q2_range = [flow_rate_from_head(h, D2, L_both, epsilon) for h in h_range]
471
Q_total = [q1 + q2 for q1, q2 in zip(Q1_range, Q2_range)]
472
473
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
474
475
ax1.plot(np.array(Q1_range)*1000, h_range, 'b-', linewidth=2, label=f'Pipe 1 (D={D1*1000:.0f}mm)')
476
ax1.plot(np.array(Q2_range)*1000, h_range, 'r-', linewidth=2, label=f'Pipe 2 (D={D2*1000:.0f}mm)')
477
ax1.plot(np.array(Q_total)*1000, h_range, 'k--', linewidth=2, label='Total')
478
ax1.set_xlabel('Flow Rate (L/s)')
479
ax1.set_ylabel('Head Loss (m)')
480
ax1.set_title('Parallel Pipe System Curves')
481
ax1.legend()
482
ax1.grid(True, alpha=0.3)
483
484
# Flow distribution at target head loss
485
Q1_target = flow_rate_from_head(h_f_target, D1, L_both, epsilon)
486
Q2_target = flow_rate_from_head(h_f_target, D2, L_both, epsilon)
487
Q_total_target = Q1_target + Q2_target
488
489
fractions = [Q1_target/Q_total_target * 100, Q2_target/Q_total_target * 100]
490
labels = [f'Pipe 1\\n{Q1_target*1000:.1f} L/s', f'Pipe 2\\n{Q2_target*1000:.1f} L/s']
491
ax2.pie(fractions, labels=labels, autopct='%1.1f%%', colors=['lightblue', 'salmon'])
492
ax2.set_title(f'Flow Distribution at $h_f$ = {h_f_target} m')
493
494
plt.tight_layout()
495
save_fig('parallel_pipes.pdf')
496
\end{pycode}
497
498
\begin{figure}[H]
499
\centering
500
\includegraphics[width=\textwidth]{parallel_pipes.pdf}
501
\caption{Parallel pipe analysis showing system curves and flow distribution.}
502
\end{figure}
503
504
\section{Pump Selection}
505
506
\begin{pycode}
507
# Pump operating point determination
508
# System curve: h_sys = h_static + K*Q^2
509
h_static = 10 # m (elevation difference)
510
K_sys = 50000 # system constant (s^2/m^5)
511
512
Q_sys = np.linspace(0, 0.04, 100)
513
h_sys = h_static + K_sys * Q_sys**2
514
515
# Pump curve (typical centrifugal)
516
h_shutoff = 25 # m
517
Q_max = 0.05 # m^3/s
518
h_pump = h_shutoff * (1 - (Q_sys/Q_max)**2)
519
520
# Find operating point
521
idx_op = np.argmin(np.abs(h_pump - h_sys))
522
Q_op = Q_sys[idx_op]
523
h_op = h_pump[idx_op]
524
525
# NPSH requirements
526
NPSH_r = 2 + 5 * (Q_sys/Q_max)**2 # typical requirement curve
527
528
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
529
530
ax1.plot(Q_sys*1000, h_sys, 'b-', linewidth=2, label='System curve')
531
ax1.plot(Q_sys*1000, h_pump, 'r-', linewidth=2, label='Pump curve')
532
ax1.plot(Q_op*1000, h_op, 'go', markersize=10, label=f'Operating point\\n({Q_op*1000:.1f} L/s, {h_op:.1f} m)')
533
ax1.set_xlabel('Flow Rate (L/s)')
534
ax1.set_ylabel('Head (m)')
535
ax1.set_title('Pump Operating Point')
536
ax1.legend()
537
ax1.grid(True, alpha=0.3)
538
539
# Efficiency curve
540
eta = 0.85 * (1 - ((Q_sys - 0.025)/0.025)**2)
541
eta = np.maximum(eta, 0)
542
ax2.plot(Q_sys*1000, eta*100, 'g-', linewidth=2, label='Efficiency')
543
ax2.plot(Q_sys*1000, NPSH_r, 'm--', linewidth=2, label='NPSH$_r$')
544
ax2.axvline(Q_op*1000, color='k', linestyle='--', alpha=0.5)
545
ax2.set_xlabel('Flow Rate (L/s)')
546
ax2.set_ylabel('Efficiency (\\%) / NPSH (m)')
547
ax2.set_title('Pump Performance')
548
ax2.legend()
549
ax2.grid(True, alpha=0.3)
550
551
plt.tight_layout()
552
save_fig('pump_selection.pdf')
553
554
# Calculate pump power
555
eta_op = 0.85 * (1 - ((Q_op - 0.025)/0.025)**2)
556
P_hydraulic = rho * 9.81 * Q_op * h_op
557
P_shaft = P_hydraulic / eta_op
558
\end{pycode}
559
560
\begin{figure}[H]
561
\centering
562
\includegraphics[width=\textwidth]{pump_selection.pdf}
563
\caption{Pump selection showing operating point and performance characteristics.}
564
\end{figure}
565
566
Pump power required: $P = \py{f"{P_shaft/1000:.2f}"}$ kW (at $\eta = \py{f"{eta_op*100:.1f}"}$\%)
567
568
\section{Conclusions}
569
570
This analysis demonstrates key aspects of pipe flow:
571
\begin{enumerate}
572
\item The Darcy-Weisbach equation provides accurate head loss predictions
573
\item Friction factors depend on both Reynolds number and relative roughness
574
\item The Moody diagram visualizes friction factor correlations
575
\item Minor losses from fittings can be significant in short pipe runs
576
\item Pipe diameter has a strong effect on pressure drop (varies as $D^{-5}$ for constant Q)
577
\item Parallel pipe analysis requires iterative solution for flow distribution
578
\item Pump operating point is determined by intersection of system and pump curves
579
\end{enumerate}
580
581
\end{document}
582
583