welltraj
v1.0.0
Published
Full well trajectory design and analysis library — minimum curvature, segment-based design, Pareto optimization, anti-collision, survey comparison, and 2D/3D visualization.
Maintainers
Readme
welltraj
Full well trajectory design and analysis library for oil & gas directional drilling.
Features
- Minimum curvature method — industry-standard survey computation (MD/INC/AZI → TVD/N/E/VS)
- Survey interpolation — interpolate at any MD, TVD, or VS; forward/backward extrapolation
- Trajectory design — build complete trajectories from KOP, build rate, and target (TVD + VS)
- Segment builder — fluent API:
.vertical().build().hold().drop().turn() - Multi-objective Pareto optimization — minimize MD, tortuosity, and collision risk simultaneously; knee-point selection
- Survey vs plan comparison — left/right, above/below, ahead/behind, centre-to-centre distance
- Anti-collision — separation factor scanning, ISCWSA MWD uncertainty ellipses
- Constraint validation — max DLS, max inclination, max MD, target tolerance
- I/O — parse CSV, JSON, LAS 2.0, WITSML-style tab files; export CSV, JSON, Markdown reports
- Visualization — 2D/3D Plotly.js charts (plan view, vertical section, DLS profile, Pareto front) and Three.js 3D renderer
- ES6 modules — tree-shakeable ESM + CJS + UMD builds
Installation
npm install welltrajOptional visualization peer dependencies:
npm install plotly.js-dist # for PlotlyRenderer
npm install three # for ThreeRendererQuick Start
import { Survey } from 'welltraj';
const survey = new Survey({ name: 'DEMO-01', vsAzimuth: 45 });
survey.setStations([
{ md: 0, inc: 0, azi: 45 },
{ md: 500, inc: 0, azi: 45 },
{ md: 1200, inc: 30, azi: 45 },
{ md: 2000, inc: 60, azi: 47 },
{ md: 3000, inc: 90, azi: 47 },
]);
// Computed coordinates
console.log(survey.get(-1)); // last station
console.log(survey.atMD(1600)); // interpolated at MD 1600
console.log(survey.stats()); // summary statistics
console.log(survey.toCSV()); // exportAPI Reference
Core
new Survey(options?)
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| name | string | 'Unnamed Well' | Well name |
| vsAzimuth | number | 0 | Vertical section reference azimuth (°) |
| origin | {tvd, north, east} | {0,0,0} | Starting coordinates |
Methods:
| Method | Returns | Description |
|--------|---------|-------------|
| setStations(stations) | Survey | Replace all stations (chainable) |
| addStation(md, inc, azi) | Survey | Append one station |
| get(i) | SurveyResult | Get result at index (negative = from end) |
| getAll() | SurveyResult[] | All computed results |
| atMD(md) | SurveyResult | Interpolate at measured depth |
| atTVD(tvd) | SurveyResult | Find point at TVD |
| atVS(vs) | SurveyResult | Find point at vertical section |
| stats() | Object | Trajectory statistics |
| toCSV(options?) | string | Export as CSV |
| toJSON() | Object | Export as JSON |
| Survey.fromCSV(text, options?) | Survey | Parse CSV |
| Survey.fromJSON(data, options?) | Survey | Parse JSON |
SurveyResult fields: md, inc, azi, tvd, north, east, vs, dls, dl, closure, closureAzi
Design
SegmentBuilder
import { SegmentBuilder } from 'welltraj';
const survey = new SegmentBuilder({ azimuth: 45, mdStep: 10 })
.vertical(500) // drill straight to 500m MD
.build(90, 3) // build to 90° at 3°/30m
.hold(1500) // 1500m horizontal section
.toSurvey({ name: 'My Well' });Methods: .vertical(length) · .build(targetInc, buildRate) · .drop(targetInc, dropRate) · .hold(length) · .turn(targetAzi, turnRate) · .station(md, inc, azi) · .toSurvey(options?) · .getStations()
TrajectoryDesigner
import { TrajectoryDesigner } from 'welltraj';
const survey = new TrajectoryDesigner({
kop: 500, azimuth: 45, buildRate: 3,
target: { tvd: 3200, vs: 1800 }
}).design();Optimizer
import { Optimizer } from 'welltraj';
const { front, knee, all } = new Optimizer({
baseOptions: { azimuth: 45, target: { tvd: 3200, vs: 1800 } },
buildRates: [2, 3, 4, 5],
kopValues: [300, 500, 700, 1000]
}).run();
console.log(`Knee point: KOP=${knee.params.kop}, buildRate=${knee.params.buildRate}`);Analysis
Survey vs Plan Comparison
import { compareSurveys, landingAccuracy } from 'welltraj';
const cmp = compareSurveys(actualSurvey, planSurvey);
// cmp[i].leftRight, .aboveBelow, .aheadBehind, .ctc
const accuracy = landingAccuracy(actualSurvey, { tvd: 3200, north: 1200, east: 1200 });Anti-Collision
import { scanAntiCollision, minSeparationFactor } from 'welltraj';
const records = scanAntiCollision(designSurvey, offsetWells);
const { sf } = minSeparationFactor(designSurvey, offsetWells);
console.log(`Min SF: ${sf.toFixed(3)}`); // >= 1.5 is safeConstraints
import { validate, passes } from 'welltraj';
const violations = validate(survey, {
maxDLS: 5, // °/30m
maxInc: 92, // °
maxMD: 6000,
targetTVD: 3200,
targetTolerance: 20
});I/O
import { parse, surveyTable, statsSummary } from 'welltraj';
// Auto-detect format
const survey = parse(csvOrJsonString, { name: 'My Well', vsAzimuth: 45 });
// Reports
console.log(surveyTable(survey));
console.log(statsSummary(survey));Visualization
import Plotly from 'plotly.js-dist';
import { PlotlyRenderer } from 'welltraj';
const r = new PlotlyRenderer(Plotly);
r.plot3D('container-id', [survey]);
r.plotVerticalSection('vs-div', [actualSurvey, planSurvey]);
r.plotDLS('dls-div', [survey], { maxDLS: 5 });Low-level functions
All core computations are also exported as standalone functions:
import { dogleg, doglegSeverity, ratioFactor, segment, compute } from 'welltraj';
const dl = dogleg(0, 45, 30, 47); // degrees
const dls = doglegSeverity(0, 45, 30, 47, 300); // °/30m
const seg = segment({ md: 0, inc: 0, azi: 0 }, { md: 300, inc: 30, azi: 45 });
// seg: { dTVD, dNorth, dEast, dls, dl }Examples
node examples/01-basic-survey.js
node examples/02-trajectory-design.js
node examples/03-anti-collision.js
node examples/04-pareto-optimization.jsTests
npm testBuild
npm run build # produces dist/welltraj.esm.js, .cjs.js, .umd.jsLicense
MIT © Ismail Harkat
