This WellLog–Multi Well Correlation widget demonstrates how to create and display correlated well logs. By default, a WellLog–Multi Well Correlation widget has a track container, header and footer containers, and default tools. A track container can display different well tracks, correlation panels, or log tracks. The wells can be visualized with different depth scales and offsets. The well track is based on WellLog widget functionality and supports all visuals and templates supported for single well visualization.
This tutorial assumes familiarity with the WellLog Introduction and WellLog Widget tutorials.
# Create a Widget
The first step is to create an empty widget.
# Add Wells
The next step is to add wells to the empty widget and correlation panels between the wells. The code below adds three well tracks and two correlation panels.
# Fill Wells with Data
In the next step, add tracks with curves to the three well tracks. The well track API is very similar to the WellLog Widget. 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.
# Add Tops
In the next step, add tops for each well. A top is an instance of geotoolkit/welllog/LogMarker to be added to the marker layer of the well. See WellLog–Markers .
# Add Tops Correlation
The last step is to display the correlation between the three well tops. The code below manually creates correlations and specifies which tops are to be connected on the left and right well tracks. Tops correlation will be added to the created correlation panels.
Polygon correlation, geotoolkit/welllog/multiwell/correlation/CorrelationRange, can be used to connect two ranges of depths on different wells, which is not covered in this tutorial.
# Result
This WellLog–Multi Well Correlation widget builds upon Getting Started . This tutorial walks through how to create a basic Multi Well Correlation widget (shown below) with three well tracks and two curves inside each track. The correlation panels are added in between the well tracks.
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { MultiWellWidget } from "@int/geotoolkit/welllog/multiwell/MultiWellWidget.ts";
import { TrackType as MultiWellTrackType } from "@int/geotoolkit/welllog/multiwell/TrackType.ts";
import { TrackType as WellLogTrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { LogMarker } from "@int/geotoolkit/welllog/LogMarker.ts";
import { CorrelationMarker } from "@int/geotoolkit/welllog/multiwell/correlation/CorrelationMarker.ts";
import { LineStyle } from "@int/geotoolkit/attributes/LineStyle.ts";
import { AlignmentStyle, TextStyle } from "@int/geotoolkit/attributes/TextStyle.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { MathUtil } from "@int/geotoolkit/util/MathUtil.ts";
import curvesData from "/src/code/WellLog/MultiWell/data/data.json?import";
function createWidget() {
const widget = new MultiWellWidget({
"verticalscrollable": "auto",
"horizontalscrollable": "auto",
"tools": {
"cursortracking": {
"tooltip": {
"enabled": true
}
}
}
});
const well1 = widget.addTrack(MultiWellTrackType.WellTrack, {
"range": new Range(0, 500),
"welllog": {
"range": new Range(4500, 5e3)
},
"name": "Well #1",
"title": '${name}<br/><span style="background-color: #DCDCDC">1 ${deviceUnit} : ${scaleValue} ${scaleUnit}</span>',
"tools": {
"navigation": true
}
});
const correlationTrack1 = widget.addTrack(MultiWellTrackType.CorrelationTrack, {
"width": 50
});
const well2 = widget.addTrack(MultiWellTrackType.WellTrack, {
"range": new Range(50, 300),
"welllog": {
"range": new Range(2500, 5e3)
},
"name": "Well #2",
"title": '${name}<br/><span style="background-color: #DCDCDC">1 ${deviceUnit} : ${scaleValue} ${scaleUnit}</span>',
"tools": {
"navigation": true
}
});
const correlationTrack2 = widget.addTrack(MultiWellTrackType.CorrelationTrack, {
"width": 50
});
const well3 = widget.addTrack(MultiWellTrackType.WellTrack, {
"range": new Range(25, 400),
"welllog": {
"range": new Range(4700, 5e3)
},
"name": "Well #3",
"title": '${name}<br/><span style="background-color: #DCDCDC">1 ${deviceUnit} : ${scaleValue} ${scaleUnit}</span>',
"tools": {
"navigation": true
}
});
addWellData(well1, 4500);
addWellData(well2, 2500);
addWellData(well3, 4700);
function addWellData(well, startDepth) {
well.addTrack(WellLogTrackType.IndexTrack);
well.addTrack(WellLogTrackType.LinearTrack).addChild([
createCurve(createTestData(startDepth, 10, "GR")).setLineStyle(KnownColors.Green),
createCurve(createTestData(startDepth, 10, "CALI")).setLineStyle(KnownColors.Orange)
]);
}
addTops(well1, "Tarbert", 4750, KnownColors.DarkRed);
addTops(well2, "Tarbert", 3e3, KnownColors.DarkRed);
addTops(well3, "Tarbert", 4800, KnownColors.DarkRed);
function addTops(well, name, depth, color) {
const top = new LogMarker(depth);
top.setLineStyle(LineStyle.fromObject({ "color": color }));
top.setTextStyle(TextStyle.fromObject({
"color": color,
"alignment": AlignmentStyle.Left,
"font": "12px sans-serif"
}));
top.setNameLabel(name);
top.setNameLabelPosition(AnchorType.TopCenter);
top.setDepthLabel(depth + "");
top.setDepthLabelPosition(AnchorType.BottomCenter);
well.getMarkerLayer().addChild(top);
}
addTopsCorrelation(correlationTrack1, 4750, 3e3, KnownColors.DarkRed);
addTopsCorrelation(correlationTrack2, 3e3, 4800, KnownColors.DarkRed);
function addTopsCorrelation(track, leftDepth, rightDepth, color) {
track.addChild(new CorrelationMarker({
"linestyle": {
"color": color,
"width": 2,
"pixelsnapmode": { "x": true, "y": true }
},
"leftdepth": leftDepth,
"rightdepth": rightDepth
}));
}
return widget;
}
function createCurve(dataSource) {
const limits = MathUtil.calculateNeatLimits(dataSource.getMinValue(), dataSource.getMaxValue(), false, false);
return new LogCurve(dataSource).setLineStyle({
color: KnownColors.Blue,
width: 2
}).setNormalizationLimits(limits.getLow(), limits.getHigh());
}
function createScene(canvas) {
const widget = createWidget();
const plot = new Plot({
"canvaselement": canvas,
"root": widget
});
widget.setHeaderHeight("auto").fitToHeight();
return plot;
}
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 createTestData(from, step, 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 * step + from);
values.push(curveData[i]);
}
data.setValues(depths, values);
return data;
}
export { createScene };
createScene(document.querySelector('[ref="plot"]'));