Skip to content

Well files

Ophiolite reads the well files that public archives such as NLOG deliver, as they are delivered: nothing is converted, repaired or guessed.

FileWhat is readWhat is refused, with the sentence you see
LAS 1.2 and 2.0every curve and every row, the version as the file states ita wrapped file
LAS 3.0files in the LAS 2 layout (one ~ASCII data section), delimited by spaces or tabsdata delimited by commas: “Unsupported LAS: the data are delimited by COMMA; LAS files delimited by spaces or tabs are read. No conversion was applied.”; LAS 3.0 data sections such as ~Log_Data: “Unsupported LAS: this file uses LAS 3.0 data sections (such as ~Log_Data with its definitions), which are not read; LAS files with one ~ASCII data section are. No conversion was applied.”
Time-depth table (CSV)a header depth,time or depth,time,velocity, then one pair per line, depth and time strictly increasinga pair whose depth or time does not increase; a table with fewer than two pairs

A LAS 2.0 file reads exactly as it did before older and newer versions were added.

A time-depth table does not say what its numbers mean, so you declare it when you upload it: whether depth is measured depth, true vertical depth or true vertical depth below sea level, its unit, whether time is one-way or two-way, and its unit. “Unknown” is an answer and stays unknown. The datum and the seismic reference elevation are optional; a table without a datum says “Not stated”, never a guess.

Drop the files on Add data. Each file shows what was read before anything is added, for example “Well log (LAS)” with “What was read: 1,520 rows, 5 curves, 0 missing samples” for a LAS 1.2 file, or “Time-depth table (CSV)” with “What was read: 1,906 pairs”. A refused file says why, and nothing is added.

For a time-depth table, Needs your decision asks Depth measured as, Depth unit, Time is and Time unit; Depth datum shows “Not stated” until you give one. After Add this file, the report says “A time-depth table belongs to one wellbore. Choose it.” Choose the wellbore under Belongs to wellbore and select Link.

Open the table in Data. The inspector shows Belongs to (for example “wellbore PRW-06”), the number of pairs, the depth and time ranges with what they mean, for example “True vertical depth · depth 0 to 2550.57 m”, the datum, the first 200 pairs as the file states them (Show all for the rest) and a line of time against depth.

client is an ophiolite.Client for your project; see Build on Ophiolite for a key and the SDK. Upload a checkshot table with what you know about it, and say which wellbore it belongs to. path is the CSV file:

import uuid
declared = {"depth_type": "tvd", "depth_unit": "m", "time_kind": "two-way", "time_unit": "ms"}
upload = client.upload_data(path, profile="time-depth-csv/1", name="PRW-06 checkshots", declared=declared,
attribution="NLOG.NL", audience=[], rights_confirmed=True, command_id=str(uuid.uuid4()))
bore = next(e for e in client.entities("wellbore") if e.name == "PRW-06")
client.of_entity(upload.asset_id, upload.revision, bore, statement="The NLOG workbook names PRW-06")

Read it back at the exact version uploaded. The pairs are the file’s, in its order, and the declarations are yours:

table = next(a for a in client.assets() if a["name"] == "PRW-06 checkshots")
checkshots = client.read_data(table["asset_id"], table["revision"])
print(checkshots)
[link] = client.associations(assets=[table["asset_id"]], kind="wellbore")
print("Belongs to wellbore", link["entity"]["name"])

This prints <TimeDepth 1906 pairs, tvd m depth, two-way ms time> and Belongs to wellbore PRW-06. Each pair is (depth, time, velocity) as the file states it:

print(checkshots.pairs[1000])

This prints (1029.5, 1000, 3463.13). With the pandas extra (pip install "ophiolite[pandas]"), checkshots.to_frame() gives a DataFrame whose velocity column is a nullable Float64: a velocity the file leaves empty stays missing (<NA>), never zero.

Write a table you computed and publish it. write_time_depth asks for every declaration (write “unknown” when it is not known) and refuses pairs whose depth or time does not increase. Here the checkshots are read every 100 ms of two-way time, and the result belongs to the same wellbore:

import numpy as np
from ophiolite.writers import write_time_depth
times = np.arange(0, 1901, 100)
depths = np.round(np.interp(times, [t for _, t, _ in checkshots.pairs], [d for d, _, _ in checkshots.pairs]), 2)
written = write_time_depth(zip(depths, times), depth_type="tvd", depth_unit="m", time_kind="two-way", time_unit="ms")
result = client.publish_derived(written, name="PRW-06 checkshots every 100 ms", from_=[(table["asset_id"], table["revision"])],
method={"name": "Linear interpolation every 100 ms of two-way time", "declared": False},
command_id=str(uuid.uuid4()), of_entity={"kind": "wellbore", "entity_id": link["entity"]["entity_id"]})
print(client.read_data(result.asset_id, result.revision))

This prints <TimeDepth 20 pairs, tvd m depth, two-way ms time>. The result is private to you until you share it.

A refusal says what to do. ValidationFailed from ophiolite.writers names the problem, for example “Declare the depth type (write “unknown” when it is not known); nothing is inferred.” or “Time of pair 3 does not increase; pairs must be in strictly increasing time.”; nothing was published. A table already linked to one wellbore cannot be linked to another: a time-depth table belongs to one wellbore.

Wells and wellbores explains wells, wellbores and what belongs to them.