Multi-event deconvolution

Multi-rate well-test deconvolution recovers a single equivalent constant-rate response from any number of buildups and drawdowns, dramatically extending the radius of investigation and revealing late-time boundaries that no individual buildup is long enough to see.

Mathematical framework

The convolution problem for a variable-rate well test is

\[p_i - p_{wf}(t) \;=\; \int_0^t q(\tau)\,p'_u(t-\tau)\,d\tau\]

where:

  • \(p_i\) is the initial reservoir pressure,

  • \(p_{wf}(t)\) is the measured flowing/shut-in pressure,

  • \(q(\tau)\) is the (piecewise-constant) rate history,

  • \(p_u(t)\) is the unit-rate constant-rate response — the unknown — and \(p'_u = dp_u/dt\) is its derivative.

Direct deconvolution (recovering \(p_u\) by deconvolving the rate history) is famously ill-posed: tiny noise in \(p_{wf}\) produces unbounded errors in \(p_u\). Regularisation is mandatory.

The vSH04 encoded formulation

We follow von Schroeter, Hollaender and Gringarten (2004), encoding the unknown as

\[z(\sigma) \;=\; \ln\!\left[\,t\,\frac{dp_u}{dt}\,\right] \;=\; \ln\!\left[\,\frac{dp_u}{d\ln t}\,\right], \qquad \sigma = \ln t.\]

Two crucial properties follow:

  1. Positivity by construction. \(p'_u(t) = e^{z(\ln t)}/t \geq 0\), so the recovered derivative cannot become negative — even when noise would otherwise drive it below zero.

  2. Logarithmic regularisation. The flow-regime signatures (WBS, IARF, linear, bilinear, …) appear as straight lines on a log–log plot. Smoothness on the \(\sigma = \ln t\) axis is the physically meaningful notion of smoothness for a Bourdet derivative.

The objective is

\[J(\mathbf{z}, p_i) \;=\; \underbrace{\| \mathbf{y} - C(q, \mathbf{z}) - p_i\,\mathbf{1} \|^2_2}_{\text{data fit}} \;+\; \nu \; \underbrace{\| D\,\mathbf{z}\|^2_2}_{\text{curvature}}\]

where:

  • \(\mathbf{y}\) is the observed pressure vector,

  • \(C(q, \mathbf{z})\) is the convolution operator applied to the rate history \(q\) and the encoded response \(\mathbf{z}\),

  • \(D\) is a centred second-difference matrix on the log-spaced \(\sigma\)-grid, so \(\| D\mathbf{z}\|^2 \approx \int |z''(\sigma)|^2 d\sigma\),

  • \(\nu\) is the user-set regularisation weight.

Both \(\mathbf{z}\) and \(p_i\) are recovered jointly (set fit_p_initial=False to fix \(p_i\) instead).

Choosing \(\nu\)

The regularisation weight \(\nu\) controls the bias–variance trade-off:

\(\nu\)

Effect

small (≤ 1e−3)

Low bias, high variance — derivative may oscillate. Use for low-noise tests with abundant late-time data.

moderate (1e−2)

Default. Typical balance for clean DSTs.

large (≥ 1e−1)

High bias, low variance — derivative is very smooth. Use for noisy mechanical-gauge data.

A practical strategy: start at \(\nu = 10^{-2}\), then L-curve or GCV to refine if needed (not yet implemented in this package — contributions welcome).

API

The entry point is welltest_pta.deconvolve():

from welltest_pta import deconvolve

res = deconvolve(
    events=wt.events,            # iterable of Event
    default_q=850,               # STB/D for DDs without ev.rate
    nu=1e-2,                     # regularisation weight
    n_response_nodes=60,         # log-spaced grid points
    t_response_min=1e-3,         # smallest Δt of recovered response (hr)
    t_response_max=None,         # default: max observation time
    p_initial=None,              # solve jointly with z (default)
    fit_p_initial=True,
    max_iter=200,
    verbose=False,
)

The return type is welltest_pta.DeconvolutionResult, which carries:

Attribute

Meaning

t

Recovered response grid (hr), log-spaced

pu

Unit-rate cumulative response (psi per unit \(q\))

dpu_dlnt

Bourdet log-derivative

z

Encoded variable \(z = \ln(dp_u/d\ln t)\)

p_initial

Recovered (or fixed) \(p_i\) (psi)

fit_pressure

Reconstructed \(p(t_{\text{obs}})\)

residual_norm

\(\|\mathbf{y} - \mathbf{p}_{\text{fit}}\|_2\)

Convenience methods:

  • plot() — log–log of recovered \(p_u\) and its derivative.

  • export() — write CSV / Excel / JSON.

  • to_dataframe() — long-form Pandas DataFrame.

Implementation notes

  • The non-linear least-squares problem is solved with Levenberg– Marquardt via scipy.optimize.least_squares() (method="lm").

  • Default residual tolerances are \(10^{-9}\).

  • The convolution operator uses piecewise-linear log-time interpolation of \(p_u\) on the response grid; this preserves the slopes of the various flow regimes when sampled.

  • Initial guess for \(\mathbf{z}\) is a constant level chosen so that \(p_u(t_{\max}) \approx \max p - \min p\) at the dominant rate.

Best-practice checklist

For a successful deconvolution:

  1. Include both the immediately-preceding drawdown(s) and the buildup(s) you care about. Drawdowns provide the late-time constraint that buildups alone cannot.

  2. Clean the buildup tails before deconvolving (the V8.1 detector does this automatically, but for manually-split events check that \(p_{\text{end}}\) is a true plateau, not a pull-spike).

  3. Use consistent rate units throughout (typically STB/D for oil). The recovered \(p_u\) will be in psi per unit \(q\).

  4. If \(\nu = 10^{-2}\) produces a wiggly derivative, increase by \(\times 10\). If it over-smooths a known flow regime, decrease by \(\times 10\).

References

  • von Schroeter, T., Hollaender, F., & Gringarten, A. C. (2004). Deconvolution of well-test data as a nonlinear total least-squares problem. SPE Journal 9 (4), 375–390.

  • Levitan, M. M. (2005). Practical application of pressure/rate deconvolution to analysis of real well tests. SPE 84290.

  • Gringarten, A. C. (2008). From straight lines to deconvolution: the evolution of the state of the art in well test analysis. SPE Reservoir Evaluation & Engineering 11 (1), 41–62.