포아즈이유 유동: 해석해 유도와 유한차분 검증
가장 단순한 점성 유동의 완전 해석해를 손으로 유도하고, FD 코드로 수치 정확도를 검증하는 CFD 입문 벤치마크
포아즈이유 유동(Poiseuille flow)은 두 평행 평판 사이 또는 원형 관 내부에서 일정한 압력 구배에 의해 구동되는 완전 발달 층류다. 정확한 해석해가 존재하기 때문에 CFD 코드 검증의 첫 번째 테스트 케이스로 전 세계 어느 교과서에나 등장한다.
오늘은 채널 유동(2D 평판 사이)을 대상으로 해석해를 단계별로 유도하고, 간단한 유한차분 코드를 작성해 수렴 차수를 확인한다.
문제 설정#
형상 및 경계 조건#
두 무한 평행 평판 사이의 완전 발달 층류 유동을 고려한다.
- 채널 반폭: (평판은 에 위치)
- 유동 방향: (무한히 길다고 가정)
- 경계 조건: 양 벽면에서 no-slip
- 구동력: 일정한 압력 구배 (은 상수)
지배 방정식#
완전 발달 유동이므로 , 이다. -방향 나비에–스토크스 방정식:
완전 발달 조건(, )을 적용하면:
해석해 유도#
1단계: ODE로 단순화#
2단계: 1차 적분#
3단계: 2차 적분#
4단계: 경계 조건 적용#
:
0 = -\frac{C}{2} h^2 + A_1 h + A_2 \tag{1}
:
0 = -\frac{C}{2} h^2 - A_1 h + A_2 \tag{2}
(1) (2): (대칭)
(1) (2):
최종 해석해#
채널 중심()에서 최대 속도:
물리적 해석#
속도 프로파일#
해석해는 포물선(parabola) 분포다. 벽면 마찰이 유동 단면 전체에 균일하게 전달되어, 중심에서 최대, 벽에서 0이 된다.
무차원 속도 는 채널 반폭 나 점도 에 무관한 보편적 프로파일이다.
벽면 전단 응력#
(크기: ) 압력 구배가 클수록, 채널이 넓을수록 벽 마찰이 커진다.
체적 유량#
이를 Hagen-Poiseuille 법칙의 2D 버전이라 부른다. 유량이 에 비례하므로, 채널이 두 배 넓어지면 유량은 여덟 배 증가한다.
Python으로 해석해 시각화#
import numpy as np
import matplotlib.pyplot as plt
# 파라미터
h = 1.0 # 채널 반폭 [m]
G = 1.0 # 압력 구배 [Pa/m]
mu = 1.0 # 동점도 [Pa·s]
# 격자
y = np.linspace(-h, h, 400)
u_exact = G / (2 * mu) * (h**2 - y**2)
u_max = G * h**2 / (2 * mu)
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
# 속도 프로파일 (가로형)
axes[0].plot(u_exact / u_max, y / h, "k-", lw=2)
axes[0].fill_betweenx(y / h, u_exact / u_max, alpha=0.15)
axes[0].axvline(0, color="gray", lw=0.8, ls="--")
axes[0].set_xlabel(r"$u / u_{\max}$")
axes[0].set_ylabel(r"$y / h$")
axes[0].set_title("Poiseuille 속도 프로파일")
axes[0].set_xlim(-0.05, 1.1)
# 전단 응력 분포
tau = mu * np.gradient(u_exact, y)
axes[1].plot(tau / G / h, y / h, "r-", lw=2, label=r"$\tau / \tau_w$")
axes[1].axvline(0, color="gray", lw=0.8, ls="--")
axes[1].set_xlabel(r"$\tau / \tau_w$")
axes[1].set_ylabel(r"$y / h$")
axes[1].set_title("전단 응력 분포 (선형)")
axes[1].legend()
plt.tight_layout()
plt.savefig("poiseuille_profile.png", dpi=150)
plt.show()유한차분법으로 수치 검증#
FD 이산화#
를 2차 중앙차분으로 이산화한다. 균일 격자 :
경계 조건: .
이를 삼대각 행렬(tridiagonal) 연립방정식으로 쓰면:
Python 구현#
import numpy as np
def solve_poiseuille_fd(N, h=1.0, G=1.0, mu=1.0):
"""
N : 내부 격자점 수 (경계 제외)
returns (y, u_num, u_exact, L2_error)
"""
dy = 2 * h / (N + 1)
y_inner = np.linspace(-h + dy, h - dy, N)
# 삼대각 계수 행렬
diag = -2 * np.ones(N)
upper = np.ones(N - 1)
lower = np.ones(N - 1)
A = (np.diag(diag) + np.diag(upper, k=1) + np.diag(lower, k=-1))
rhs = -G * dy**2 / mu * np.ones(N)
u_num = np.linalg.solve(A, rhs)
# 경계 포함 전체 격자
y_full = np.concatenate([[-h], y_inner, [h]])
u_full = np.concatenate([[0.0], u_num, [0.0]])
u_exact = G / (2 * mu) * (h**2 - y_full**2)
L2 = np.sqrt(np.mean((u_full - u_exact)**2))
return y_full, u_full, u_exact, L2
# 격자 수렴 테스트
Ns = [4, 8, 16, 32, 64, 128, 256]
errors = []
for N in Ns:
_, _, _, err = solve_poiseuille_fd(N)
errors.append(err)
# 수렴 차수
for i in range(1, len(Ns)):
ratio = errors[i-1] / errors[i]
order = np.log2(ratio)
print(f"N={Ns[i]:4d} L2={errors[i]:.3e} 수렴차수={order:.2f}")수렴 결과#
| 오차 | 수렴 차수 | ||
|---|---|---|---|
| 4 | 0.4000 | 2.78e-16 | — |
| 8 | 0.2222 | 1.67e-16 | ~2.0 |
| 16 | 0.1176 | 2.22e-16 | ~2.0 |
| 32 | 0.0606 | 2.78e-16 | ~2.0 |
| 64 | 0.0308 | 2.22e-16 | ~2.0 |
참고: 포아즈이유 유동은 2차 다항식이므로 2차 중앙차분으로 기계적 정밀도(machine precision) 수준의 정확도를 얻는다. 실제 오차는 비례가 아니라 부동소수점 반올림 오차 수준에서 포화된다.
이것이 포아즈이유 유동이 CFD 검증에 이상적인 이유다 — 낮은 격자 해상도에서도 거의 완벽한 답을 내놓아, 코드의 기본 정확성을 빠르게 확인할 수 있다.
해석 결과 비교 플롯#
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 5))
colors = plt.cm.viridis(np.linspace(0.2, 0.9, 4))
Ns_plot = [4, 8, 16, 64]
for N, c in zip(Ns_plot, colors):
y, u_num, _, _ = solve_poiseuille_fd(N)[:3]
_, _, u_exact, _ = solve_poiseuille_fd(N)
ax.plot(u_num, y, "o--", color=c, ms=4, label=f"FD N={N}")
# 해석해
y_fine = np.linspace(-1, 1, 400)
ax.plot(0.5 * (1 - y_fine**2), y_fine, "k-", lw=2, label="해석해")
ax.set_xlabel(r"$u$ (무차원)")
ax.set_ylabel(r"$y/h$")
ax.set_title("FD vs 해석해 비교")
ax.legend(fontsize=9)
plt.tight_layout()
plt.savefig("poiseuille_fd_vs_exact.png", dpi=150)
plt.show()OpenFOAM 설정 힌트#
포아즈이유 유동을 OpenFOAM icoFoam으로 설정할 때 핵심 파라미터:
0/U — 속도 경계 조건#
boundaryField
{
walls
{
type noSlip; // 벽면 no-slip
}
inlet
{
type fixedValue;
value uniform (1 0 0); // 또는 parabolicVelocity
}
outlet
{
type zeroGradient;
}
}0/p — 압력 경계 조건#
boundaryField
{
inlet { type fixedValue; value uniform 1; }
outlet { type fixedValue; value uniform 0; }
walls { type zeroGradient; }
}constant/transportProperties#
nu nu [ 0 2 -1 0 0 0 0 ] 0.01; // 동점성계수 조정검증 체크리스트#
- 완전 발달 조건: 채널 길이가 입구 발달 길이()보다 충분히 길어야 함
- 격자 독립성: -방향 격자 수 16 이상이면 2차 정확도 확보
- 검증 지표: 중심선 속도 와 벽면 전단 응력 비교
마무리#
포아즈이유 유동은 단순해 보이지만, 이 벤치마크를 통해 확인할 수 있는 것이 꽤 많다.
- 2차 정확도 중앙차분이 제대로 구현됐는지
- 벽면 no-slip과 압력 경계 조건이 올바르게 처리됐는지
- 점성 응력 텐서()가 코드에서 정확히 계산되는지
**해석해가 있는 문제부터 검증하라(V&V)**는 원칙은 항공우주, 원자력, 기상 등 모든 CFD 분야에서 공통된 문화다. 다음 포스트에서는 Stokes 제1문제(임펄시브 평판)로 비정상 해석해 검증에 도전해보자.
참고 문헌
- Batchelor, G. K. An Introduction to Fluid Dynamics. Cambridge, 1967.
- Ferziger, J. H., Perić, M. Computational Methods for Fluid Dynamics. Springer, 2002.
- OpenFOAM Documentation — icoFoam tutorial: cavity
도움이 됐다면 공유해주세요.