Exercise 11.4
The CFL Condition - Why Explicit Time-Stepping Pays the Price
Implement the explicit time-stepping method. Calculate the CFL limit for the reservoir parameters in this chapter. Verify by running the explicit method with a time step just below and just above the CFL limit. Show that the solution diverges above the limit.
---
The implicit simulator you have been using (the embedded Reservoir1D) is unconditionally stable: you can march it forward with a 30-day step and it never blows up. An explicit scheme is cheaper per step (no linear solve) but it is only stable while the time step stays under the CFL limit. Push past that limit by even a hair and the pressure solution oscillates and diverges to garbage. This exercise quantifies exactly how punishing that constraint is.
For the diffusion problem solved in this chapter, the explicit stability ceiling in days is
Two things make it brutal. The grid spacing enters as , so halving the cells quarters the allowed step. And it is inversely proportional to permeability, so a more permeable rock forces smaller steps. Either way, a real field grid drives down to a tiny fraction of a day, meaning thousands of explicit steps to cover a single year, versus the few hundred an implicit scheme can take with a 1-day step. That trade is the whole reason production simulators are implicit.
The chapter case (OML 58, the OD field): phi = 0.2, mu_cp = 2.0, ct_psi = 1.5e-5, dx_ft = 100.0, k_md = 100.0.
Your tasks:
- Write
cfl_limit(phi, mu, ct, dx, k)returning the CFL time-step limit in
days using the formula above (the constant 6.328e-3 is already provided as ALPHA).
- Write
steps_per_year_explicit(phi, mu, ct, dx, k)returning the number of
explicit steps needed to cover one year: ceil(365.0 / cfl_limit(...)) as an int. (One year is DAYS_PER_YEAR = 365.0; use math.ceil.)
- Compute and store:
dt_cfl_days = cfl_limit(...)for the chapter case (≈ 0.047 days).n_explicit = steps_per_year_explicit(...)for the chapter case (a big
number (thousands).
n_implicit = 365: the steps an implicit run takes atdt = 1day.
> Think about it: the explicit scheme needs ~n_explicit steps to do what > the implicit scheme does in 365. Now imagine refining dx from 100 ft to > 25 ft for a sharper flood front: the CFL step drops by a factor of 16, and the > explicit step count climbs by the same factor. Unconditional stability is not > a luxury; it is what makes field-scale simulation tractable at all.
Stuck? Reveal hints one at a time — they progress from nudge to near-solution.
visibilityReveal reference solutionexpand_more
Try solving it yourself first — the hints walk you through it. The solution below is one valid approach; yours may differ and still be correct.
import math
# ── CFL constants for the explicit diffusion scheme ──────────────────────
# The 6.328e-3 factor pairs with the implicit simulator's beta = 1.127e-3:
# it is the diffusivity constant in field units (md, cp, 1/psi, ft, days).
ALPHA = 6.328e-3 # field-unit diffusivity constant
DAYS_PER_YEAR = 365.0 # days the explicit scheme must cover in one year
# ── Chapter case: OML 58, the OD field ───────────────────────────────────
PHI = 0.2 # porosity (fraction)
MU_CP = 2.0 # oil viscosity (cp)
CT_PSI = 1.5e-5 # total compressibility (1/psi)
DX_FT = 100.0 # grid-cell length (ft)
K_MD = 100.0 # permeability (md)
def cfl_limit(phi, mu, ct, dx, k):
"""Explicit-scheme CFL time-step limit, in DAYS.
dt_cfl = phi * mu * ct * dx**2 / (2 * k * ALPHA)
Smaller cells (dx**2) and higher permeability both SHRINK the limit.
"""
return phi * mu * ct * dx ** 2 / (2.0 * k * ALPHA)
def steps_per_year_explicit(phi, mu, ct, dx, k):
"""Number of explicit steps needed to cover one year (DAYS_PER_YEAR).
That is ceil(365.0 / cfl_limit(...)), returned as an int.
"""
return math.ceil(DAYS_PER_YEAR / cfl_limit(phi, mu, ct, dx, k))
# ── Chapter-case results ─────────────────────────────────────────────────
dt_cfl_days = cfl_limit(PHI, MU_CP, CT_PSI, DX_FT, K_MD)
n_explicit = steps_per_year_explicit(PHI, MU_CP, CT_PSI, DX_FT, K_MD)
n_implicit = 365 # an implicit run at dt = 1 day covers a year in 365 steps
print("CFL limit (days):", dt_cfl_days)
print("explicit steps/year:", n_explicit, "vs implicit steps/year:", n_implicit)
lockCopying code is a Full Access feature.