Much of the rig data in use today still reaches the office through WITSML 1.4.1.1, polled over SOAP. WITSML 2.0 changes the data model and hands transport to ETP, a streaming protocol that runs over WebSockets. This article sets the two side by side, works out what streaming saves in delay and in empty requests, and lays out a migration that keeps the rig feed running while it happens.
A data model and a transport
WITSML 1.4.1.1 bundles two things: a data model, written as XML schemas, and the Store interface, a SOAP web service through which applications read and write that data. WITSML explained covers both. WITSML 2.0 is a data model only. It belongs to the Energistics Common Technical Architecture, which it shares with RESQML for earth models and PRODML for production data, and the protocol designed to carry it is the Energistics Transfer Protocol, ETP.
A move to 2.0 is therefore two decisions: which data model your systems exchange, and which transport carries it. In practice they travel together, and a provider that offers 2.0 normally offers it over ETP. It still pays to keep the two apart when you assess a change. The data model decides how objects are identified, linked and described. The transport decides how quickly new data arrives and what it costs to ask for it.
What changes
| WITSML 1.4.1.1 | WITSML 2.0 with ETP | |
|---|---|---|
| Transport | SOAP over HTTP: one request, one answer | One WebSocket session, with sub-protocols for discovery, store access, notifications and channel streaming |
| New data | The reader polls growing objects | The server pushes channel data and change notifications to subscribers |
| Messages | XML text in a SOAP envelope | Binary-encoded messages; objects travel inside them as XML |
| Identity | A uid unique within its parent, plus the parents' uids | A UUID per object, unique on its own, and typed references between objects |
| Structure | Objects in plural containers, nested by their parents' uids | One object per document, linked to others by reference |
| Real-time curves | A log: a header, then comma-separated rows | Channels, grouped into channel sets held by a log |
| Units | The unit list of the 1.x standard | The Energistics Unit of Measure Standard, shared across the Energistics standards |
| Finding changes | dTimLastChange and the changeLog object | Store notifications pushed when an object changes |
Three of these changes reach the engineer as well as the software.
Identity. A 1.4.1.1 uid only has to be unique within its parent, so two wells can each have a wellbore called "wb1" and a log called "time-1s". A system that stores data from several servers has to key on the full path: server, well, wellbore, object. A 2.0 UUID is unique on its own. Moving between the two needs a mapping table, built once and kept. Regenerating UUIDs on every export breaks every reference to the object.
Curves. In 1.4.1.1 a log is a table: one index, many curves, rows of text. In 2.0 each channel carries its own metadata, and channel sets group the channels that share an index. That suits streaming, because a reader can subscribe to the eight channels it needs instead of a whole log.
Units. 2.0 uses the Energistics Unit of Measure Standard, and some symbols are written differently from the 1.x list. Map units through a conversion table and check each one. An unrecognised unit should stop the mapping until someone has looked at it; passing it through as a label hides the problem.
Not every 1.4.1.1 object maps one-to-one onto 2.0. Test each object type you depend on, starting with the ones engineering models read: logs, trajectories, mud logs and BHA runs.
Polling against streaming: the delay
With 1.4.1.1 a new row waits for the next poll; with ETP the server sends it when it arrives. The arithmetic, for a rig on a geostationary satellite link:
- Polling every T seconds. A new row waits on average T/2 for the next poll, and at worst T. The poll and its answer then cross the link: at least 4 × 35,786 km ÷ 299,792 km/s = 0.48 s, taken as 0.6 s with ground equipment.
- At T = 2 s: 1.0 + 0.6 = 1.6 s on average and 2.6 s at worst.
- At T = 10 s: 5.6 s on average and 10.6 s at worst.
- Streaming. The row crosses the link once: at least 2 × 35,786 ÷ 299,792 = 0.24 s, taken as 0.3 s, whatever the poll interval would have been.
- Polling, average
- Polling, worst case
- Streaming
Hand calculation over a geostationary link: a poll waits half its interval on average (all of it at worst) plus a 0.6 s round trip; a pushed row crosses once, 0.3 s. Server write intervals, the same for both, are left out.
Show the data
| Poll every | Polling, average | Polling, worst case |
|---|---|---|
| 1.0 | 1.1 | 1.6 |
| 2.0 | 1.6 | 2.6 |
| 3.0 | 2.1 | 3.6 |
| 4.0 | 2.6 | 4.6 |
| 5.0 | 3.1 | 5.6 |
| 6.0 | 3.6 | 6.6 |
| 8.0 | 4.6 | 8.6 |
| 10.0 | 5.6 | 10.6 |
| 12.0 | 6.6 | 12.6 |
| 15.0 | 8.1 | 15.6 |
| 20.0 | 10.6 | 20.6 |
| 25.0 | 13.1 | 25.6 |
| 30.0 | 15.6 | 30.6 |
Polling's delay grows with half the interval, while streaming's stays flat. At a 2 s interval polling costs about 1.3 s more than streaming on average, which nobody on the rig floor would notice. At 30 s it costs about 15 s, which a well-control screen would. Both share any wait at the source: if the acquisition system writes rows to its server every 5 s, streaming that server's data cannot beat 5 s either. Streaming removes the poll; it doesn't remove the source's batching.
Polling against streaming: the requests
The second cost of polling is the requests that find nothing. Take one well with four growing objects, each polled once per interval, drilling at 20 m/h:
- Arrivals. The time log gets a row every second. The depth log gets one every 0.1 m, which at 20 m/h is every 18 s. The mud log gets a sample every 5 m (900 s), and the trajectory a survey every 30 m (5,400 s).
- Polls. At a 2 s interval each object is polled 43,200 times a day: 172,800 polls in all.
- Empty polls. A poll finds something only if a row arrived since the last one. The time log always has one. Only one depth-log poll in nine finds a row, so 38,400 of its polls are empty; the mud log has 43,104 empty polls and the trajectory 43,184. That is 124,688 empty polls a day, 72 % of the total.
- Polls that find new rows
- Polls that find nothing
- Streamed messages
Hand calculation: a time log, a depth log, a mud log and a trajectory, each polled once per interval, drilling at 20 m/h. New rows arrive every 1 s, 18 s (0.1 m), 900 s (5 m) and 5,400 s (30 m). A poll finds rows only if one arrived since the last poll.
Show the data
| Polls that find new rows | Polls that find nothing | |
|---|---|---|
| 1 s | 91.3 | 254.3 |
| 2 s | 48.1 | 124.7 |
| 5 s | 22.2 | 46.9 |
| 10 s | 13.6 | 21.0 |
| 30 s | 5.9 | 5.7 |
| 60 s | 3.0 | 2.8 |
Longer intervals cut the total and the waste together, but the share of waste falls slowly: at 10 s, 61 % of 34,560 polls are still empty, and at 30 s, 49 % of 11,520. It stays high because the mud log and the trajectory almost never have anything new.
Streaming sends a message only when something changes. That doesn't always mean fewer messages. At one message per new row this well streams 91,312 a day, more than polling every 5 s sends requests. What streaming removes is the empty round trip and the wait for the next poll. A producer can also put several rows into one message, which brings the count down.
A migration path
No rig should lose its feed while the standard changes. A staged path looks like this:
- Inventory. List every producer and consumer, the WITSML versions and objects each supports, and the channels each consumer reads.
- Keep 1.4.1.1 running. Add a 2.0 feed beside it on one rig and one well, and switch nothing off.
- Map identity and units once. Keep one table from 1.4.1.1 uid paths to 2.0 UUIDs and one unit table, both under change control.
- Run both and compare. Check the same channels at the same index, with values equal within rounding, and count gaps and measure latency on each feed for at least one full hole section.
- Move consumers one at a time. Retire the 1.4.1.1 feed only when nothing reads it.
Running both has a cost: two feeds, two mappings, and the risk of one well's data arriving twice by two routes. Keep each feed's logs apart in the receiving system, and key stored rows on their index so that a row arriving twice is stored once.
One step gets much of streaming's benefit with no change to the provider's server: poll at the rig and push across the link. An agent on the rig network polls a rig-site 1.4.1.1 server over the local network, where a round trip takes milliseconds, and sends only the new rows across the satellite. The empty polls never leave the rig, and the office sees each row as soon as the agent forwards it.
What to ask a provider
- Which WITSML versions does the server support, and which objects: logs, trajectories, mud logs, reports?
- Does it offer ETP? Which version, and which sub-protocols: channel streaming, store notifications, discovery?
- How often does the acquisition system write new rows to the server?
- What is the largest answer it returns, and does it honour a list of mnemonics in a log query?
- Does it keep a changeLog, so that filled gaps and corrections can be found?
- Which mnemonics and unit symbols does it use, and is there a channel dictionary?
- Are time stamps written in UTC, or in local time with an offset?
- Can it deliver WITS0 or a 1.4.1.1 feed alongside 2.0 while consumers move?
A checklist for the rig team
- Know the version and transport of every data feed on the rig.
- Get the server's write interval and set poll intervals to match it.
- Keep the 1.4.1.1 feed until the 2.0 feed has matched it on the same well.
- Compare both feeds channel by channel before moving a consumer.
- Keep identifiers and units in one mapping table under change control.
- Where the provider's server is at the rig, poll it there and push new rows across the link.
- Check that both feeds write time stamps in UTC.
How DrillIQ handles it
DrillIQ's WITSML module reads WITSML 1.3.1.1 and 1.4.1.1 servers over SOAP and WITS0 feeds, and imports LAS and CSV files. It can't yet read WITSML 2.0 over ETP, so a source that offers only 2.0 needs a 1.4.1.1 or WITS0 output beside it for now. The version belongs to the source. Every source's channels are mapped to the same standard channels and units, with an engineer's approval, so the engineering modules read the same data whichever version delivered it.
At the rig, the Rig Connect agent polls a rig-site WITSML 1.4.1 server over the rig network, every 10 s by default and read-only, and forwards only the new rows to DrillIQ's own store with signed writes, buffering them on disk when the link drops. The store records every write that lands behind a log's head as a changeLog entry, and DrillIQ re-reads those ranges, so gaps filled after an outage reach the modules. How the parts are deployed is covered in on-premises deployment and drilling data sovereignty.
Book a demo See all capabilities
References
- Energistics. WITSML Store Application Program Interface (API), version 1.4.1.
- Energistics. WITSML Standard, version 2.0.
- Energistics. Energistics Transfer Protocol (ETP) Specification, version 1.2.
- Energistics. Energistics Unit of Measure Standard, version 1.0.
- Fette, I. and Melnikov, A. The WebSocket Protocol. RFC 6455, IETF, 2011.