Part III: Reservoir & Production Engineering
Chapter 11
Introduction to Reservoir Simulation with Python
Get the TL;DR and the key concepts before you dive in — or as a quick review after.
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
Every cell in the grid you are about to build needs an equation that says how fast fluid crosses its faces and how much its pressure changes as a result. Three pieces of physics supply that equation. 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:
where is the superficial velocity (flow rate per unit area), is the rock permeability, is the fluid viscosity, and 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:
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.
- is porosity (the fraction of rock volume that is pore space)
- 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
The diffusivity equation has no closed-form solution for a real reservoir, so a computer cannot integrate it directly; it can only add and multiply numbers in arrays. Discretization is what turns the continuous equation into exactly that. 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 grid cells of width . Replace the spatial derivative with a central difference approximation:
where is the transmissibility between cells and (RB/d/psi). is the cross-sectional area, is the harmonic mean of the two cells' permeabilities (the correct average for series flow), and is the Darcy field-unit constant. Flux, accumulation, and the well source are all carried in reservoir barrels, so the formation volume factor enters only on the well term (converting STB/d to RB/d), not here. Multiplying the equation through by the cell bulk volume gives the finite-volume form the code solves.
Temporal Discretization
Replace the time derivative with a forward difference:
How you combine spatial and temporal discretization determines whether the scheme is explicit or implicit.
Building a 1D Single-Phase Simulator
The class below assembles exactly the finite-volume system from the last section. Each grid cell contributes one row to a tridiagonal matrix: the diagonal holds its accumulation term plus the transmissibilities to its neighbours, the off-diagonals hold those neighbour transmissibilities, and the right-hand side carries the old pressure and any well source. spsolve then returns the new pressure field in one step.

Running the Simulator
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
The explicit method is simpler to implement but has a critical limitation: it is only stable if the time step satisfies the CFL condition:
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 () 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.
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.
where and are the relative permeabilities of oil and water, which depend on water saturation.

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.
Coupling Pressure and Saturation: an IMPES Waterflood
Fractional-flow theory is analytical: it tells you the shape of the answer. A real simulator couples it to the pressure solution. The standard scheme is IMPES (IMplicit Pressure, Explicit Saturation): each step solves the pressure equation with the current total mobility, computes the inter-cell flows, then advances water saturation explicitly with upstream weighting (the saturation of a face is taken from the cell the fluid is flowing from, central differencing of a hyperbolic transport term produces non-physical oscillations). This is the actual engine behind a waterflood forecast, and it reproduces the Buckley-Leverett front rather than a hand-drawn sketch.

The simulated front lands within a few percent of the analytical Buckley-Leverett position; the small lag is numerical dispersion, the smearing a first-order upwind scheme adds to a true shock. Refining the grid (larger nx) sharpens the front toward the analytical discontinuity, the displacement-engineering version of the grid-refinement study in Exercise 11.1.
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. The leap to a field model is one of scale and bookkeeping, not of new physics; the mass-balance and Darcy core you built here is unchanged.
Exercises
: 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...
: 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...
: 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 ...
: 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...
: 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 ...
: 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...
: 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(-\...
: 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...
: 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...
: 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...