Exploring the Contents of DLIS Files with Python

DLIS files are a standard oil and gas industry data format. They are structured binary files that contain tables of well information, tool information and well logging data. They are much more complex and harder to open compared to flat LAS (Log ASCII Standard) files. This can make them more difficult to work with and often requires dedicated tools to view and explore their contents.
Luckily, Equinor has published a Python library called dlisio, which makes the process of exploring these files much easier.
dlsio is a Python library developed by Equinor ASA to read dlis files and Log Information Standard 79 (LIS79) files. The main idea behind the development of this library is to reduce the burden and effort of exploring and extracting data contained within these files without having to fully understand how they are structured. This allows users to focus on accessing and working with the data.
For more information on the dlisio library, you can check out the documentation below
Within this short tutorial, we will see how we can access the contents of the dlis file by converting information and data to a pandas dataframe, a much more common data format within Data Science.
Importing Libraries
If you have not already installed dlisio, you can do so directly within your Jupyter Notebook using the following command.
!pip install dlisio
Once the library has been installed, we can begin importing the necessary libraries. For this tutorial, we will need to import the dlis
module from dlisio, and the pandas library.
from dlisio import dlis
import Pandas as pd
Loading DLIS Data Files with DLISIO
Once the libraries have been imported, we can load our DLIS data using the following code.
The data used within this tutorial was downloaded from NLOG.nl, a website containing well logging data for the entire Dutch sector of the North Sea.
The data is free to download and use. Full details of the data licence can be found at the end of this article.
Python">f, *tail = dlis.load('Data/NLOG Data/NPN_TVN-1_23_Dec_2009_E3_Main_SONIC_057PUC.DLIS')
You will notice that we have two variables at the start: f
and *tail
. This is to accommodate the fact that dlis files can contain multiple logical files, representing additional well logging passes or other datasets that have been processed after data acquisition.
If we do have multiple logical files, the first one will be placed into f
and any subsequent logical files will be placed into *tail
.
If we want to check the contents of the first logical file, we can call upon the following code.
f.describe()
This will generate the following summary of the logical file. This summary includes information about the frames and channels (curves) contained within it. It also includes information about the logging tool setup, environment and other important parameters.

Working with DLIS Frames
Frames within a dlis file can also represent different logging passes or different stages of processed data. This can range from raw well log measurements to petrophysical interpretations or advanced processed data.
We can access the frames from the DLIS file by calling upon the following:
f.frames
Which returns a list of frames.
[Frame(60B), Frame(10B), Frame(15B)]
By looking at the frame names above, it can be difficult to tell what information and data is stored within them.
We could loop over each frame and print out its properties. However, to make things nicer to view and create code that can be reused, we can create a function which creates a summary pandas dataframe.
The function loops over each of the frames within the dlis file, extracts key information and puts that information into a summary dataframe.
def frame_summary(dlis_file: dlis) -> pd.DataFrame:
"""
Generates a summary DataFrame of the frames contained within a given DLIS file.
This function iterates through the frames and channels in the DLIS file,
converting depth values from inches to meters if necessary, and then compiles
the information into a DataFrame. The resulting DataFrame contains the frame
name, index type, index curve, minimum and maximum index, spacing, direction,
number of channels, and channel names for each frame.
Parameters:
dlis_file (DLIS): The DLIS file to summarise.
Returns:
DataFrame: A DataFrame summarising the frames and channels of the DLIS file.
"""
temp_dfs = []
for frame in dlis_file.frames:
for channel in frame.channels:
# Get the index units
if channel.name == frame.index:
depth_units = channel.units
# In cases where units are stored in inches, we need to convert to m
if depth_units == "0.1 in":
multiplier = 0.00254
else:
multiplier = 1
df = pd.DataFrame(data= [[frame.name,
frame.index_type,
frame.index,
(frame.index_min * multiplier),
(frame.index_max * multiplier),
(frame.spacing * multiplier),
frame.direction,
len(frame.channels),
[channel.name for channel in frame.channels]]],
columns=['Frame Name',
'Frame Index Type',
'Index Curve',
'Index Min',
'Index Max',
'Spacing',
'Direction',
'Number of Channels',
'Channel Names'])
temp_dfs.append(df)
final_df = pd.concat(temp_dfs)
return final_df.reset_index(drop=True)
When we pass in our first logical file, we get back the following information.
This contains information about the index used for each frame (e.g. time or depth), the depth range, spacing, logging direction, the number of logging measurements and their names.

Converting DLIS Curves / Channels to Pandas Dataframes
You will see from above that each of our frames within the dlis file contains channels. These channels represent well logging measurements. However, they can be difficult to work with directly.
Converting dlis channels to pandas dataframes can make data analysis and exploration much more accessible. By default, dlisio does not output dataframes. However, with a few lines of code, we can easily convert the channel data to a dataframe.
We first call upon the pd.DataFrame
method from pandas and pass in our logical file. We then call upon the frames contained within that logical file and access the required frame by passing in the index position of it. We can then call upon the curves method to access the individual logging curves.
df = pd.DataFrame(f.frames[1].curves())
When we run the above code (assuming we do not have multi-dimensional columns) we will get back the following dataframe.

You will notice in the above dataframe that the TDEP
values seem extremely large. This is due to the measurement being in units of 0.1 in. To convert this to metres, we need to multiply the TDEP
column by 0.00254.
Handling Arrays Within dlis Channels
When our channels contain array data, the previous line of code will not work. If we do have multi-dimensional data, we will get an error that the Data must be 1-dimensional
.
One way to deal with this is to exclude any channels that contain an array and only create the dataframe with single-dimensional data.
df = pd.DataFrame()
for frame in f.frames:
for channel in frame.channels:
# Check if the channel is 1-dimensional
if channel.dimension[0] == 1:
# Get the data for the channel
data = channel.curves()
# Get the data for the channel
data = channel.curves()
# Add the channel data to the DataFrame as a new column
df[channel.name] = pd.Series(data)
After we have run the above code, we can now view our dataframe ( df
) containing all regularly sampled measurements.
Be aware that you may have multiple sample rates within the same frame, and this should be explored thoroughly before converting.

As this particular dlis file has frames indexed using inches 0.1 inches, we need to multiply our TDEP column by 0.00254 to convert it to metres.
df['TDEP'] = df['TDEP'] * 0.00254
When we view the dataframe after this calculation, we now have our depth column in metric units.

To tidy the dataframe up, we could sort the TDEP column in ascending order so that we go from the shallowest measurement at the top to the deepest measurement at the bottom.
df = df.sort_values(by='TDEP', ascending=True)
Summary
In this article, we have seen how to load dlis files, which are a complex binary format used to store well log data acquired from subsurface exploration. Using the dlisio library from Equinor, we can easily load these files into Python and explore the different components, such as the frames and channels.
Once this data has been loaded, we can easily use pandas to create summary dataframes of the contents of the dlis file and export well logging data from channels to an easier-to-work-with format.
To explore more on how you can work with DLIS files, check out my earlier article:
Dataset Used in this Tutorial
Data from NLOG.nl is free to download and use. Full details of the data licence can be found here, but a summary of the usage is provided here from the Intellectual Property Rights section:
NLOG.NL does not claim any rights (except domain names, trademark rights, patents and other intellectual property rights) in respect of information provided on or through this website. Users are permitted to copy, to download and to disclose in any way, to distribute or to simplify the information provided on this website without the prior written permission of NLOG.NL or the lawful consent of the entitled party. Users are also permitted to copy, duplicate, process or edit the information and/or layout, provided NLOG.NL is quoted as the source.
Thanks for reading. Before you go, you should definitely subscribe to my content and get my articles in your inbox. You can do that here!
Secondly, you can get the full Medium experience and support thousands of other writers and me by signing up for a membership. It only costs you $5 a month, and you have full access to all of the fantastic Medium articles, as well as the chance to make money with your writing.
If you sign up using my link, you will support me directly with a portion of your fee, and it won't cost you more. If you do so, thank you so much for your support.