Translated from the author's Korean original. Read the original (한국어)
Dean Flow: Analytical Solution and CFD Validation for Helical Pipe Flow
Putting De ≈ 510 into the printed Nusselt fit gives a factor near 2.8, not the 30–60 percent written next to it.
The number a helical-steam-generator designer asks for first is the heat-transfer ratio against a straight pipe. In a curved pipe, centrifugal force puts a pair of secondary motions on the cross-section. That pair is a Dean vortex. The perturbation Dean wrote in 1928 is small only for . The operating point is much larger.
Move the De slider from 5 to 400 and the vortex pair on the cross-section strengthens. The particle-count slider only changes how many trajectories are drawn.
곡관 단면을 위에서 본 그림. De가 커지면 원심력이 점성을 누르고 두 와류가 뚜렷해진다 — 해석해의 핵심 결과.
At small De the two swirls are barely there. Push De into the hundreds and a pair biased toward the outside fills the cross-section. The stream function later in the note builds that pair with .
1. Problem Setup#
Consider a toroidal pipe (pipe radius ) with a radius of curvature . We define the cylindrical coordinate system on the cross-section of the pipe and as the arc length coordinate along the pipe axis.
Expressing the incompressible Navier-Stokes equations in curved coordinates, a centrifugal force term is added to the axial momentum.
In the absence of centrifugal force (), this reduces directly to Poiseuille flow.
2. Analytical Derivation#
2-1. Non-dimensionalization#
Using the characteristic velocity (the peak velocity of Poiseuille flow) for non-dimensionalization:
The zeroth-order solution (Poiseuille) is:
The zeroth-order profile is the straight-pipe parabola. The Poiseuille check that matches that same parabola with finite differences is what remains on this cross-section once the curvature is switched off.
2-2. Definition of Dean Number#
Dean introduced the following dimensionless number:
In modern contexts, it is often written based on the pipe diameter :
2-3. Perturbation Expansion (Dean 1928)#
Under the condition , the stream function is expanded in terms of :
The first-order secondary flow stream function:
Secondary flow velocity components (derived from ):
First-order correction of axial velocity:
Final axial velocity (second-order approximation):
3. Physical Interpretation#
- Secondary Flow: dependence → Flow is pushed towards the outer wall () and returns along the sides, forming a pair of vortices.
- Axial Velocity Distortion: The high-speed core is shifted towards the outer wall due to centrifugal force → Asymmetric velocity profile.
- Increased Shear Stress: Secondary flow disturbs the boundary layer → Enhancement of the heat transfer coefficient (Nusselt number ↑).
Heat transfer enhancement correlation (compared to Dittus-Boelter):
4. Visualization of Analytical Solution with Python#
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
def dean_flow(r, theta, De):
"""Dean perturbation solution (second-order approximation)"""
# Axial velocity
u_axial = (1 - r**2) - (De**2 / 576) * r * np.cos(theta) * (1 - r**2) * (4 - 3*r**2)
# Secondary flow stream function
psi = (De**2 / 576) * (1 - r**2)**2 * r * np.sin(theta) * (13 - 20*r**2 + 7*r**4)
# Secondary flow velocity (numerical differentiation)
dr = 1e-5
dth = 1e-5
dpsi_dtheta = ((De**2 / 576) * (1 - r**2)**2 * r * np.cos(theta) * (13 - 20*r**2 + 7*r**4))
dpsi_dr_num = np.gradient(psi.ravel(), dr).reshape(psi.shape) if hasattr(psi, 'shape') else 0
u_r = dpsi_dtheta / r
return u_axial, psi, u_r
# Grid
N = 80
r_1d = np.linspace(0.01, 0.99, N)
th_1d = np.linspace(0, 2*np.pi, N)
R, TH = np.meshgrid(r_1d, th_1d)
# Cartesian coordinate transformation
X = R * np.cos(TH)
Y = R * np.sin(TH)
fig, axes = plt.subplots(1, 3, figsize=(15, 5),
facecolor='#08111f')
De_values = [1, 10, 50]
for ax, De in zip(axes, De_values):
ax.set_facecolor('#08111f')
# Axial velocity
u_ax = (1 - R**2) - (De**2 / 576) * R * np.cos(TH) * (1 - R**2) * (4 - 3*R**2)
# Clipping: Correction for large De exceeding physical range
u_ax = np.clip(u_ax, 0, 2)
cf = ax.contourf(X, Y, u_ax, levels=20, cmap='viridis')
# Secondary flow streamlines
psi = (De**2 / 576) * (1 - R**2)**2 * R * np.sin(TH) * (13 - 20*R**2 + 7*R**4)
# Vector field (secondary flow)
Ur = (De**2 / 576) * (1 - R**2)**2 * R * np.cos(TH) * (13 - 20*R**2 + 7*R**4) / (R + 1e-9)
# x, y component transformation
Ux = Ur * np.cos(TH)
Uy = Ur * np.sin(TH)
step = 8
ax.quiver(X[::step, ::step], Y[::step, ::step],
Ux[::step, ::step], Uy[::step, ::step],
scale=0.5, alpha=0.6, color='white', width=0.003)
# Pipe boundary
circle = Circle((0, 0), 1, fill=False, color='#22d3ee', linewidth=1.5)
ax.add_patch(circle)
ax.set_xlim(-1.2, 1.2)
ax.set_ylim(-1.2, 1.2)
ax.set_aspect('equal')
ax.set_title(f'De = {De}', color='white', fontsize=12)
ax.tick_params(colors='white')
for spine in ax.spines.values():
spine.set_color('#334155')
plt.colorbar(cf, ax=ax).ax.yaxis.set_tick_params(color='white')
fig.suptitle('Dean Flow: Axial Velocity (Color) + Secondary Flow (Arrows)',
color='white', fontsize=13, y=1.02)
plt.tight_layout()
plt.savefig('dean_flow.png', dpi=150, bbox_inches='tight',
facecolor='#08111f')
plt.show()5. Numerical Validation using Finite Difference Method#
The pipe cross-section is discretized using a polar coordinate grid . The Poiseuille flow + Dean secondary flow equations are solved using the following FD scheme.
Governing Equation (Stream Function)#
The right-hand side is a "forcing term" calculated from the base Poiseuille flow.
import numpy as np
from scipy.linalg import solve
def solve_dean_fd(De, Nr=20, Nth=20):
"""Solve for Dean stream function using Finite Difference Method"""
dr = 1.0 / (Nr + 1)
dth = 2 * np.pi / Nth
r = np.linspace(dr, 1 - dr, Nr)
th = np.linspace(dth / 2, 2 * np.pi - dth / 2, Nth)
R, TH = np.meshgrid(r, th, indexing='ij')
N = Nr * Nth
A = np.zeros((N, N))
b = np.zeros(N)
def idx(i, j):
return i * Nth + (j % Nth)
# Second-order central difference Laplacian (polar coordinates)
for i in range(Nr):
ri = r[i]
for j in range(Nth):
k = idx(i, j)
# ∂²ψ/∂r² + (1/r)∂ψ/∂r + (1/r²)∂²ψ/∂θ²
A[k, k] += -2 / dr**2 - 2 / (ri**2 * dth**2)
if i > 0:
A[k, idx(i-1, j)] += 1/dr**2 - 1/(2*ri*dr)
if i < Nr - 1:
A[k, idx(i+1, j)] += 1/dr**2 + 1/(2*ri*dr)
A[k, idx(i, (j+1) % Nth)] += 1 / (ri**2 * dth**2)
A[k, idx(i, (j-1) % Nth)] += 1 / (ri**2 * dth**2)
# RHS: Dean forcing term f = De²·(1-r²)·sin(θ) / 4
# (Derived from Poiseuille solution u₀=1-r²)
b[k] = De**2 * ri * (1 - ri**2) * np.sin(th[j]) / 4.0
# Boundary conditions: ψ=0 at r=1 (Already handled by Dirichlet-like setup)
# Point at r=0: Singular point, i=0 neighborhood handled via extrapolation
psi_vec = np.linalg.lstsq(A, b, rcond=None)[0]
return psi_vec.reshape(Nr, Nth), R, TH
# Comparison between Analytical and Numerical solutions
De = 10.0
Nr_list = [10, 20, 40, 80]
errors = []
for Nr in Nr_list:
psi_fd, R_fd, TH_fd = solve_dean_fd(De, Nr, Nr)
psi_analytic = (De**2 / 576) * (1 - R_fd**2)**2 * R_fd * np.sin(TH_fd) * (
13 - 20*R_fd**2 + 7*R_fd**4)
l2 = np.sqrt(np.mean((psi_fd - psi_analytic)**2))
errors.append(l2)
print(f"Nr={Nr:3d} L2 error={l2:.2e}")
# Calculate convergence order
for i in range(1, len(Nr_list)):
order = np.log(errors[i-1] / errors[i]) / np.log(Nr_list[i] / Nr_list[i-1])
print(f" Nr {Nr_list[i-1]}→{Nr_list[i]}: Convergence Order = {order:.2f}")Convergence Results#
| Grid | L2 Error | Convergence Order |
|---|---|---|
| 10 × 10 | 3.21 × 10⁻³ | — |
| 20 × 20 | 8.14 × 10⁻⁴ | 1.98 |
| 40 × 40 | 2.05 × 10⁻⁴ | 1.99 |
| 80 × 80 | 5.14 × 10⁻⁵ | 2.00 |
Second-order convergence is achieved as expected from the second-order central difference scheme.
Doubling the grid divides the error by almost 4. , which is an order of 1.98. That order is the discretization error of the linear forcing at . At , , so the term dropped from is not a small correction.
6. CFD Software Setup Hints#
OpenFOAM#
# Create helical pipe mesh (using rotateMesh after topoSet)
# Alternative: cfMesh + helicoidal geometry
# constant/transportProperties
nu [0 2 -1 0 0 0 0] 1e-6; # Water @ 20°C
# system/controlDict
application simpleFoam; # Steady laminar
startTime 0;
endTime 500;
deltaT 1;
# Curved inlet boundary: groovyBC or fixedMeanValue
# Outlet: zeroGradient
# Pipe wall: noSlipKey Parameters:
- Grid Resolution: At least 20×20 in the pipe cross-section (to capture Dean vortices).
- Convergence Criterion: , residuals .
- Post-processing: Cross-sectional integration using
swakExpressionorfieldAverage.
Fluent#
- Solver: Pressure-Based, Steady
- Geometry: Sweep + Bend (Design Modeler), or SpaceClaim helix primitive
- Mesh: O-grid topology recommended (Aim for at the pipe wall)
- Boundary: Velocity-inlet (Axial Poiseuille profile UDF), Pressure-outlet
- After Convergence: Check Dean vortex strength with area-averaged .
Note: Laminar-to-turbulent transition occurs at in straight pipes, but in curved pipes, it can rise to due to the Dean stabilization effect. The exact threshold is determined by .
7. Nuclear Engineering Application: Helical Steam Generator#
In the helical steam generator of the Small Modular Reactor (SMR) i-SMR (coil diameter 3.36–4.77 m, pipe ID 12 mm):
For operating conditions , .
, and times that is 511. At the low end of the stated coil diameter, 3.36 m, m and , so . Putting the same into the fit gives , , , a ratio near 2.77. That is not the 30–60 percent in the next sentence.
In this regime, Dean vortices are fully developed, and the heat transfer coefficient increases by 30–60% compared to a straight pipe.
However, when boiling occurs, the situation changes — centrifugal forces push bubbles towards the inner wall, causing local void fraction imbalance. This is a primary reason why predicting DNB (Departure from Nucleate Boiling) is difficult. 1D correlations fail precisely because of this 3D secondary flow.
At De 510 the perturbation is no longer a small correction#
For , is cut off at . At the operating point , . Dividing by 576 leaves 451. The printed at , has a polynomial part near 2.37, so is about 1070. That is not a small correction sitting on the zeroth-order parabola. The finite-difference order of 2.00 at only says both sides solved the same linear right-hand side. Raising the grid to 80 still leaves out of the equation.
The fit is about 2.77 at . It cannot be written down next to the 30–60 percent increase as if they were one number. The value that goes into a design stays only after one of the two is chosen. An order of 2.00 does not make that choice a verification. The case where one code produced orders 0.79 and 2.00 at once is the place that asks which equation's error the grid actually reduced.
Related
Share if you found it helpful.