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.
Comments