CamPetro

Shift, Scale, and Shift-and-Scale

On this page

Summary

Normalization maps a curve from one well onto the scale of a Key well by matching a few percentile picks taken in a shared reference interval. A shift adds a constant, a scale multiplies, and a two-point shift-and-scale maps a low and a high pick onto their key-well values with a straight line. Use the simplest map that removes the offset you can demonstrate.

Inputs and outputs

Item Units
Input Curve value before normalization
Input Source low pick
Input Source middle pick
Input Source high pick
Input Reference low value
Input Reference middle value
Input Reference high value
Output Shifted value
Output Scaled value
Output Normalized curve value
Output Three-point normalized value
Output Normalization slope

Equations

Let the picks in the reference interval of the well being normalized be \(\nrmSrcLow\), \(\nrmSrcMid\) and \(\nrmSrcHigh\) (for example the 5th, 50th and 95th percentiles), and let \(\nrmRefLow\), \(\nrmRefMid\) and \(\nrmRefHigh\) be the same percentiles in the key well.

Shift (additive). One constant moves the middle pick onto its reference value and leaves every difference in the curve unchanged:

\[ \nrmShifted = \nrmIn + \left(\nrmRefMid - \nrmSrcMid\right) \]

Scale (multiplicative). One factor moves the middle pick onto its reference value and leaves zero where it is. It is only sensible for a quantity with a natural zero:

\[ \nrmScaled = \nrmIn \cdot \frac{\nrmRefMid}{\nrmSrcMid} \]

Shift and scale (two-point linear). A straight line through the low and high picks. It fixes both the offset and the spread:

\[ \nrmSlope = \frac{\nrmRefHigh - \nrmRefLow}{\nrmSrcHigh - \nrmSrcLow} \qquad \nrmOut = \nrmRefLow + \nrmSlope\left(\nrmIn - \nrmSrcLow\right) \]

If \(\nrmSrcHigh = \nrmSrcLow\) the slope is undefined (a constant curve, for example), and the map falls back to a pure shift with \(\nrmSlope = 1\).

Three-point piecewise. A two-segment straight line through the low, middle and high picks. Each segment has its own slope, so the map matches three points of the distribution but has a kink at the middle pick:

\[ \nrmPiece = \begin{cases} \nrmRefLow + \dfrac{\nrmRefMid - \nrmRefLow}{\nrmSrcMid - \nrmSrcLow}\left(\nrmIn - \nrmSrcLow\right), & \nrmIn < \nrmSrcMid \\[2ex] \nrmRefMid + \dfrac{\nrmRefHigh - \nrmRefMid}{\nrmSrcHigh - \nrmSrcMid}\left(\nrmIn - \nrmSrcMid\right), & \nrmIn \ge \nrmSrcMid \end{cases} \]

The two-point map is applied to the whole curve, including values outside the picks, where it extrapolates along the same straight line.

Symbol Variable Units Typical range
\(x_{\mathrm{in}}\) Curve value before normalization
\(p_{\mathrm{lo}}\) Source low pick
\(p_{\mathrm{mid}}\) Source middle pick
\(p_{\mathrm{hi}}\) Source high pick
\(r_{\mathrm{lo}}\) Reference low value
\(r_{\mathrm{mid}}\) Reference middle value
\(r_{\mathrm{hi}}\) Reference high value
\(x_{\mathrm{shift}}\) Shifted value
\(x_{\mathrm{scale}}\) Scaled value
\(x_{\mathrm{norm}}\) Normalized curve value
\(x_{\mathrm{pw}}\) Three-point normalized value
\(s_{\mathrm{n}}\) Normalization slope
Key well

Single-value calculator

Behavior

All four maps agree where the data lie close to the middle pick and separate toward the ends. With the default picks (a second well that reads about 21 gAPI high in shale and 12 gAPI high in clean rock), a shale reading of 126 gAPI maps to 105.3 with the two-point map, 105.0 with the shift, 103.4 with the scale and 104.6 with the three-point map. The disagreement is at the clean end. A reading of 30 gAPI maps to 17.9 with the two-point and three-point maps but to 9.0 with the shift, which moves a clean sand well below any believable gamma ray, and to 24.6 with the scale. At 250 gAPI the two-point map gives 218.3, the shift gives 229.0 and the scale 205.1. The plot makes the point: the shift is a line of slope 1, the scale a line of slope 0.82 through the origin, and the two-point map a line of slope 0.91 that does not pass through the origin. The three-point map follows the two-point line closely here only because the three picks are nearly collinear; with picks that are not collinear it would show a visible kink at the median.

Parameter guidance

Which map. Start from the evidence in a cross-plot or overlaid histograms of the reference interval in the two wells. If the histograms have the same shape and are displaced, use a shift. If the second well is a stretched or compressed version of the key well (the low and high picks move by different amounts), use the two-point map. A pure scale suits a quantity that is zero when the response is zero, which is rare for the curves normalized here. The three-point map is only justified when the relation between the wells is demonstrably non-linear, because it fits the sampling noise in the middle pick as well as the offset.

Which picks. The low and high picks are normally the 5th and 95th percentiles (the 2nd and 98th for a thick, clean interval) and the middle pick the 50th. How to read them from a histogram, how thick an interval to use and how robust each choice is are covered on the Histogram and Percentile-Based Picks page, and the choice of method for different curves is on the Curve Normalization page. For a target that is not a key well, see Normalization to a Fixed Range or Value. Resistivity is treated separately on Resistivity Normalization.

Worked example

Two synthetic wells with the same rock but a different tool calibration: the second well reads 1.12 times the true gamma ray plus 8 gAPI. Percentile picks from a 5th to 95th percentile reference interval are used to build each map, and the maps are then checked at a clean sand (25 gAPI in the key well) and at a shale (105 gAPI), where the right answer is known.

rng = np.random.default_rng(11)

def make_gr(n, lo=25.0, hi=105.0):
    """Synthetic reference interval: 35% clean beds near `lo`, 65% shale near `hi`."""
    clean = rng.random(n) < 0.35
    return np.where(clean, rng.normal(lo, 6.0, n), rng.normal(hi, 10.0, n))

key = make_gr(600)                         # key well, taken as correct
true_map = lambda g: 1.12 * g + 8.0        # unknown tool offset of the second well
tgt = true_map(make_gr(600))               # second well, same rock, different calibration

p = [5, 50, 95]
k5, k50, k95 = np.percentile(key, p)
t5, t50, t95 = np.percentile(tgt, p)
print(f"key  well P5/P50/P95 = {k5:6.1f} {k50:6.1f} {k95:6.1f}")
print(f"tgt  well P5/P50/P95 = {t5:6.1f} {t50:6.1f} {t95:6.1f}")

shift = k50 - t50
scale = k50 / t50
slope = (k95 - k5) / (t95 - t5)
two_point = lambda x: k5 + slope * (x - t5)

print(f"\nshift (P50)            : x + {shift:.1f}")
print(f"scale (P50 ratio)      : x * {scale:.3f}")
print(f"two-point (P5, P95)    : {k5:.1f} + {slope:.3f} * (x - {t5:.1f})")

# Where the truth is known: a clean sand at 25 and a shale at 105 on the key scale
for name, true_key in (("clean sand", 25.0), ("shale", 105.0)):
    x = true_map(true_key)                 # what the second well reads there
    print(f"\n{name}: second well reads {x:.1f}, correct value {true_key:.1f}")
    print(f"  shift     -> {x + shift:6.1f}")
    print(f"  scale     -> {x * scale:6.1f}")
    print(f"  two-point -> {two_point(x):6.1f}")

Output

key  well P5/P50/P95 =   17.1   95.9  119.0
tgt  well P5/P50/P95 =   28.6  117.0  141.0

shift (P50)            : x + -21.2
scale (P50 ratio)      : x * 0.819
two-point (P5, P95)    : 17.1 + 0.907 * (x - 28.6)

clean sand: second well reads 36.0, correct value 25.0
  shift     ->   14.8
  scale     ->   29.5
  two-point ->   23.8

shale: second well reads 125.6, correct value 105.0
  shift     ->  104.4
  scale     ->  102.9
  two-point ->  105.1

Assumptions and limitations

  • The two wells sampled the same rock in the reference interval. If the zone changes geologically between the wells, the picks measure geology and not calibration.
  • The difference between the wells is a smooth, monotonic function of the curve value that a straight line (or two) can approximate.
  • The key well is correct, or at least the agreed standard. Normalization removes disagreement; it does not make a curve right.
  • The picks are stable estimates: the interval is thick enough and free of spikes and bad hole (see the percentile page).
  • The same map is applied to the whole well. A tool or calibration change part way down the well needs a separate map per section.

QC checks

  • After normalization the histogram of the reference interval overlays the key-well histogram, and the picks match (they do by construction at the anchors, so check at percentiles not used, such as the 25th and 75th).
  • A second, independent interval that was not used for the picks also matches between the wells.
  • The shift, scale or slope is plausible: a slope far from 1 (outside roughly 0.8 to 1.25 as a rule of thumb) or a very large shift points to a wrong reference interval or a unit problem.
  • Clean-rock and shale end-points sit at believable values after normalization (no negative porosity, no gamma ray below the clean-sand value).
  • Apply the correction once. A curve that has been normalized and re-normalized by a second pass usually has an unintended compound map.
  • Keep the original curve and the normalized curve both, and record the picks and the map used for each well.

Going Deeper

Normalization is the equalizing of curve distributions across wells, usually with the assumption that a chosen interval has the same distribution everywhere. The two-point map is the simplest transformation that matches two distribution quantiles; matching the full distribution (quantile mapping) is the limiting case with many picks. The cost of more flexibility is that the map starts to absorb real geology, so most practical workflows stop at one or two parameters. The choice between a shift and a scale also depends on what the curve measures: for a physical quantity with a true zero (a count rate, a transit time) a scale error is plausible, and for an environmentally affected reading an additive offset is more common. A calibration error in a tool is often both.

References

  1. Shier, D.E., 2004. Well log normalization: methods and guidelines. Petrophysics, 45(3), 268–280.
  2. Neinast, G.S. and Knox, C.C., 1973. Normalization of well log data. Transactions of the SPWLA 14th Annual Logging Symposium, Paper I.

Python reference implementation

Python reference implementation

The Python reference implementation is available to registered users with a verified email address. Register or sign in to view it.