This tutorial shows how to request well data from IVAAP backend. This tutorial creates geotoolkit.ivaapbackend.well.RemoteWellLogDataSource datasource to control data requests.
# Log Curve Data
The canvas below shows how Log Curve data can be requested from the server.
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { LogCurveDataSource } from "@int/geotoolkit/welllog/data/LogCurveDataSource.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { Orientation } from "@int/geotoolkit/util/Orientation.ts";
import { RemoteWellLogDataSource } from "@int/geotoolkit/ivaapbackend/well/RemoteWellLogDataSource.ts";
import { UnitFactory } from "@int/geotoolkit/util/UnitFactory.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { MathUtil } from "@int/geotoolkit/util/MathUtil.ts";
import { log, warn } from "@int/geotoolkit/base.js";
import { authorize, headers } from "/src/helpers/IvaapAutorize.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
const unitFactory = UnitFactory.getInstance();
unitFactory.addUnit("0.1 in", ["length"], "0.1inch", "m", 0, 254e-5, 1, 0);
const ERROR_LOAD_WELLS = "Cannot load wells from ivaap server";
function isCurveData(data) {
return data != null && data.length > 0 && typeof data[0] === "number";
}
function generateData(scaleUnit) {
return getLogCurvesData().then(
(result) => result.map((data) => {
let values = data.values;
if (!isCurveData(values)) {
return null;
}
const depthUnit = unitFactory.getUnit(data.indexUnit);
values = values.map(
(value) => MathUtil.equals(value, data.emptyValue) || MathUtil.equals(value, data.nullValue) ? Number.NaN : value
);
const depths = data.depths.map((depth) => depthUnit.convert(depth, scaleUnit));
return new LogCurveDataSource({
"depths": depths,
"values": values,
"name": data.name
});
})
);
}
function getLogCurvesData() {
const wellsServiceUrl = "https://pub.ivaap.int.com/ivaap/api/ds/mongo/v1/sources/e7b82fa5-6186-404f-994a-d50c18bb23ec/wells";
const wellsServiceDataSource = new RemoteWellLogDataSource();
let logDataset = null;
return authorize().then(
() => wellsServiceDataSource.setProperties({ "requestheaders": headers }).loadWellsMeta(wellsServiceUrl).then((wellCollection) => {
const wellMeta = wellCollection.items.find((wellMeta2) => wellMeta2.content.name === "15/9-F-5");
return wellsServiceDataSource.loadWellData(wellMeta);
}).then((wellData) => wellsServiceDataSource.loadLogsMeta(wellData)).then((logsCollection) => {
const logMeta = logsCollection.items.find(
(meta) => meta.content.name === "QC Data/15/9-F-5/&0&B34604_2"
);
return wellsServiceDataSource.loadLogData(logMeta);
}).then((logData) => {
logDataset = logData;
const curveInfoList = logData.content.curveInfoList;
const logCurves = curveInfoList.filter(
(info) => info.numColumns === 1 && info.name !== logData.content.indexInfo.indexName
);
return Promise.all(logCurves.map((curveInfo) => {
const curveIds = [curveInfo.dataUID];
const minIndex = curveInfo.minIndex;
const maxIndex = curveInfo.maxIndex;
const indexType = logData.content.indexInfo.indexType;
return wellsServiceDataSource.loadLogCurveValues(logData, curveIds, minIndex, maxIndex, indexType);
}));
}).then(
(dataArray) => dataArray.map((curvesData) => {
const indexName = logDataset.content.indexInfo.indexName;
const depthsData = curvesData.map(
(curveData) => isCurveData(curveData.data) && curveData.name === indexName ? {
name: curveData.name,
depths: curveData.data
} : null
).find((data) => data != null);
const valuesData = curvesData.map(
(curveData) => isCurveData(curveData.data) && curveData.name !== indexName ? {
name: curveData.name,
values: curveData.data
} : null
).find((data) => data != null);
const curveInfoList = logDataset.content.curveInfoList;
const curveInfo = curveInfoList.find((info) => info.name === valuesData.name);
return {
name: valuesData.name,
depths: depthsData.depths,
values: valuesData.values,
emptyValue: curveInfo.emptyValue,
nullValue: curveInfo.nullValue,
indexUnit: logDataset.content.indexInfo.unitName
};
})
)
).catch((error) => {
log(error);
throw new Error(ERROR_LOAD_WELLS);
});
}
function createScene(canvas) {
const widget = createWellLogWidget().setOrientation(Orientation.Vertical).setAxisHeaderType(HeaderType.Simple).scale(2);
generateData(widget.getTrackContainer().getIndexUnit()).then((dataSources) => {
if (widget.isDisposed())
return;
let minDepth = Number.POSITIVE_INFINITY;
let maxDepth = Number.NEGATIVE_INFINITY;
widget.addTrack(TrackType.IndexTrack);
dataSources.forEach((dataSource) => {
if (minDepth > dataSource.getMinDepth()) {
minDepth = dataSource.getMinDepth();
}
if (maxDepth < dataSource.getMaxDepth()) {
maxDepth = dataSource.getMaxDepth();
}
widget.addTrack(TrackType.LinearTrack).addChild([
new LogCurve(dataSource).setLineStyle(KnownColors.Red)
]);
widget.addTrack(TrackType.IndexTrack);
});
widget.setDepthLimits(minDepth, maxDepth);
}).catch((error) => {
warn(error);
});
return new Plot({
"canvaselement": canvas,
"root": widget
});
}
export { createScene };
createScene(document.querySelector('[ref="plot"]'));
# Array Log Data
The canvas below shows how Array Log data can be requested from the server.
import { Log2DVisual, PlotTypes } from "@int/geotoolkit/welllog/Log2DVisual.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { Orientation } from "@int/geotoolkit/util/Orientation.ts";
import { CompositeLog2DVisualHeader } from "@int/geotoolkit/welllog/header/CompositeLog2DVisualHeader.ts";
import { ArrayLogDataSource } from "@int/geotoolkit/welllog/data/ArrayLogDataSource.ts";
import { DataTable } from "@int/geotoolkit/data/DataTable.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { RemoteWellLogDataSource } from "@int/geotoolkit/ivaapbackend/well/RemoteWellLogDataSource.ts";
import { UnitFactory } from "@int/geotoolkit/util/UnitFactory.ts";
import { MathUtil } from "@int/geotoolkit/util/MathUtil.ts";
import { log, warn } from "@int/geotoolkit/base.js";
import { create2DVisual } from "/src/code/WellLog/utils/util.ts";
import { authorize, headers } from "/src/helpers/IvaapAutorize.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
const unitFactory = UnitFactory.getInstance();
unitFactory.addUnit("0.1 in", ["length"], "0.1inch", "m", 0, 254e-5, 1, 0);
const ERROR_LOAD_WELLS = "Cannot load wells from ivaap server";
function isArrayData(data) {
return data != null && data.length > 0 && Array.isArray(data[0]);
}
function generateData(scaleUnit) {
return getLogArrayData().then(
(result) => result.map((data) => {
const table = new DataTable({
"cols": [
{ "name": "depth", "type": "number", "unit": scaleUnit.getSymbol() },
...data.angles.map((v) => ({ "name": v + "", "type": "number" }))
],
"colsdata": []
});
const depthUnit = unitFactory.getUnit(data.indexUnit);
for (let i = 0; i < data.depths.length; i++) {
let row = data.values[i];
if (!Array.isArray(row))
continue;
row = row.map(
(value) => MathUtil.equals(value, data.emptyValue) || MathUtil.equals(value, data.nullValue) ? Number.NaN : value
);
const depth = depthUnit.convert(data.depths[i], scaleUnit);
table.addRow([depth, ...row]);
}
return new ArrayLogDataSource({
"name": data["name"],
"datatable": table,
"angles": {
"values": data["angles"]
}
});
})
);
}
function generateAngles(values) {
return values[0].map((v, i, arr) => Math.PI * 2 / (arr.length - 1) * i);
}
function getLogArrayData() {
const wellsServiceUrl = "https://pub.ivaap.int.com/ivaap/api/ds/mongo/v1/sources/e7b82fa5-6186-404f-994a-d50c18bb23ec/wells";
const wellsServiceDataSource = new RemoteWellLogDataSource();
let logDataset = null;
return authorize().then(
() => wellsServiceDataSource.setProperties({ "requestheaders": headers }).loadWellsMeta(wellsServiceUrl).then((wellCollection) => {
const wellMeta = wellCollection.items.find((wellMeta2) => wellMeta2.content.name === "15/9-F-5");
return wellsServiceDataSource.loadWellData(wellMeta);
}).then((wellData) => wellsServiceDataSource.loadLogsMeta(wellData)).then((logsCollection) => {
const logMeta = logsCollection.items.find(
(meta) => meta.content.name === "QC Data/15/9-F-5/&0&B34604_2"
);
return wellsServiceDataSource.loadLogData(logMeta);
}).then((logData) => {
logDataset = logData;
const curveInfoList = logData.content.curveInfoList;
const logArrays = curveInfoList.filter((info) => info.numColumns > 1);
return Promise.all(logArrays.map((curveInfo) => {
const curveIds = [curveInfo.dataUID];
const minIndex = curveInfo.minIndex;
const maxIndex = curveInfo.maxIndex;
const indexType = logData.content.indexInfo.indexType;
return wellsServiceDataSource.loadLogCurveValues(logData, curveIds, minIndex, maxIndex, indexType);
}));
}).then(
(dataArray) => dataArray.map((curvesData) => {
const depthsData = curvesData.map(
(curveData) => !isArrayData(curveData.data) ? {
name: curveData.name,
depths: curveData.data
} : null
).find((data) => data != null);
const valuesData = curvesData.map(
(curveData) => isArrayData(curveData.data) ? {
name: curveData.name,
values: curveData.data
} : null
).find((data) => data != null);
const angles = generateAngles(valuesData.values);
const curveInfoList = logDataset.content.curveInfoList;
const curveInfo = curveInfoList.find((info) => info.name === valuesData.name);
return {
name: valuesData.name,
depths: depthsData.depths,
values: valuesData.values,
angles,
emptyValue: curveInfo.emptyValue,
nullValue: curveInfo.nullValue,
indexUnit: logDataset.content.indexInfo.unitName
};
})
)
).catch((error) => {
log(error);
throw new Error(ERROR_LOAD_WELLS);
});
}
function createScene(canvas) {
const widget = createWellLogWidget().setOrientation(Orientation.Vertical).setAxisHeaderType(HeaderType.Simple).scale(2);
const headerProvider = widget.getHeaderContainer().getHeaderProvider();
headerProvider.registerHeaderProvider(Log2DVisual.getClassName(), new CompositeLog2DVisualHeader());
generateData(widget.getTrackContainer().getIndexUnit()).then((dataSources) => {
if (widget.isDisposed())
return;
let minDepth = Number.MAX_VALUE;
let maxDepth = Number.MIN_VALUE;
widget.addTrack(TrackType.IndexTrack);
dataSources.forEach((dataSource) => {
if (minDepth > dataSource.getMinDepth()) {
minDepth = dataSource.getMinDepth();
}
if (maxDepth < dataSource.getMaxDepth()) {
maxDepth = dataSource.getMaxDepth();
}
widget.addTrack(TrackType.LinearTrack).addChild([
create2DVisual(dataSource, dataSource.getName(), 0, "#fff9c4", true).setPlotType(PlotTypes.Linear)
]);
widget.addTrack(TrackType.IndexTrack);
});
widget.setDepthLimits(minDepth, maxDepth);
}).catch((error) => {
warn(error);
});
return new Plot({
"canvaselement": canvas,
"root": widget
});
}
export { createScene };
createScene(document.querySelector('[ref="plot"]'));