Last updated

Proxy Track

This tutorial demonstrates how to share single well template for different well tracks.

This tutorial assumes familiarity with the MultiWell Introduction tutorials.

# Create a DataSource

The first step is to create a a data source to be applied for each proxy track. It contains two parts: data binding, data source. Data Binding is associate visuals like LogCurve with provided data. DataSource is a container of your data for the current well. It is passed to bind method of data binding with instance of visual to apply data.

# Create a Template

The next step is to create a template to be used as prototype for well tracks. The well track API supports adding and removing tracks and provides options to initialize the well from the JSON template. See the WellLog–Data Connection tutorial. This template can be loaded with method loadTemplate of WellTrack or can be created programmatically as code below. It contains index track and log track with two curves.

# Create Wells

In the next step, create proxy well tracks and provide created template as prototype.

# Add Data

In the next step, add data source and data binding for each created well.

# Result

This WellLog–Multi Well Correlation widget can display well tracks and correlation tracks between them. A Well Track can have the different set of tracks and curves, which is named as a template. Often the same template is used for all wells in the display to see correlation between the different wells. In this case usage of a normal WellTrack cannot be efficient for big amount of wells, because it has a copy of tracks and curves and the own set of tools. In this case it is better to use ProxyWellTrack for read only displays.

import { obfuscate } from "@int/geotoolkit/lib.js";
import { MultiWellWidget } from "@int/geotoolkit/welllog/multiwell/MultiWellWidget.ts";
import { ProxyTrackHighlightTool } from "@int/geotoolkit/welllog/multiwell/tools/ProxyTrackHighlightTool.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { TrackType as MultiWellTrackType } from "@int/geotoolkit/welllog/multiwell/TrackType.ts";
import { TrackType as WellLogTrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { MathUtil } from "@int/geotoolkit/util/MathUtil.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { LineStyle } from "@int/geotoolkit/attributes/LineStyle.ts";
import { LogMarker } from "@int/geotoolkit/welllog/LogMarker.ts";
import { AlignmentStyle, TextStyle } from "@int/geotoolkit/attributes/TextStyle.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { CorrelationMarker } from "@int/geotoolkit/welllog/multiwell/correlation/CorrelationMarker.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { DataBinding } from "@int/geotoolkit/data/DataBinding.ts";
import { DataSource } from "@int/geotoolkit/data/DataSource.ts";
import { DataBindingRegistry } from "@int/geotoolkit/data/DataBindingRegistry.ts";
import curvesData from "/src/code/WellLog/MultiWell/data/data.json?import";
import { ProxyTrackActivationTool } from "@int/geotoolkit/welllog/multiwell/tools/ProxyTrackActivationTool.ts";
const bindingFunctions = [];
class CurveBinding extends DataBinding {
  constructor() {
    super();
  }
  accept(node) {
    return node instanceof LogCurve;
  }
  bind(curve, data) {
    if (data == null) {
      return;
    }
    const id = curve.getName();
    const source = data.getCurveSource(id);
    if (source != null) {
      const limits = MathUtil.calculateNeatLimits(source.getMinValue(), source.getMaxValue());
      if (curve.isCustomLimits() === true) {
        curve.setData(source, false, true);
      } else {
        curve.setData(source, true, true).setNormalizationLimits(limits.getLow(), limits.getHigh());
      }
    }
  }
  unbind(curve, data) {
  }
}
obfuscate(CurveBinding);
class LogDataSource extends DataSource {
  constructor(startDepth) {
    super();
    this._sources = {};
    this._startDepth = startDepth;
    this._step = 10;
  }
  getCurveSource(curveMnemonic) {
    if (this._sources[curveMnemonic]) {
      return this._sources[curveMnemonic];
    }
    const data = new LogData(curveMnemonic);
    const depths = [];
    const values = [];
    const curveData = getCurveData(curveMnemonic);
    const amountOfPoints = curveData.length;
    for (let i = 0; i < amountOfPoints; i++) {
      depths.push(i * this._step + this._startDepth);
      values.push(curveData[i]);
    }
    data.setValues(depths, values);
    this._sources[curveMnemonic] = data;
    return data;
  }
}
obfuscate(LogDataSource);
function getCurveData(curveMnemonic) {
  const curveNames = curvesData.curveNames;
  const curveData = curvesData.curveData;
  for (let i = 0; i < curveNames.length; i++) {
    if (curveNames[i] === curveMnemonic)
      return curveData[i];
  }
  return null;
}
function createWidget() {
  const widget = new MultiWellWidget({
    "verticalscrollable": "auto",
    "horizontalscrollable": "auto",
    "tools": {
      "cursortracking": {
        "tooltip": {
          "enabled": true
        }
      }
    }
  });
  widget.getTool().insert(0, [
    new ProxyTrackHighlightTool(widget.getOverlayLayer(), widget.getTrackContainer()),
    new ProxyTrackActivationTool(widget)
  ]);
  const template = createTemplate(widget);
  const well1 = widget.addTrack(MultiWellTrackType.ProxyTrack, {
    "name": "Proxy Well #1",
    "track": template,
    "range": new Range(0, 500),
    "welllog": {
      "range": new Range(4500, 5e3)
    },
    "tools": {
      "navigation": true
    }
  });
  const correlationTrack1 = widget.addTrack(MultiWellTrackType.CorrelationTrack, {
    "width": 50
  });
  const well2 = widget.addTrack(MultiWellTrackType.ProxyTrack, {
    "name": "Proxy Well #2",
    "track": template,
    "range": new Range(50, 300),
    "welllog": {
      "range": new Range(2500, 5e3)
    },
    "tools": {
      "navigation": true
    }
  });
  const correlationTrack2 = widget.addTrack(MultiWellTrackType.CorrelationTrack, {
    "width": 50
  });
  const well3 = widget.addTrack(MultiWellTrackType.ProxyTrack, {
    "name": "Proxy Well #3",
    "track": template,
    "range": new Range(25, 400),
    "welllog": {
      "range": new Range(4700, 5e3)
    },
    "tools": {
      "navigation": true
    }
  });
  addWellData(well1, 4500);
  addWellData(well2, 2500);
  addWellData(well3, 4700);
  function addWellData(well, startDepth) {
    const data = new LogDataSource(startDepth);
    const bindingFunc = new CurveBinding();
    bindingFunctions.push(bindingFunc);
    well.getDataBinding().add(bindingFunc);
    well.setData(data);
  }
  addTops(well1, "Tarbert", 4750, KnownColors.DarkRed);
  addTops(well2, "Tarbert", 3e3, KnownColors.DarkRed);
  addTops(well3, "Tarbert", 4800, KnownColors.DarkRed);
  addTopsCorrelation(correlationTrack1, 4750, 3e3, KnownColors.DarkRed);
  addTopsCorrelation(correlationTrack2, 3e3, 4800, KnownColors.DarkRed);
  return widget;
}
function createTemplate(widget) {
  const well = widget.createTrack(MultiWellTrackType.WellTrack, {
    "name": "Well Prototype",
    "welllog": {
      "range": new Range(4700, 5e3)
    }
  });
  well.addTrack(WellLogTrackType.IndexTrack);
  well.addTrack(WellLogTrackType.LinearTrack).addChild([
    createEmptyCurve("GR").setLineStyle(KnownColors.Green),
    createEmptyCurve("CALI").setLineStyle(KnownColors.Orange)
  ]);
  return well;
}
function createEmptyCurve(name) {
  return new LogCurve().setName(name);
}
function addTops(well, name, depth, color) {
  well.getMarkerLayer().addChild(
    new LogMarker(depth).setLineStyle(LineStyle.fromObject({ "color": color })).setTextStyle(TextStyle.fromObject({
      "color": color,
      "alignment": AlignmentStyle.Left,
      "font": "12px sans-serif"
    })).setNameLabel(name).setNameLabelPosition(AnchorType.TopCenter).setDepthLabel(depth + "").setDepthLabelPosition(AnchorType.BottomCenter)
  );
}
function addTopsCorrelation(track, leftDepth, rightDepth, color) {
  track.addChild(
    new CorrelationMarker({
      "linestyle": {
        "color": color,
        "width": 2,
        "pixelsnapmode": { "x": true, "y": true }
      },
      "leftdepth": leftDepth,
      "rightdepth": rightDepth
    })
  );
}
function createScene(canvas) {
  const widget = createWidget();
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setHeaderHeight("auto").fitToHeight();
  return plot;
}
function dispose() {
  bindingFunctions.forEach((bindingFunc) => DataBindingRegistry.getInstance().remove(bindingFunc));
}
export { createScene, dispose };

createScene(document.querySelector('[ref="plot"]'));