Skip to content
cfd-lab:~/en/posts/2026-05-19-darcy-forchhe…online
NOTE #048DAY TUE 유체역학DATE 2026.05.19READ 5 min readWORDS 944#유체역학#Porous-Media#Darcy-Law#Forchheimer#Brinkman#Permeability

Three Faces of Porous Flow — Darcy, Forchheimer, and Brinkman

A fluid moving through pores wears three different masks as its speed changes.

1856, Henry Darcy's report to the city of Dijon#

In the middle of the nineteenth century, Dijon needed a new system to deliver clean water to its citizens. The civil engineer Henry Darcy proposed filtering river water through a sandbank outside the city, and he ran a stubbornly simple experiment to back up the plan. Drive a pressure drop across a vertical column packed with sand, and measure the flow that comes out the bottom. The relationship turned out to be strictly linear.

Fluid mechanics up to that point spoke only the language of free flow — Bernoulli, Euler, Navier–Stokes. Darcy's single line opened up another world that had been sitting quietly next to it.

Today's post starts at that line. As the velocity rises, Forchheimer's quadratic term sneaks in. When a wall comes close, Brinkman's viscous Laplacian comes back to life. We will walk through the three faces a fluid puts on as it pushes through pores, using a pump curve and a channel profile.

When the pump curve starts to bend — the Forchheimer correction#

Darcy's law reads

uD=Kμp\mathbf{u}_D = -\frac{K}{\mu}\,\nabla p

where uD\mathbf{u}_D is the Darcy velocity (the cross-section-averaged flow including both pores and solid, m/s), KK is the permeability (m²), μ\mu is the dynamic viscosity, and p\nabla p is the pressure gradient. The fluid inside the actual pore moves faster: u=uD/ϕ\mathbf{u} = \mathbf{u}_D / \phi, with ϕ\phi the porosity (the volume fraction of pores per unit cell).

A small bump in velocity changes the picture. Define a pore-scale Reynolds number from the grain diameter dd and pore velocity uu,

Rep=ρudμ\mathrm{Re}_p = \frac{\rho\,u\,d}{\mu}

Once Rep\mathrm{Re}_p climbs past one, the pressure-drop curve begins to bend away from a straight line. Forchheimer (1901) wrote down that bend as a quadratic term.

p=μKuD+βρuDuD-\nabla p = \frac{\mu}{K}\,\mathbf{u}_D + \beta\,\rho\,\lvert\mathbf{u}_D\rvert\,\mathbf{u}_D

The coefficient β\beta (1/m) sets the speed at which inertial losses — fluid having to swerve around each grain — overtake viscous losses. Gravel beds, heat-sink fins, and catalyst reactors all live on this curve in practice.

When the wall is still alive — Brinkman's return of viscosity#

Darcy and Forchheimer both absorb viscosity into a grain-scale loss term. That assumption breaks the moment the porous region touches a wall or an open fluid layer. No-slip forces the velocity to zero at the wall, and inside that thin film the bare viscous Laplacian has to be alive again.

Brinkman (1947) put that term back in.

p=μKuDμeff2uD-\nabla p = \frac{\mu}{K}\,\mathbf{u}_D - \mu_{\text{eff}}\,\nabla^2\mathbf{u}_D

μeff\mu_{\text{eff}} is an effective viscosity, often taken as μ/ϕ\mu/\phi or calibrated from experiment. The ruler of choice is the Darcy number

Da=KL2\mathrm{Da} = \frac{K}{L^2}

with LL a macroscopic length such as the channel half-width. When Da0\mathrm{Da} \to 0 the channel is filled by a Darcy plug. When Da\mathrm{Da} \to \infty viscosity comes back and the profile relaxes to Poiseuille parabolas. In between, a thin Brinkman boundary layer of thickness K\sqrt{K} shows up — and it has to be small enough to span only one or two pores before plain Darcy is safe.

Pore-fraction averaging — when fluid and solid share a single cell#

Imagine a CFD cell that contains both grains of sand (solid) and water in between (fluid). The conservation laws are written as pore-fraction-weighted averages. Mass conservation reads

(ϕρf)t+ ⁣(ρfuD)=0\frac{\partial (\phi\,\rho_f)}{\partial t} + \nabla \!\cdot (\rho_f\,\mathbf{u}_D) = 0

and that form is naturally conservative if face fluxes use uD\mathbf{u}_D. If a neighbor cell has ϕ=0\phi = 0 (a solid wall), the face flux must vanish too — otherwise spurious mass leaks into a pore that does not exist. Numerically, ϕ=0\phi = 0 cells are stabilized by forcing the diagonal to one with zero off-diagonals, or by clipping ϕ\phi to a tiny value like 10810^{-8}.

The energy equation is trickier. Under the local thermal equilibrium assumption (fluid and solid share the same temperature), we have to combine the conductivities into an effective keffk_{\text{eff}}. Three mixing rules show up most often.

klin=ϕkf+(1ϕ)kskharm1=ϕkf+1ϕkskGM=kfϕks1ϕ\begin{aligned} k_{\text{lin}} &= \phi\,k_f + (1-\phi)\,k_s \\ k_{\text{harm}}^{-1} &= \frac{\phi}{k_f} + \frac{1-\phi}{k_s} \\ k_{\text{GM}} &= k_f^{\phi}\,k_s^{1-\phi} \end{aligned}

Linear matches grains lined up in parallel, harmonic matches grains stacked in series, and the geometric mean (GM) matches random orientations best. Soils, rocks, and porous metals usually fit the GM model.

Python — three models on a single channel#

The 1-D non-dimensional momentum balance for a walled porous channel is

d2UdY21DaU+G=0,U(0)=U(1)=0\frac{d^2 U}{dY^2} - \frac{1}{\mathrm{Da}}\,U + G = 0,\qquad U(0)=U(1)=0

where GG is the non-dimensional pressure forcing, Da\mathrm{Da} is the Darcy number, and UU is the non-dimensional velocity. A closed-form solution exists, U(Y)=GDa(1cosh((Y0.5)/Da)/cosh(0.5/Da))U(Y) = G\,\mathrm{Da}\,\bigl(1 - \cosh((Y-0.5)/\sqrt{\mathrm{Da}}) / \cosh(0.5/\sqrt{\mathrm{Da}})\bigr), but a numerical solve makes the structure clearer.

import numpy as np
 
def brinkman_channel_velocity(Da: float, G: float = 1.0, N: int = 200):
    """Steady 1-D Brinkman profile in a walled porous channel. Da = K/L²."""
    Y = np.linspace(0.0, 1.0, N)
    dY = Y[1] - Y[0]
    # U'' - U/Da + G = 0  →  tridiagonal system
    main = -2.0 / dY**2 - 1.0 / Da
    off  =  1.0 / dY**2
    A = np.zeros((N, N))
    rhs = np.full(N, -G)
    A[0, 0] = 1.0;   rhs[0]  = 0.0   # left wall U=0
    A[-1, -1] = 1.0; rhs[-1] = 0.0   # right wall U=0
    for i in range(1, N - 1):
        A[i, i - 1] = off
        A[i, i]     = main
        A[i, i + 1] = off
    return Y, np.linalg.solve(A, rhs)
 
 
def darcy_forchheimer_pressure_drop(u: np.ndarray, mu: float, K: float,
                                    beta: float, rho: float):
    """Pressure drop in a uniform porous column: Darcy + Forchheimer."""
    visc_loss    = (mu / K) * u
    inertia_loss = beta * rho * u * np.abs(u)
    return visc_loss + inertia_loss
 
 
if __name__ == "__main__":
    # 1) Brinkman profile: sweep Da, watch the mid-channel velocity
    for Da in [1e-4, 1e-2, 1e0]:
        Y, U = brinkman_channel_velocity(Da)
        print(f"Da = {Da:7.0e}   U_mid = {U[len(U)//2]:.4f}")
 
    # 2) Gravel-bed pump curve (K=1e-8 m², β=1e3 1/m)
    mu, K, beta, rho = 1e-3, 1e-8, 1.0e3, 1000.0
    u = np.linspace(0.0, 0.5, 6)
    dp = darcy_forchheimer_pressure_drop(u, mu, K, beta, rho)
    print("\n u [m/s]    ΔP/L [Pa/m]")
    for ui, dpi in zip(u, dp):
        print(f"  {ui:5.2f}      {dpi:.3e}")

Run it and the mid-channel velocity flattens as Da\mathrm{Da} shrinks — most of the channel is now a Darcy plug. The pump curve stays nearly linear up to u0.05u \approx 0.05 m/s, then bends visibly above 0.20.2 m/s. A pump designed on Darcy alone would mis-size the required pressure by almost a factor of two right there.

Sliders for the bending pump curve and the wall-bound profile#

Play with the parameters in the simulations below.

Pump curve · ΔP/L vs Darcy velocity u

Solid cyan: ΔP/L = (μ/K) u + βρ u². Dashed gray: Darcy-only (μ/K) u. Red dashed line: u* where the two terms balance.

Set β\beta to zero and the curve is a straight line. Push β\beta up and the curve bends upward. Once your design point in the gravel-bed regime (β103\beta \sim 10^3) crosses uu^{\star}, a Darcy-only design under-predicts the actual pressure loss by nearly half.

1D channel · Brinkman steady profile U(Y) for U″ − U/Da + 1 = 0, U(0)=U(1)=0

Drop Da below ~10⁻³: the profile flattens into a Darcy plug. Increase Da past 1: it relaxes back to Poiseuille (dashed gray). The red dashed lines mark the Brinkman boundary-layer thickness δ ≈ √Da.

Drop Da\mathrm{Da} to 10410^{-4}: the center of the channel becomes a flat plug. From the plug edge to the wall, a thin viscous layer (the Brinkman boundary layer) of thickness Da\sqrt{\mathrm{Da}} survives. That layer is the fingerprint of the interface between the porous medium and the free flow.

Three faces of porous flow — a line each#

  • Darcy (Rep<1\mathrm{Re}_p < 1): pressure gradient balances viscous loss. The straight line is the truth.
  • Forchheimer (Rep1\mathrm{Re}_p \gtrsim 1): inertial losses around grains pile on. The pump curve bends.
  • Brinkman (DaL\sqrt{\mathrm{Da}} \lesssim L): a wall or an open flow lives nearby, so the viscous Laplacian wakes back up. A boundary layer of thickness K\sqrt{K} reappears.

The same sand or gravel switches between these three faces depending on where Reynolds and Darcy numbers land. Pinning those two numbers down before any simulation already settles nine-tenths of the model-choice question.

Share if you found it helpful.