Skip to content
cfd-lab:~/posts/2026-03-28-poiseuille-fl…● online
NOTE #015DAY SAT 논문리뷰DATE 2026.03.28READ 10 min readWORDS 1,875#해석해#고전유동#CFD검증#포아즈이유#유한차분

포아즈이유 유동: 해석해 유도와 유한차분 검증

가장 단순한 점성 유동의 완전 해석해를 손으로 유도하고, FD 코드로 수치 정확도를 검증하는 CFD 입문 벤치마크

포아즈이유 유동(Poiseuille flow)은 두 평행 평판 사이 또는 원형 관 내부에서 일정한 압력 구배에 의해 구동되는 완전 발달 층류다. 정확한 해석해가 존재하기 때문에 CFD 코드 검증의 첫 번째 테스트 케이스로 전 세계 어느 교과서에나 등장한다.

오늘은 채널 유동(2D 평판 사이)을 대상으로 해석해를 단계별로 유도하고, 간단한 유한차분 코드를 작성해 수렴 차수를 확인한다.

문제 설정#

형상 및 경계 조건#

두 무한 평행 평판 사이의 완전 발달 층류 유동을 고려한다.

  • 채널 반폭: hh (평판은 y=±hy = \pm h에 위치)
  • 유동 방향: xx (무한히 길다고 가정)
  • 경계 조건: 양 벽면에서 no-slip \Rightarrow u(±h)=0u(\pm h) = 0
  • 구동력: 일정한 압력 구배 dpdx=G<0\dfrac{dp}{dx} = -G < 0 (G>0G > 0은 상수)

지배 방정식#

완전 발달 유동이므로 /x=0\partial/\partial x = 0, v=0v = 0이다. xx-방향 나비에–스토크스 방정식:

ρ(uux+vuy)=dpdx+μ2uy2\rho \left( u \frac{\partial u}{\partial x} + v \frac{\partial u}{\partial y} \right) = -\frac{dp}{dx} + \mu \frac{\partial^2 u}{\partial y^2}

완전 발달 조건(u/x=0\partial u/\partial x = 0, v=0v = 0)을 적용하면:

μd2udy2=dpdx=G\mu \frac{d^2 u}{dy^2} = \frac{dp}{dx} = -G

해석해 유도#

1단계: ODE로 단순화#

d2udy2=GμC(C>0)\frac{d^2 u}{dy^2} = -\frac{G}{\mu} \equiv -C \quad (C > 0)

2단계: 1차 적분#

dudy=Cy+A1\frac{du}{dy} = -C y + A_1

3단계: 2차 적분#

u(y)=C2y2+A1y+A2u(y) = -\frac{C}{2} y^2 + A_1 y + A_2

4단계: 경계 조건 적용#

u(+h)=0u(+h) = 0:

0 = -\frac{C}{2} h^2 + A_1 h + A_2 \tag{1}

u(h)=0u(-h) = 0:

0 = -\frac{C}{2} h^2 - A_1 h + A_2 \tag{2}

(1) - (2): 0=2A1hA1=00 = 2 A_1 h \Rightarrow A_1 = 0 (대칭)

(1) ++ (2): 0=Ch2+2A2A2=Ch220 = -C h^2 + 2A_2 \Rightarrow A_2 = \dfrac{C h^2}{2}

최종 해석해#

u(y)=G2μ(h2y2)\boxed{u(y) = \frac{G}{2\mu}\bigl(h^2 - y^2\bigr)}

채널 중심(y=0y=0)에서 최대 속도:

umax=Gh22μu_{\max} = \frac{G h^2}{2\mu}

물리적 해석#

속도 프로파일#

해석해는 포물선(parabola) 분포다. 벽면 마찰이 유동 단면 전체에 균일하게 전달되어, 중심에서 최대, 벽에서 0이 된다.

무차원 속도 u/umax=1(y/h)2u/u_{\max} = 1 - (y/h)^2는 채널 반폭 hh나 점도 μ\mu에 무관한 보편적 프로파일이다.

벽면 전단 응력#

τw=μdudyy=h=μGμ(h)=Gh\tau_w = \mu \left.\frac{du}{dy}\right|_{y=h} = \mu \cdot \frac{G}{\mu}(-h) = -G h

(크기: τw=Gh\tau_w = G h) 압력 구배가 클수록, 채널이 넓을수록 벽 마찰이 커진다.

체적 유량#

Q=hhudy=G2μhh(h2y2)dy=G2μ4h33=2Gh33μQ = \int_{-h}^{h} u \, dy = \frac{G}{2\mu} \int_{-h}^{h} (h^2 - y^2) \, dy = \frac{G}{2\mu} \cdot \frac{4h^3}{3} = \frac{2 G h^3}{3\mu}

이를 Hagen-Poiseuille 법칙의 2D 버전이라 부른다. 유량이 h3h^3에 비례하므로, 채널이 두 배 넓어지면 유량은 여덟 배 증가한다.

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 이산화#

d2u/dy2=G/μd^2u/dy^2 = -G/\mu를 2차 중앙차분으로 이산화한다. 균일 격자 Δy=2h/(N1)\Delta y = 2h/(N-1):

ui+12ui+ui1(Δy)2=Gμ\frac{u_{i+1} - 2u_i + u_{i-1}}{(\Delta y)^2} = -\frac{G}{\mu}

경계 조건: u0=uN1=0u_0 = u_{N-1} = 0.

이를 삼대각 행렬(tridiagonal) 연립방정식으로 쓰면:

(2112112)u=G(Δy)2μ1\begin{pmatrix} -2 & 1 \\ 1 & -2 & 1 \\ & \ddots & \ddots & \ddots \\ & & 1 & -2 \end{pmatrix} \mathbf{u} = -\frac{G (\Delta y)^2}{\mu} \mathbf{1}

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}")

수렴 결과#

NNΔy\Delta yL2L_2 오차수렴 차수
40.40002.78e-16
80.22221.67e-16~2.0
160.11762.22e-16~2.0
320.06062.78e-16~2.0
640.03082.22e-16~2.0

참고: 포아즈이유 유동은 2차 다항식이므로 2차 중앙차분으로 기계적 정밀도(machine precision) 수준의 정확도를 얻는다. 실제 오차는 Δy2\Delta y^2 비례가 아니라 부동소수점 반올림 오차 수준에서 포화된다.

이것이 포아즈이유 유동이 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;  // 동점성계수 조정

검증 체크리스트#

  1. 완전 발달 조건: 채널 길이가 입구 발달 길이(Ldev0.05RehL_{dev} \approx 0.05 \, Re \cdot h)보다 충분히 길어야 함
  2. 격자 독립성: yy-방향 격자 수 16 이상이면 2차 정확도 확보
  3. 검증 지표: 중심선 속도 uc=Gh2/(2μ)u_c = G h^2 / (2\mu)와 벽면 전단 응력 τw=Gh\tau_w = G h 비교

마무리#

포아즈이유 유동은 단순해 보이지만, 이 벤치마크를 통해 확인할 수 있는 것이 꽤 많다.

  • 2차 정확도 중앙차분이 제대로 구현됐는지
  • 벽면 no-slip과 압력 경계 조건이 올바르게 처리됐는지
  • 점성 응력 텐서(μ2u\mu \nabla^2 \mathbf{u})가 코드에서 정확히 계산되는지

**해석해가 있는 문제부터 검증하라(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

도움이 됐다면 공유해주세요.