A live drilling screen is only as good as the chain behind it: sensors, an acquisition system, a WITSML server, a satellite link and the application that reads it. WITSML is the standard that lets those systems agree on what a reading is, which well it belongs to and when it was taken. This article explains the objects and the servers, works out how late a live reading really is and how much data a day of logging makes, and lists the checks that catch a feed going wrong.
What WITSML is
WITSML, the Wellsite Information Transfer Standard Markup Language, is a data standard published by Energistics. It defines two things: a data model for wells and everything recorded about them, written as XML schemas, and an interface through which applications read and write that data. Version 1.4.1.1 remains in wide use on rigs and in operations centres. Version 2.0 changed both the model and the transport; the two are compared in WITSML 1.4.1 against 2.0 and ETP.
Three roles meet in any WITSML set-up. Producers measure: the mud-logging unit, the drilling data recorder, the MWD and LWD surface systems. Servers, also called stores, hold the data as WITSML objects. Consumers read it: real-time monitoring, engineering models, reporting. A provider's server may sit at the rig or in its data centre, and a consumer may be anywhere with a route to it.
WITSML did not replace everything before it. At the rig, many systems still exchange WITS Level 0, a plain-text stream of numbered records and items, typically sent once a second over a serial line or a network socket. Record 1, item 14 is average hookload, for example. WITS0 carries values with little context: no well identity, and units only by prior agreement between the two ends. WITSML adds identity, units and history.
The object model
Every WITSML 1.4.1.1 object sits in a hierarchy: a well, its wellbores, and the objects recorded against each wellbore. Each object carries its own identifier, the uid, and its parents' identifiers, uidWell and uidWellbore. An identifier only has to be unique within its parent. These are the objects a drilling team meets most often:
| Object | What it holds | Grows while drilling |
|---|---|---|
| well | Name, location, time zone, field and country | No |
| wellbore | One hole: the main bore, a pilot hole or a sidetrack, and its parent | No |
| log | Channels indexed by time or depth: a header naming each curve and its unit, then rows of values | Yes |
| trajectory | Survey stations: measured depth, inclination, azimuth, TVD, dogleg severity | Yes |
| mudLog | Lithology by interval, gas readings, shows | Yes |
| rig, bhaRun, tubular | The rig's equipment and the string in the hole | No |
| fluidsReport, opsReport, message | Mud checks, daily operations reports, time-stamped events | New ones are added |
The log does most of the work. Its header lists each curve in a logCurveInfo element with its mnemonic, unit and data type. Its data block names the mnemonics and units once, then sends each row as one line of comma-separated text, index first. A time log is indexed by date and time, a depth log by measured depth, and the same sensor can appear in both, sampled differently.
Log, trajectory and mudLog are growing objects. While the well is drilled, rows, stations and intervals are added to the same object, and its objectGrowing flag is true. Reading growing objects well is most of what "real-time WITSML" means.
Store and streaming
WITSML 1.x is a store. A server offers a small set of SOAP web-service calls: WMLS_GetFromStore to read; WMLS_AddToStore, WMLS_UpdateInStore and WMLS_DeleteFromStore to write; WMLS_GetCap and WMLS_GetVersion to find out what the server supports. Reads are queries by template. The reader sends an XML skeleton of the object with empty elements where it wants values, plus options such as returnElements=header-only or data-only to say how much comes back.
Nothing arrives unless someone asks. Streaming works the other way round: the producer pushes each new value as it is measured. WITS0 does this at the rig, and so does ETP, the WebSocket protocol that carries WITSML 2.0. With a 1.4.1.1 store, live data means asking for new rows often.
Following a growing log
An application following a log keeps a cursor: the last index it has stored. Each poll asks for rows from that index on, with startDateTimeIndex for a time log or startIndex and its unit for a depth log. The server answers from the cursor inclusive, so the reader drops the repeated boundary row and moves its cursor to the newest row it stored. Servers cap how much one answer carries. When the cap is hit, the answer comes back with Result 2, "partial", and the reader asks again from the last row it got. DrillIQ's own store caps an answer at 10,000 rows, so reading a day of a one-second log takes nine requests.
Two things trip up simple followers. New logs and new curves appear part-way through a well, so the headers have to be re-read now and then. And rows can change behind the cursor: a gap filled later from a file, or a corrected value. A follower that only looks forward never sees them. WITSML 1.4.1.1 has a standard object for this, the changeLog, which records the index range of each change so a reader can fetch that range again. Not every server keeps one.
How late a live reading is
Each step in the chain waits for the next. Take a rig on a geostationary satellite link, with the provider's WITSML server at the rig and the reading application in the office. The assumptions below are illustrative; replace them with your rig's settings.
- Sampling. The acquisition system records every second, so a change waits on average half a second to be sampled, and at most one.
- The server's write. Here the acquisition system appends rows to its WITSML log every 5 s: 2.5 s of waiting on average, 5 s at worst.
- The link. A geostationary satellite is 35,786 km up, and a request and its answer cross that distance four times: 4 × 35,786 km ÷ 299,792 km/s = 0.48 s at least, before any ground equipment. Call it 0.6 s.
- The reader. DrillIQ's follower pauses 2 s after each pass, and a pass takes about one round trip, so it reads every 2.6 s: 1.3 s of waiting on average and 2.6 s at worst. Pushing the row to the browser adds about 0.1 s.
- Total. 0.5 + 2.5 + 0.6 + 1.4 = 5.0 s on average, and 1.0 + 5.0 + 0.6 + 2.7 = 9.3 s at worst.
- Sampling every 1 s
- Rig server writes rows
- Satellite round trip
- DrillIQ reads, then pushes
- Freshness limit
Hand calculation with illustrative assumptions: 1 s sampling, the rig's WITSML server appending rows every 5 s, a 0.6 s geostationary round trip, DrillIQ's follower pausing 2 s between passes and 0.1 s to the browser. Average waits are half of each interval.
Show the data
| Sampling every 1 s | Rig server writes rows | Satellite round trip | DrillIQ reads, then pushes | |
|---|---|---|---|---|
| Average | 0.5 | 2.5 | 0.6 | 1.4 |
| Worst case | 1.0 | 5.0 | 0.6 | 2.7 |
| Worst, 1 s writes | 1.0 | 1.0 | 0.6 | 2.7 |
The largest item is the server's write interval, then the reader's poll interval, and the satellite comes third. Both intervals are settings, and each costs on average half its length. If the server wrote every second, the worst case would fall to 5.3 s with no change to the link.
That matters for how a screen marks freshness. DrillIQ's Rig Watch calls a reading fresh up to 8 s after the time it was measured, stale up to 30 s, and dead after that. With 5 s server writes the worst case of 9.3 s is past 8 s, so a healthy feed would flick to stale now and then. When that happens, ask the provider for the write interval before blaming the link.
How much data a day of logging makes
Data volume is rows a day times bytes a row. In a 1.4.1.1 log each row is text: a 24-character time stamp, the <data> tags and a line break (14 bytes), and about 8 bytes for each value with its comma. Forty channels make 24 + 14 + 40 × 8 = 358 bytes a row. At one row a second that is 86,400 rows, or 30.9 MB a day.
- 80 channels
- 40 channels
- 20 channels
Hand calculation: rows a day × bytes a row. A row is a 24-byte time stamp, 14 bytes of tags and line break, and about 8 bytes per value with its comma, as text in a WITSML 1.4.1.1 log. Envelopes and headers are left out.
Show the data
| Rate | 80 channels | 40 channels | 20 channels |
|---|---|---|---|
| 0.0 | 0.0 | 0.0 | 0.0 |
| 0.2 | 11.7 | 6.2 | 3.4 |
| 0.5 | 29.3 | 15.5 | 8.6 |
| 1.0 | 58.6 | 30.9 | 17.1 |
| 2.0 | 117.2 | 61.9 | 34.2 |
| 5.0 | 292.9 | 154.7 | 85.5 |
| 10.0 | 585.8 | 309.3 | 171.1 |
Volume grows in a straight line with channels and with sample rate: 309 MB a day for 40 channels at ten samples a second, 586 MB for 80. A 256 kbit/s link moves about 2.8 GB a day, so even the largest of these fits. On most feeds the limits are the number of requests and the waits between them, which is why the interval settings above matter more than bandwidth.
Channel mapping and units
The same quantity arrives under different names. One system sends HKLA, the WITS short name for average hookload; another sends "Hookload" or "Hook Load"; a third uses its own code. Units vary as much: hookload in klbf, kdaN, tf or "klbs"; pressure in psi, kPa or bar; mud density in ppg, SG or kg/m³. Before a model can use the data, each source channel has to be mapped to one meaning and one unit. A sound mapping follows a few rules:
- Store the unit on each mapping row. Two rigs can send one mnemonic in different units, and average and maximum torque from one rig can differ by a factor of 1,000 when one is in kft·lbf and the other in ft·lbf.
- A unit has to fit the channel's kind of quantity. A percentage mapped to a flow rate is an error, and no conversion fixes it.
- Prefer the averaged channel. WITS separates hookload (HKLD) from average hookload (HKLA), and engineering models are written for the averages.
- Map one source curve to each channel in a log. If measured, vertical and returns depth are all mapped to hole depth, their rows interleave and the trace jumps between them.
- Keep time stamps in UTC. A rig clock in local time, read as UTC, shifts every row by the time-zone offset and makes the data look hours late or early.
Data-quality checks
A feed can be connected and still be wrong. These checks are worth automating:
| Check | What it looks for | What it usually means |
|---|---|---|
| Gaps | Missing rows in the index; null markers such as −999.25 | A cut link, an acquisition restart, a sensor out of service |
| Latency | Each sample's time stamp against its arrival time | The write or poll interval, the link, a wrong time zone |
| Silence | No new rows for minutes from a source that should be live | A stopped service or a dead connection |
| Range | Values outside physical limits, such as hookload above the rig's rating | A unit error or a failing sensor |
| Spikes | A one-sample jump on one channel that related channels don't show | Electrical noise or a transmission error |
| Flat lines | The same value for many samples while the rig is working | A frozen sensor or a system repeating its last value |
| Duplicates | The same rows served twice, or shifted by a whole number of hours | A time-zone or replay fault at the source |
Spikes and flat lines need judgement. A hookload spike as the string is picked up off bottom is real; the same spike with no movement of the block is not. Gaps need a plan before they happen. If the rig buffers data through an outage and sends it later, or a provider supplies a file to fill the hole, the receiving system has to accept rows behind its cursor without duplicating them. Writes keyed on the index make that safe, because a row sent twice is stored once.
A checklist for the rig team
- Ask the provider which WITSML version and objects the server offers, and how often it writes new rows.
- Check that the rig's clocks are synchronised and that time stamps go out in UTC.
- Map every channel with its unit, and have an engineer approve the mapping before the data feeds any model.
- Keep to one source curve per channel in each log.
- Set the freshness limit above the chain's worst-case latency, so a healthy feed doesn't flicker.
- Watch for silence, gaps, out-of-range values and flat lines, and show on screen how each was judged.
- Agree how gaps will be filled after an outage, and confirm the receiving system re-reads them.
How DrillIQ handles it
DrillIQ's WITSML module connects to WITSML 1.3.1.1 and 1.4.1.1 servers over SOAP, receives WITS0 over TCP and UDP, and imports LAS and CSV files. It files a server's object tree in Project Explorer without fetching any rows (logs, trajectories, mud logs, rigs, messages, tubulars, wellbore geometries, BHA runs, risks, fluids reports and formation markers) and ingests only the logs and channels you select. Auto-map suggests a standard channel and unit conversion for each source curve, and approval is refused while a unit doesn't fit its channel. A follower polls each log for new rows with a 2 s pause between passes, re-reads any range a server's changeLog reports every 30 s, and refreshes growing trajectories every 90 s. The Health view shows each source's state and how it was judged, the Log Viewer plots the data against time and depth, and Rig Watch marks each reading fresh, stale or dead by its own time stamp.
At the rig, the Rig Connect agent reads WITS0, Modbus, OPC UA, a rig-site WITSML server or dropped files, buffers them on disk through link outages, and writes them with signed requests to DrillIQ's own WITSML 1.4.1.1 store, where each rig's well is set up and followed automatically, leaving only the channel mapping for an engineer to approve. The live views only read: nothing is sent back to the rig. Where each part can run is covered in on-premises deployment and drilling data sovereignty.
Book a demo See all capabilities
References
- Energistics. WITSML Data Schema, version 1.4.1.1.
- Energistics. WITSML Store Application Program Interface (API), version 1.4.1.
- Energistics. Energistics Transfer Protocol (ETP) Specification, version 1.2.
- W3C. Simple Object Access Protocol (SOAP) 1.1. W3C Note, 8 May 2000.