Part III: Reservoir & Production Engineering

Chapter 11

Introduction to Reservoir Simulation with Python

schedule15 min readfitness_center10 exercises

Why This Chapter Exists

Material balance tells you how much oil is in the reservoir and what is driving it out. But it treats the entire reservoir as a single tank --- it cannot tell you where the oil is, how the fluids move through the rock, or what happens when you change well locations, injection rates, or completion designs.

Reservoir simulation solves this problem. It divides the reservoir into thousands or millions of grid cells, assigns rock and fluid properties to each cell, and solves the equations of fluid flow at every cell and every time step. The result is a dynamic, spatial model of the reservoir that can predict how fluids move, where pressure fronts develop, and how different development strategies compare.

Commercial reservoir simulators (Eclipse, CMG, tNavigator) cost tens or hundreds of thousands of dollars per license. Understanding what they do under the hood --- the physics, the math, and the numerical methods --- makes you a better user of those tools and a better engineer. This chapter builds a reservoir simulator from scratch. It will be simple compared to commercial software, but the principles are identical.

infoWhat You'll Learn

  • The diffusivity equation governing fluid flow in porous media
  • Finite difference discretization of partial differential equations
  • Building a 1D single-phase reservoir simulator from scratch
  • Implicit vs. explicit time-stepping: stability, accuracy, and cost
  • Buckley-Leverett two-phase displacement theory
  • Working with output from commercial simulators
  • Validating simulation results against analytical solutions

The Physics of Flow in Porous Media

Fluid flow through reservoir rock is governed by three fundamental principles: conservation of mass, Darcy's Law, and an equation of state.

Darcy's Law

In 1856, Henry Darcy showed experimentally that the flow rate of a fluid through a porous medium is proportional to the pressure gradient and inversely proportional to the fluid viscosity:

u=kμPxu = -\frac{k}{\mu} \frac{\partial P}{\partial x}

where uu is the superficial velocity (flow rate per unit area), kk is the rock permeability, μ\mu is the fluid viscosity, and P/x\partial P / \partial x is the pressure gradient.

The physical interpretation: fluid flows from high pressure to low pressure. The rate of flow depends on how permeable the rock is (how connected the pore spaces are) and how viscous the fluid is (how much it resists flowing). Darcy's Law is the petroleum engineering equivalent of Ohm's Law in electrical circuits: pressure difference drives flow, permeability is conductance, viscosity is resistance.

Conservation of Mass

The mass of fluid entering a volume element minus the mass leaving must equal the change in mass stored within the element:

x(kμPx)=ϕctPt\frac{\partial}{\partial x}\left(\frac{k}{\mu}\frac{\partial P}{\partial x}\right) = \phi c_t \frac{\partial P}{\partial t}

This is the diffusivity equation for single-phase, slightly compressible flow. It combines Darcy's Law with mass conservation and a compressibility equation of state.

  • ϕ\phi is porosity (the fraction of rock volume that is pore space)
  • ctc_t is total compressibility (how much the fluid and rock compress per unit pressure drop)
  • The left side represents spatial variation in flow
  • The right side represents temporal change in pressure

This equation is a partial differential equation (PDE). It cannot be solved analytically for most realistic reservoir geometries and boundary conditions. Numerical methods are required.

Finite Difference Discretization

To solve the diffusivity equation numerically, we discretize it --- convert the continuous PDE into a system of algebraic equations that a computer can solve.

Spatial Discretization

Divide the reservoir into nn grid cells of width Δx\Delta x. Replace the spatial derivative with a central difference approximation:

x(kμPx)Ti+1/2(Pi+1Pi)Ti1/2(PiPi1)Δx2\frac{\partial}{\partial x}\left(\frac{k}{\mu}\frac{\partial P}{\partial x}\right) \approx \frac{T_{i+1/2}(P_{i+1} - P_i) - T_{i-1/2}(P_i - P_{i-1})}{\Delta x^2}

where Ti+1/2=ki+1/2μT_{i+1/2} = \frac{k_{i+1/2}}{\mu} is the transmissibility between cells ii and i+1i+1.

Temporal Discretization

Replace the time derivative with a forward difference:

PtPin+1PinΔt\frac{\partial P}{\partial t} \approx \frac{P_i^{n+1} - P_i^n}{\Delta t}

How you combine spatial and temporal discretization determines whether the scheme is explicit or implicit.

Building a 1D Single-Phase Simulator

main.py

Running the Simulator

main.py

The pressure profiles show the characteristic shape of a drawdown: pressure drops sharply near the well and the disturbance propagates outward over time. Early time steps show the pressure front still traveling through the reservoir (transient flow). At late times, the pressure front has reached the boundary and the entire reservoir is depleting (boundary-dominated flow).

This transition from transient to boundary-dominated flow is fundamental in reservoir engineering. It affects decline curve behavior, well test interpretation, and spacing decisions.

Implicit vs. Explicit Methods

The simulator above uses implicit time-stepping, meaning it solves a linear system at each time step. The alternative is explicit time-stepping, where the new pressure is calculated directly from the old pressure without solving a system.

Explicit Method

Pin+1=Pin+ΔtϕctΔx2[Ti+1/2(Pi+1nPin)Ti1/2(PinPi1n)]P_i^{n+1} = P_i^n + \frac{\Delta t}{\phi c_t \Delta x^2} \left[ T_{i+1/2}(P_{i+1}^n - P_i^n) - T_{i-1/2}(P_i^n - P_{i-1}^n) \right]

The explicit method is simpler to implement but has a critical limitation: it is only stable if the time step satisfies the CFL condition:

Δt<ϕμctΔx22k6.328×103\Delta t < \frac{\phi \mu c_t \Delta x^2}{2k \cdot 6.328 \times 10^{-3}}

If you exceed this limit, the solution oscillates and diverges. In practical terms, explicit methods require very small time steps for high-permeability reservoirs or fine grids, making them prohibitively slow.

Implicit Method

The implicit method has no stability restriction --- you can take arbitrarily large time steps without divergence. The cost is that you must solve a linear system (APn+1=bA \cdot P^{n+1} = b) at each step. For a tridiagonal system (1D problem), this is efficient. For 3D problems with millions of cells, it requires iterative solvers and sophisticated linear algebra.

main.py

Buckley-Leverett Two-Phase Displacement

When water is injected into an oil reservoir, two immiscible fluids flow simultaneously through the same rock. The displacement process is governed by the Buckley-Leverett equation, which predicts the position of the water front as a function of time.

The key concept is fractional flow: the fraction of total flow that is water at any point in the reservoir.

fw=11+kroμwkrwμof_w = \frac{1}{1 + \frac{k_{ro} \mu_w}{k_{rw} \mu_o}}

where krok_{ro} and krwk_{rw} are the relative permeabilities of oil and water, which depend on water saturation.

main.py

The Buckley-Leverett solution reveals a sharp saturation discontinuity --- the shock front --- where water abruptly replaces oil. Behind the front, the rock is at near-residual oil saturation. Ahead of the front, only connate water is present. The front velocity depends on the derivative of the fractional flow curve, which is why the viscosity ratio between oil and water is so important for displacement efficiency.

Summary

  • Reservoir simulation solves the equations of fluid flow at every point in space and time, providing spatial resolution that material balance cannot.
  • Darcy's Law relates flow rate to pressure gradient, permeability, and viscosity. It is the fundamental flow equation in porous media.
  • The diffusivity equation combines Darcy's Law with mass conservation. It is a PDE that must be solved numerically for realistic reservoirs.
  • Finite differences convert the continuous PDE into discrete algebraic equations by approximating derivatives on a grid.
  • Implicit methods have no stability restriction and allow large time steps. Explicit methods are simpler but require time steps below the CFL limit.
  • Buckley-Leverett theory predicts the displacement of oil by water. The shock front saturation and velocity are determined by the fractional flow curve.
  • Commercial simulators use the same principles but extend them to 3D, multiphase flow, complex geology, and sophisticated well models. Understanding the fundamentals makes you a better user of those tools.

Exercises

fitness_center
Exercise 11.1Practice

-- Grid Refinement Study

Run the 1D simulator from this chapter with 10, 25, 50, 100, and 200 grid cells. Plot the pressure profile at t=180 days for each case. At what grid r...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.2Practice

-- Permeability Heterogeneity

Modify the simulator to use a non-uniform permeability field: cells 1–25 have k=200 md, cells 26–50 have k=20 md. Run the simulation and compare the p...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.3Practice

-- Injection-Production Pair

Place a water injector (constant rate = +500 STB/d) at cell 0 and a producer (constant BHP = 2000 psi) at cell 49. Run for 2 years. Plot the pressure ...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.4Practice

-- CFL Condition

Implement the explicit time-stepping method. Calculate the CFL limit for the reservoir parameters in this chapter. Verify by running the explicit meth...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.5Practice

-- Time Step Sensitivity

Using the implicit simulator, run the same problem with dt = 0.1, 1, 10, and 30 days. Compare the final pressure profiles. How large can you make the ...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.6Practice

-- Fractional Flow Sensitivity

Plot the fractional flow curve for three different oil viscosities: 1 cp (light oil), 5 cp (medium), and 50 cp (heavy oil). How does the shock front s...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.7Practice

-- Analytical Validation

The line-source solution for pressure drawdown in an infinite reservoir is P(r,t)=Pi+qμ4πkhEi(−ϕμctr24kt)P(r,t) = P_i + \frac{q\mu}{4\pi kh}Ei\left(-\...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.8Practice

-- Boundary Conditions

The simulator uses no-flow boundaries by default (no flux at x=0 and x=L). Modify it to support a constant-pressure boundary at x=L (representing an a...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.9Practice

-- Corey Exponent Sensitivity

Using the Buckley-Leverett analysis, investigate how the Corey exponents (non_ono​ and nwn_wnw​) affect the shape of the fractional flow curve and the...

arrow_forward
codePythonSolve Nowarrow_forward
fitness_center
Exercise 11.10Practice

-- Build a 2D Simulator

Extend the 1D simulator to 2D by adding a second spatial dimension. Use a 20×20 grid. Place an injector in one corner and a producer in the opposite c...

arrow_forward
codePythonSolve Nowarrow_forward