Top Zechstein · well-based depth correction · interactive explainer

Gaussian-process depth correction

When the regional velocity model converts the top-of-salt time surface to depth, the result usually differs from the top measured in the wells by a hundred metres or more (median absolute difference 107 m). A Gaussian process joins the differences at 52 wells into one smooth correction surface. On this page you can move its parameters and see where the surface comes from, what it can correct and what it cannot.

Depth conversion uses a regional velocity function V(z) derived from seismic-to-well ties: it converts the supplied Top Zechstein time surface T(x, y) to depth zVz. At each well, the difference between this depth and the top of salt interpreted from the logs is written as

r = zVz(T) − zlog

A positive r means that the converted depth is too deep. The fit uses r from 52 wells only: they lie inside the survey, have a level-A or level-B tie, and their tied top differs from the supplied surface by no more than 50 ms, so that r reflects velocity error rather than an error in the surface itself. The Gaussian process interpolates r between the wells to give r̂(x, y) over the whole survey, and the corrected depth is

zcal(x, y) = zVz(T(x, y)) − r̂(x, y)

Where the supplied surface is defined, the median correction is 35 m, and the 5th and 95th percentiles are −85 m and 266 m.

Calibration set
52 wells
Length scale ℓ
5.58 km
Signal SD σf
167 m
Noise SD σn
45.6 m
Leave-one-well-out median |error|
107 → 37 m

sklearn fit: 1.09**2 * RBF(length_scale=5.58) + WhiteKernel(noise_level=0.0883); log marginal likelihood −54.34; mean of r at the wells 21.84 m, population standard deviation 153.41 m.

Every figure has the same set of sliders beneath it, and they share one set of parameters: drag any of them and the whole page updates; a well switched off by clicking it in one figure is off in all of them. The sliders display metres and kilometres but store sklearn's standardised values (see Section 1). Every number is computed live in the browser; the check against sklearn is at the foot of the page.

1Priorbefore any well is seen

Before it has seen a single well, the Gaussian process places a probability distribution over what the correction surface might look like. It needs only one rule: the covariance of r at any two points depends only on the distance d between them, and is given by the kernel:

k(d) = σf2 exp(−d2 / 2ℓ2) + σn2 [d = 0]

Each of the three hyperparameters controls one thing. The signal standard deviation σf sets the amplitude of the correction surface. The length scale ℓ sets how quickly the correlation decays with distance: at a separation of ℓ the correlation coefficient is e−1/2 ≈ 0.61, and at 2ℓ only 0.14 remains. The noise standard deviation σn appears only at d = 0: it is the part that is unique to each well and cannot be predicted from its neighbours; tie errors, the pick of the log top and local velocity anomalies all end up here.

With normalize_y=True, sklearn first standardises r: it subtracts the mean at the wells, 21.84 m, and divides by the population standard deviation, 153.41 m. The fitted hyperparameters are all on this standardised scale: amp2 = 1.188, ℓ = 5.58 km, noise = 0.0883; converted back to metres, σf = √amp2 × 153.41 = 167 m and σn = √noise × 153.41 = 45.6 m. The prior mean is the mean at the wells, so far from all wells the correction returns to the constant 21.84 m. When some wells are switched off, sklearn re-standardises with the mean and standard deviation of the remaining wells, while the hyperparameters stay in standardised units; the metre values on the sliders are therefore always converted with the 153.41 m of the full well set, and the actual values in metres change slightly with the set of active wells.

ρ(1 km) = 0.98 ρ(5 km) = 0.67 ρ(10 km) = 0.20
Variance at a well: 93 % signal

5.58 km
fit
167 m
fit
45.6 m
fit
Fig. 1The prior along the line y = 37.25 km. Left: five prior draws (latent function, without white noise); shading, the prior 95 % interval (mean ± 1.96 σf); small dots, the first draw plus white noise, i.e. the r that a well drilled at that point might measure; hatched, where the supplied surface is undefined. Right: the latent correlation coefficient ρ(d); the vertical line marks ℓ. Drag the length scale from 0.3 km to 60 km and watch the curves go from jagged to almost straight; then increase the noise and watch the dots leave the curve.

2Conditioningon the calibration wells

Bring in the wells and the prior becomes the posterior: of all possible surfaces, only those that pass close to the wells, with misfits in proportion to the noise, remain. For a Gaussian process this step has a closed form. Let ȳ be the mean of r over the active wells and s its population standard deviation, z = (y − ȳ) / s the standardised observations, K the well-to-well kernel matrix and k* the kernel values between the target point and each well (all in standardised units):

r̂(x*) = ȳ + s · k*T (K + noise · I)−1 z

sdlatent = s · √( amp2 − k*T (K + noise · I)−1 k* )

sdpred = s · √( amp2 + noise − k*T (K + noise · I)−1 k* )

The page solves (K + noise · I) by Cholesky decomposition and, like sklearn, adds a tiny alpha to the diagonal. The latent sd is the uncertainty of the correction surface itself; the predictive sd adds the white noise and describes where r at a new well might fall. For this kernel, sklearn's predict(return_std=True) returns the latter.

The posterior surface is two-dimensional; Fig. 2 is only a slice through it along one line. Wells seldom lie exactly on the line, so the figure shows the wells within 1.5 km of it, projected onto the line (the farther away, the paler), and the curve need not pass through them: the wells lie off the line, and the noise term allows the curve to pass beside a well in any case. There are currently 52 active wells, standardised with ȳ = 21.84 m and s = 153.41 m.

5.58 km
fit
167 m
fit
45.6 m
fit
Active calibration wells 52 / 52
List of calibration wells (switch wells on and off from the keyboard)
Fig. 2A slice through the full two-dimensional posterior along the line y = 37.25 km (vertical axis r = V(z) depth − log top depth). Heavy line, posterior mean r̂; dark shading, latent 95 % interval; dashed lines, predictive 95 % interval (with white noise); thin lines, three posterior draws; dotted line, mean r of the active wells, i.e. the value the surface reverts to far from wells; dots, calibration wells within 1.5 km of the line (12), plotted at their projected positions, paler the farther they are from the line; hatched, supplied surface undefined. Click a well to switch it off and watch the mean and the intervals loosen around it; then switch to the line x = 38 km (across a salt pillow) to see what happens with only 4 wells nearby.

3Whole surveythe correction map

The same calculation over the whole survey: one point every 16 traces (spacing 0.4 km), 166 × 204 grid points in all, drawn only where the supplied surface is defined. The left map is the correction r̂: blue where the V(z) depth is too shallow (r̂ < 0, deepened by the correction), red where it is too deep (made shallower). The right map is the posterior standard deviation: smallest within the well clusters, it approaches the prior value away from the wells, which is 173 m for the predictive sd and 167 m for the latent sd.

Coordinates x and y are distances in km from a corner of the seismic survey. On the maps x increases to the right and y downwards, so the top of each map faces south-west: y increases towards an azimuth of 49° and x towards 319° (the arrow at top right points north).

Move the pointer over a map to read r̂ and sd; click a dot to switch a calibration well on or off.

5.58 km
fit
167 m
fit
45.6 m
fit
Right map
Fig. 3Left: posterior mean r̂ (m); the colour scale is fixed at ±300 m and values beyond it take the end colours. Right: posterior standard deviation (m), currently the predictive sd (with white noise), colour scale 0–250 m. Both maps show only the grid points where the supplied surface is defined (hatched, undefined); grid spacing 0.4 km; wells are plotted at their exact coordinates. Switch off a few wells of the 48/06 cluster near the line y = 37.25 km and watch the blue patch on the mean map fall back to the mean and the standard deviation rise.

4Leave-one-well-outeach well predicted by the others

The misfit at the wells says little: the posterior mean is drawn towards the wells by construction. The real test is leave-one-well-out: remove one well, redo normalize_y and the conditioning on the remaining 51 with the same hyperparameters, and predict the well that was removed, exactly as in the original sklearn analysis. Wells that are switched off take no part in the fit; their errors are computed directly from the posterior mean of the active wells, so they are already held out.

With the fitted parameters, the median absolute error at the 52 wells falls from 107 m uncorrected to 37 m, and the RMS from 155 m to 112 m. Drag the sliders and these numbers are recomputed.

The right panel plots the median error as a function of the length scale (σf and σn at their current values). When ℓ is very short, almost no two wells are correlated and the well left out receives only the mean of the others, which amounts to a constant correction; when ℓ is very long, the whole surface is smeared into a gentle slope. The fitted value lies in the trough between the two. The floor of the trough is not smooth: the median is set by the one or two wells in the middle of the ranking and jumps by a few metres when ℓ changes slightly; and the marginal likelihood measures the overall probability, not the median of these 52 numbers, so the lowest point of the trough need not coincide with the fitted value. Of the 24 sample points on the curve, the lowest is at ℓ = 7.55 km (37.5 m); at the current ℓ (orange dot) the median is 36.6 m.

Current parameters: leave-one-well-out median absolute error 37 m (V(z) only: 107 m)

5.58 km
fit
167 m
fit
45.6 m
fit
Fig. 4Left: the 52 calibration wells ranked by uncorrected error |r|, largest first, one column per well; open circles, error with V(z) only; filled dots, error after leave-one-well-out correction; the connecting line is teal where the error decreases and red where it increases; dashed and solid lines, the medians of the two errors. Click a column to switch that well on or off. Right: median absolute error as a function of the length scale ℓ (σf and σn at their current values); dashed line, uncorrected; orange dot, current parameters. Drag ℓ to its shortest and watch the median error return almost to the uncorrected level; then drag the noise to its minimum and see which wells get worse.

5Marginal likelihoodwhere the fitted parameters come from

The fitted values come from maximising the log marginal likelihood. For the standardised observations z (n wells):

log p(z | θ) = −½ zT (K + noise · I)−1 z − ½ log |K + noise · I| − (n/2) log 2π

The first term is the data fit: the better the data at the wells match the correlation structure that the model assumes, the larger it is. The second term is a complexity penalty: the shorter ℓ, the less correlated the wells, the more surfaces the model can generate, the larger the determinant |K + noise · I| and the more negative this term; conversely, the longer ℓ and the smaller the noise, the more rigid the model and the smaller the determinant, but as soon as the data at the wells are less smooth than the model assumes, the first term quickly becomes negative. The maximum is a compromise between the two. sklearn maximises it with L-BFGS-B within the bounds (ℓ ∈ [0.3, 60] km, amp2 ∈ [0.01, 100], noise ∈ [0.001, 10]), starting from the initial values and several random starting points, and reaches −54.34.

Fig. 5 is a slice through the ℓ × σn plane, with σf fixed at the current slider value (by default the fitted value); the colour shows how many log units below the maximum within the slice each point lies. The log marginal likelihood at the current parameters is −54.34. Switching wells off changes this surface, and the original fit is then no longer the optimum; ‘Re-maximise’ repeats the fit on the currently active wells (the page uses multi-start Nelder–Mead with the same bounds as sklearn).

Current log L = −54.34

5.58 km
fit
167 m
fit
45.6 m
fit
Fig. 5Log marginal likelihood on a slice through the length scale ℓ (log axis) and the noise standard deviation σn (log axis, converted with 153.41 m), with σf at its current value, banded by log units below the slice maximum. Ring with cross, the fitted optimum for all 52 wells; orange dot, the current slider position. Click anywhere in the plot to set ℓ and σn to that point. Click the lower-left corner (short ℓ, small noise), then scroll up to see what has become of the leave-one-well-out errors in Fig. 4.

6What it cannot fixlimits of a velocity correction

This correction fixes velocity only. It assumes that the supplied time surface is correct at the wells, which is why r was estimated only from wells whose tie agrees with the surface to within 50 ms. Another 32 wells took no part in the fit; they fall into two groups:

The reason is simple: r̂ is a smooth surface, and where the surface is defined its 5th–95th percentile range spans only −85 m to 266 m, whereas the errors at these wells reach several hundred metres and change abruptly: at 48/11b-10 and 48/11b-6, not far apart, they are −738 m and 585 m. This is a problem of the surface, beyond the reach of a velocity correction. Take 48/02b-3 (a level-B tie): the supplied surface is 308.6 ms later than the tied top, so the converted depth is 752.0 m deeper than the log top (785.5 m TVDSS), while the correction there is only 85.1 m, leaving 666.9 m.

Current parameters · independent check, 12 wells: median |error| 121 → 43 m · surface disagrees, 20 wells: 492 → 394 m

5.58 km
fit
167 m
fit
45.6 m
fit
Fig. 6Signed residuals at the 32 wells not used in the fit (m, V(z) depth − log top depth). Open circles, r with V(z) only; filled dots, after subtracting the current r̂; upper group, independent check wells; lower group, wells where the surface and the tie disagree; sorted by r within each group. Drag ℓ or σf and compare how far the dots move with how far they lie from 0.