Use dlisio for binary RP66 DLIS and LIS79 input. It returns structured NumPy arrays and metadata objects; it does not write DLIS. Use lasio for LAS.
Select a logical file and frame
Inspect the physical file before selecting data. Logical files and frames may
have different depths, sampling rates and channel identities. dlis.load()
returns a PhysicalFile context manager, not a generator. Read array data
inside the context, then retain copied arrays or DataFrames after closing it.
from dlisio import dlis
def inventory(path): items = [] with dlis.load(str(path)) as files: for logical_index, logical in enumerate(files): for frame_index, frame in enumerate(logical.frames): items.append({ 'logical_file': logical_index, 'frame': frame_index, 'fingerprint': frame.fingerprint, 'index_type': frame.index_type, 'index': frame.index, 'channels': [(ch.fingerprint, ch.units, ch.dimension) for ch in frame.channels], }) return items
A channel's identity includes type, mnemonic, origin and copy number. Names
alone need not be unique. Use `channel.fingerprint` to access its array field;
`frame.curves()` uses fingerprints as dtype titles even when names are disambiguated.
The `FRAMENO` field records frame sequence numbers, not measured depth.
## Read scalar and array channels
```python
from dlisio import dlis
import pandas as pd
def read_frame(path, logical_file_index=0, frame_index=0):
with dlis.load(str(path)) as files:
if not 0 <= logical_file_index < len(files):
raise ValueError('Logical file index out of range')
logical = files[logical_file_index]
if not 0 <= frame_index < len(logical.frames):
raise ValueError('Frame index out of range')
frame = logical.frames[frame_index]
records = frame.curves()
scalar = {name: records[name].copy() for name in records.dtype.names
if records[name].ndim == 1}
arrays = {ch.fingerprint: records[ch.fingerprint].copy()
for ch in frame.channels if records[ch.fingerprint].ndim > 1}
metadata = {'frame': frame.fingerprint, 'index_type': frame.index_type,
'index': frame.index,
'channels': {ch.fingerprint: {'name': ch.name, 'units': ch.units,
'dimension': ch.dimension} for ch in frame.channels}}
return pd.DataFrame(scalar), arrays, metadata
Keep array/image channels as arrays, preserving all trailing dimensions.
A structured array has dtype.names, not .items(). Direct DataFrame
conversion fails when it contains multidimensional fields. Do not average
image channels into scalars without a requested, documented reduction.
Depth, missing values and conversion
- Check
frame.index_typeand the first channel's units before declaring an index to be depth. A time channel orFRAMENOis not a depth surrogate. - Preserve increasing or decreasing depth order. Duplicate/nonmonotonic depths need explicit handling; do not silently sort or resample different passes.
- DLIS has no universal LAS-style null sentinel. Retain NaNs and apply a vendor null marker only when its meaning is documented. Preserve masks through export.
- Read frame and channel handling for identity, searching and separate lossless array export. Read file structure and LIS for metadata, encodings and the separate LIS API.
The bundled DLIS-to-LAS helper always includes a
validated depth curve first, even when --curves requests only measurements.
It accepts a unique mnemonic or full fingerprint, preserves m/ft and depth
order, and writes STEP=0 for irregular sampling. Arrays are excluded with a
diagnostic by default; explicitly requesting one fails instead of discarding it.
LAS is a lossy representation of DLIS metadata and multidimensional samples.
python scripts/dlis_to_las.py well.dlis --list
python scripts/dlis_to_las.py well.dlis scalar.las --logical-file 0 --frame 0 --curves GR
Resolve the script path relative to this installed skill directory. For a
non-depth-indexed frame, require an explicit --depth-channel. Supported
export depth units are m and ft; other units need a documented conversion.
--null-value records the operator's choice of a known vendor sentinel.
Verification scope
Checked with dlisio 1.0.4 using project-generated binary DLIS, including multiple logical files/frames, duplicate mnemonics, scalar/array channels, NaNs and LAS roundtrips. These synthetic files are project-owned, not redistributed field logs. LIS, damaged-file recovery and vendor-specific records need their own fixtures; do not claim those branches were exercised by the DLIS tests.
Official DLIS API, checked 2026-09-14. Use strict parsing unless an explicit, recorded recovery decision justifies relaxing it; errors must not be reported as successful empty exports.