examples.depletion

Primary depletion: production without injection.

Impossible with ct = 0 (the rates must balance, ref Wells.rates); with ct > 0 the deficit is drawn from storage, i.e. from the expansion of the rock and fluids as the pressure drops.

Two flow regimes are visible:

  • Transient (early): the pressure disturbance has not yet reached the (closed) boundaries, so the reservoir behaves as if it were infinite.
  • Boundary-dominated (late): the disturbance has swept the whole domain, and the pressure profile is frozen in shape -- it simply subsides at the constant rate dictated by material balance,

    $$ dp̄/dt = -q / (c_t V_p) $$

    ($V_p$ = pore volume), and the drawdown $p̄ - p_\mathrm{cell}$ is constant.

There is no water anywhere here (S = 0 throughout), so this is effectively a single-phase example -- and, rates being signed (negative to produce), the lone producer is the only well there is.

In the figures:

  • "pressure": the depression cone grows (t = 0.003 → 0.025) and then stops changing shape, while the entire field subsides (t = 0.025 → 0.1). The colour scale is shared, so that late, uniform darkening is the decline.
  • "decline" (left): $\bar{p}$ falls exactly along the material-balance line (dashed), and the producer's cell pressure runs parallel to it, one drawdown below.
  • "decline" (right): that drawdown (note the logarithmic time axis) grows throughout the transient, and then settles at 0.15 -- the transition occurring at about the time $r^2/η$ that the disturbance needs to reach the boundary (dotted).

Throughout, $p_\mathrm{cell}$ is the pressure of the cell that holds the well, not that of the wellbore, so it deepens under grid refinement (0.15 at 32², 0.18 at 64²). For a bottom-hole pressure, give the well an rw and read model.wells.actual_bhp instead; ref examples/well_control.py.

Depletion -- pressure
Depletion -- pressure
Depletion -- decline
Depletion -- decline
  1"""Primary depletion: production *without* injection.
  2
  3Impossible with `ct = 0` (the rates must balance, ref `Wells.rates`); with
  4`ct > 0` the deficit is drawn from *storage*, i.e. from the expansion of the
  5rock and fluids as the pressure drops.
  6
  7Two flow regimes are visible:
  8
  9- **Transient** (early): the pressure disturbance has not yet reached the
 10  (closed) boundaries, so the reservoir behaves as if it were infinite.
 11- **Boundary-dominated** (late): the disturbance has swept the whole domain, and
 12  the pressure profile is *frozen in shape* -- it simply subsides at the constant
 13  rate dictated by material balance,
 14
 15  $$ dp̄/dt = -q / (c_t V_p) $$
 16
 17  ($V_p$ = pore volume), and the drawdown $p̄ - p_\\mathrm{cell}$ is constant.
 18
 19There is no water anywhere here (`S = 0` throughout), so this is effectively a
 20single-phase example -- and, rates being signed (negative to produce),
 21the lone producer is the only well there is.
 22
 23In the figures:
 24
 25- "pressure": the depression cone grows (t = 0.003 → 0.025) and then stops
 26  changing shape, while the entire field subsides (t = 0.025 → 0.1).
 27  The colour scale is shared, so that late, uniform darkening *is* the decline.
 28- "decline" (left): $\\bar{p}$ falls exactly along the material-balance line
 29  (dashed), and the producer's *cell* pressure runs parallel to it, one drawdown
 30  below.
 31- "decline" (right): that drawdown (note the logarithmic time axis) grows
 32  throughout the transient, and then settles at 0.15 -- the transition
 33  occurring at about the time $r^2/η$ that the disturbance needs to reach the
 34  boundary (dotted).
 35
 36Throughout, $p_\\mathrm{cell}$ is the pressure of the *cell* that holds the well,
 37not that of the wellbore, so it deepens under grid refinement (0.15 at 32², 0.18
 38at 64²). For a bottom-hole pressure, give the well an `rw` and read
 39`model.wells.actual_bhp` instead; ref `examples/well_control.py`.
 40"""
 41
 42from mpl_tools.place import freshfig
 43import numpy as np
 44
 45from TPFA_ResSim import ResSim
 46from TPFA_ResSim.plotting import show
 47
 48## Setup
 49q = .25
 50model = ResSim(Lx=1, Ly=1, Nx=32, Ny=32, ct=.1,
 51               wells=[dict(xy=[.5, .5], rate=-q)])
 52
 53dt = 1e-3
 54nSteps = 100
 55tt = dt*np.arange(nSteps + 1)
 56oil_only = np.zeros(model.Nxy)
 57P0 = np.ones(model.Nxy)
 58
 59## Simulate
 60SS, PP = model.sim(dt, nSteps, oil_only, P0=P0, pbar=False)
 61assert SS.max() == 0, "No water is injected, so none should appear."
 62
 63iw = model.xy2ind(*model.wells.xy[0])
 64p_mean = PP.mean(axis=1)
 65p_cell = PP[:, iw]
 66pore_volume = model.h2 * model.por.sum()
 67
 68## Plot: the pressure field, subsiding
 69fig, axs = freshfig("Depletion -- pressure", ncols=3, sharex=True, sharey=True,
 70                    figsize=(9, 3.5))
 71kws: dict = dict(levels=np.linspace(PP.min(), 1, 21), cmap="viridis",
 72                 colorbar=False, finalize=False, wells=dict(size=.4))
 73for i, (ax, k) in enumerate(zip(axs, [3, 25, nSteps])):
 74    cc = model.plt_field(ax, PP[k], **kws, labels=(i == 0), title=f"t = {k*dt:.3f}")
 75fig.colorbar(cc, ax=axs, shrink=.6, label="p")
 76# Note how the *shape* stops changing, while the level keeps dropping.
 77
 78## Plot: decline and drawdown
 79fig, (ax1, ax2) = freshfig("Depletion -- decline", ncols=2, figsize=(10, 4))
 80
 81ax1.plot(tt, p_mean, label="Mean, $\\bar{p}$")
 82ax1.plot(tt, p_cell, label="Producer cell, $p_\\mathrm{cell}$")
 83ax1.plot(tt, 1 - q*tt/(model.ct*pore_volume), "k--", lw=1,
 84         label="$p_0 - q t / (c_t V_p)$")
 85ax1.set(title="Pressure decline", xlabel="Time", ylabel="p")
 86ax1.legend()
 87
 88ax2.plot(tt[1:], (p_mean - p_cell)[1:], "-o", ms=3)
 89ax2.set(title="Drawdown, $\\bar{p} - p_\\mathrm{cell}$", xlabel="Time",
 90        xscale="log", ylabel="$\\Delta p$")
 91ax2.axhline((p_mean - p_cell)[-1], c="k", ls="--", lw=1,
 92            label="Boundary-dominated value")
 93ax2.axvline(.25/(1/model.ct), c="C1", ls=":", lw=1,
 94            label="$r^2/η$, $r$ = ½ (to the boundary)")
 95ax2.legend(fontsize="small")
 96fig.tight_layout()
 97
 98# Material balance holds exactly (see also tests/test_compressible.py)
 99assert np.allclose(p_mean, 1 - q*tt/(model.ct*pore_volume))
100
101# Regression values, checked by `tests/test_examples.py`.
102__digest__ = dict(p_mean = p_mean,
103                  p_cell = p_cell,
104                  p_last = PP[-1])
105
106if __name__ == "__main__":
107    show()