Log I/O: Java library for fast well log access

The jwitsml.org Log Studio™ research application uses the high quality Log I/O library (logio.jar) from Petroware AS for accessing data from common well log file formats, such as DLIS, LAS2, LAS3, LIS, BIT, ASC, SPWLA, CSV or Excel.

Log I/O utilize high capacity memory mapped non-blocking I/O from Java 8 in order to get maximum performance for very large (GB) files.

Note that virtually all well logging data from the Norwegian continental shelf are QC'ed through the Log Studio™ application causing the library to get extremely well tested.

API Documentation

      Log I/O for Java: Javadoc

      Log I/O for .Net: Doxygen

Videos

File handling
Illustrates the capabilities of Log I/O and how the library is used in Log Studio.
WITSML Upload
Shows how Log I/O is used in Log Studio to load well log content from various sources for upload to WITSML databases.


Programming examples



DLIS

Digital Log Interchange Standard (DLIS) is a digital well log format introduced as Recommended Practice 66 (RP 66) by the American Petroleum Institute in 1991. RP 66 exists in two versions, V1 and V2. V2 is not commonly used. DLIS is a binary data format.

DLIS is an old format in all possible ways. Available DLIS software is limited and to a large degree orphaned technology. The existence of programming tools for DLIS are absent. There is no easily accessible DLIS format description available, dialects exists, and DLIS is in general very hard to digest.

But still, DLIS is the main storage and communication medium for wellbore logging information. Since logging technology has evolved substantially since the introduction of the format, the amount of information contained may be vast; multi-GB volumes are commonplace.

A coding example for reading a DLIS file is shown below. Note that a physical DLIS file consist of a file header and one or more logical DLIS files, each containing a number of sets (meta-data), one or more frames containing curve data, and possibly a set of encrypted records. A frame contains an index curve and a set of measurement curves. Each curve may be single- or multi-dimensional.

     import no.petroware.logio.dlis.*;
     :

     File file = ...;

     // Instantiate a DLIS file reader
     DlisFileReader reader = new DlisFileReader(file);

     // Read logical files. Include bulk data.
     boolean shouldReadBulkData = true;
     List<DlisFile> dlisFiles = reader.readFiles(shouldReadBulkData);

     // Loop over all logical files
     for (DlisFile dlisFile : dlisFiles) {
       System.out.println("File ID: " + dlisFile.getFileId());

       // Access the file header information
       DlisFileHeader fileHeader = dlisFile.getHeader();
       :

       // Loop over all frames
       for (DlisFrame dlisFrame : dlisFile.getFrames()) {

         System.out.println("Frame: " + frame.getName());
         System.out.println("Index type: " + frame.getIndexType());

         // Loop over all curves
         for (DlisCurve curve : frame.getCurves()) {
           System.out.println("Curve name..: " + curve.getName());
           System.out.println("Description.: " + curve.getDescription());
           System.out.println("Unit........: " + curve.getUnit());
           System.out.println("Dimensions..: " + curve.getNDimensions());
           System.out.println("value type..: " + curve.getvalueType());

           // The curve values are accessed by curve.getValue(index)
           // or curve.getValue(dimension, index)
           :
           :
         }
       }
     }
  

The meta-data sets are organized in objects, attributes and values. all easily accessible from the DlisFile instance. Some of the common meta-data can be conveniently accessed using the DlisUtil utility class:

    System.out.println("Well name.....: " + DlisUtil.getWellName(dlisFile));
    System.out.println("Field name....: " + DlisUtil.getFieldName(dlisFile));
    System.out.println("Run number....: " + DlisUtil.getRunNumber(dlisFile));
    System.out.println("Producer name.: " + DlisUtil.getProducerName(dlisFile));
    System.out.println("Country.......: " + DlisUtil.getCountry(dlisFile));
    System.out.println("Start date....: " + DlisUtil.getStartDate(dlisFile));
    System.out.println("Bit size......: " + DlisUtil.getBitSize(dlisFile));
    :
    :
  

Creating DLIS files from scratch includes populating DlisFile instance with sets, frames and curves and writing it to a disk file using the DlisFileWriter class.

The following example illustrates the process:

     import no.petroware.logio.dlis.*;
     :

     // Create an empty DLIS file instance
     DlisFile dlisFile = new DlisFile();

     //
     // Add the mandatory FILE-HEADER set
     //

     // Attributes
     List fileHeaderAttributes = new ArrayList<>();
     fileHeaderAttributes.add(DlisComponent.newAttributeComponent("SEQUENCE-NUMBER", DlisRepresentationCode.ASCII, null));
     fileHeaderAttributes.add(DlisComponent.newAttributeComponent("ID", DlisRepresentationCode.ASCII, null));

     // Object
     DlisComponent fileHeaderObject = DlisComponent.newObjectComponent(0, "0");

     // Values
     List fileHeaderValues = new ArrayList<>();
     fileHeaderValues.add(DlisComponent.newValueComponent("1", DlisRepresentationCode.ASCII, null));
     fileHeaderValues.add(DlisComponent.newValueComponent(logSet.getName(), DlisRepresentationCode.ASCII, null));

     // Create the set and add to the DlisFile
     DlisSet fileHeaderSet = new DlisSet("FILE-HEADER", null, fileHeaderAttributes);
     fileHeaderSet.addObject(fileHeaderObject, fileHeaderValues);
     dlisFile.addSet(fileHeaderSet);

     //
     // Add the mandatory ORIGIN set
     //

     // Attributes
     originAttributes.add(DlisComponent.newAttributeComponent("FILE-ID", DlisRepresentationCode.ASCII, null));
     originAttributes.add(DlisComponent.newAttributeComponent("WELL-NAME", DlisRepresentationCode.ASCII, null));
     originAttributes.add(DlisComponent.newAttributeComponent("FIELD-NAME", DlisRepresentationCode.ASCII, null));
     originAttributes.add(DlisComponent.newAttributeComponent("COMPANY", DlisRepresentationCode.ASCII, null));
     :

     // Object
     DlisComponent originObject = DlisComponent.newObjectComponent(0, "DLIS_DEFINING_ORIGIN");

     // Values
     originValues.add(DlisComponent.newValueComponent("fileId", DlisRepresentationCode.ASCII, null));
     originValues.add(DlisComponent.newValueComponent("25/1-A-4", DlisRepresentationCode.ASCII, null));
     originValues.add(DlisComponent.newValueComponent("Frigg", DlisRepresentationCode.ASCII, null));
     originValues.add(DlisComponent.newValueComponent("Mobil", DlisRepresentationCode.ASCII, null));

     // Create the set and add to the DlisFile
     DlisSet originSet = new DlisSet("ORIGIN", null, originAttributes);
     originSet.addObject(originObject, originValues);
     dlisFile.addSet(originSet);

     //
     // Add more sets here including the mandatory CHANNEL and FRAME sets
     //
     :
     :


     //
     // Create frame(s) with curve data
     //
     DlisFrame frame = new DlisFrame();
     dlisFile.addFrame(frame);

     DlisCurve curve1 = new DlisCurve("MD", "m", "Measured depth", DlisRepresentationCode.FDOUBL, 1);
     curve1.addValue(1450.0);
     curve1.addValue(1450.5);
     curve1.addValue(1451.0);
     :
     frame.addCurve(curve1);

     DlisCurve curve2 = new DlisCurve("GR", "API", "Gamma ray", DlisRepresentationCode.FDOUBL, 1);
     curve2.addValue(46.89);
     curve2.addValue(30.65);
     curve2.addValue(43.02);
     :
     frame.addCurve(curve2);

     //
     // Write to disk file
     //
     DlisFileWriter writer = new DlisFileWriter(new File(...));
     writer.write(dlisFile);
  

In addition to reading and writing DLIS files, the Log I/O API may be used to convert between DLIS and other log file formats.

LIS

Log Interchange Standard (LIS) is the predecessor to DLIS and was developed by Schlumberger in the late 1970s.

Like DLIS, LIS is a binary format. It it is based on the VAX binary information standard and has an even more awkward syntax than DLIS.

But still, LIS files are still being produced and immense volumes of historical logging information exists in this format. Log I/O is a convenient platform for being able to manage and maintain this information.

A physical LIS file consists of one or more logical LIS files, each containing a set of records (meta-data) of different types as well as an index curve and a set of measurement curves. Each curve may be single- or multi-dimensional.

The code example below indicates the few simple steps necessary for accessing a LIS file:

     import no.petroware.logio.lis.*;
     :

     File file = ...;

     // Instantiate a LIS file reader
     LisFileReader reader = new LisFileReader(file);

     // Read logical files. Include bulk data.
     boolean shouldReadBulkData = true;
     List<LisFile> lisFiles = reader.readFiles(shouldReadBulkData);

     // Loop over all logical files
     for (LisFile lisFile : lisFiles) {
       System.out.println("File name: " + lisFile.getName());

       // Loop over all non-data records of the file
       for (LisRecord lisRecord : lisFile.getRecords()) {
         :
       }

       // Loop over all curves
       for (LisCurve curve : lisFile.getCurves()) {
         System.out.println("Curve name..: " + curve.getName());
         System.out.println("Description.: " + curve.getDescription());
         System.out.println("Unit........: " + curve.getUnit());
         System.out.println("Dimensions..: " + curve.getNDimensions());
         System.out.println("Value type..: " + curve.getvalueType());

         // The curve values are accessed by curve.getValue(index)
         // or curve.getValue(dimension, index)
         :
         :
       }
     }
  

In addition to curve data, a LIS file contains logging meta-data. This information is organized in records of different types accessible through the LisFile instance. Some of the common meta-data can be conveniently accessed using the LisUtil utility class:

    System.out.println("Well name........: " + LisUtil.getWellName(lisFile));
    System.out.println("Field name.......: " + LisUtil.getFieldName(lisFile));
    System.out.println("Run number.......: " + LisUtil.getRunNumber(lisFile));
    System.out.println("Company..........: " + LisUtil.getCompany(lisFile));
    System.out.println("Service company..: " + LisUtil.getServiceCompany(lisFile));
    System.out.println("Country..........: " + LisUtil.getCountry(lisFile));
    System.out.println("Rig name.........: " + LisUtil.getRigName(lisFile));
    System.out.println("Date.............: " + LisUtil.getDate(lisFile));
    System.out.println("Bit size.........: " + LisUtil.getBitSize(lisFile));
    :
    :
  


LAS

The Log ASCII Standard (LAS) was created by the Canadian Well Logging Society (CWLS) in the late 1980s.

LAS popuplarity is due to its simple syntax and the fact that it contains human readable ASCII text. Consequently it is easier to work with than the black-box DLIS files. The ASCII format has a price however; It requires a lot more storage space than equivalent DLIS files, so LAS is not useful for very large log volumes. Also, the easily accessible text format combined with an ambiguous format description has caused many LAS dialects and semantic interpretations over the years.

Three different versions of LAS exists, 1.2, 2.0 and 3.0. Current version is 3.0, published in 2000, but version 2.0 is by far the most common. Log I/O supports all LAS versions, as well as converting between them. Note that LAS does not support multi-frame nor multi-dimensional curves like DLIS.

The code example below illustrates the simple approach for accessing a LAS file using Log I/O:

     import no.petroware.logio.las.*;
     :

     File file = ...;

     // Instantiate a reader and read the LAS file
     LasFileReader reader = new LasFileReader(file);
     LasFile lasFile = reader.readFile();

     // Loop over all curves
     for (LasCurve curve : lasFile.getCurves()) {
       System.out.println("Curve name..: " + curve.getName());
       System.out.println("Description.: " + curve.getDescription());
       System.out.println("Unit........: " + curve.getUnit());
       System.out.println("value type..: " + curve.getValueType());

       // The curve values are accessed by curve.getValue(index)
       :
       :
     }

  

As for DLIS, a LAS file contains logging meta-data. This information is organized in sections and parameters which are easily accessed from the LasFile instance. Some of the common meta-data can be conveniently accessed through the LasUtil class:

     System.out.println("Well name..: " + LasUtil.getWellName(lasFile));
     System.out.println("Run number.: " + LasUtil.getRunNumber(lasFile));
     System.out.println("Date.......: " + LasUtil.getDate(lasFile));
     System.out.println("Country....: " + LasUtil.getCountry(lasFile));
     System.out.println("MD.........: " + LasUtil.getMd(lasFile));
     :
     :
  

Converting from DLIS to LAS is done on a DLIS frame by frame basis using the DlisToLasConverter class:

     import no.petroware.logio.dlis.*;
     import no.petroware.logio.las.*;
     :

     // Identify the input file containing DLIS
     File sourceFile = ...;

     // Read the DLIS file
     DlisFileReader reader = new DlisFileReader(sourceFile);
     List<DlisFile> dlisFiles = reader.readFiles(true);

     // Pick the first logical file and its first frame
     DlisFile dlisFile = dlisFiles.get(0);
     DlisFrame dlisFrame = dlisFile.getFrames().get(0);

     // Convert to LAS
     LasFile lasFile = DlisToLasConverter.convert(dlisFile, dlisFrame);

     // Create an empty destination file and write LAS
     File = destinationFile = ...;
     LasFileWriter.write(destinationFile, lasFile);
  
Log I/O also contains a rich set of features for validating LAS files.

BIT

The Basic Information Tape (BIT) is a binary well log format created by Dresser Atlas in in the 1970's. Each physical BIT disk file can contain one or more logical BIT files. Each logical file is composed by a simple General Heading record followed by a number of Data records holding data for a maximum of 20 curves (not including the index channel of depth or time). All curve data is 4-byte floating point in the IBM System/360 representation.

The BIT format is no longer in common use, but vast amounts of historic logging data still exists in this format. The format is quite simple, but no public description of it is available.

The code example below indicates the few simple steps necessary for accessing a BIT file using the Log I/O library:

     import no.petroware.logio.bit.*;
     :

     File file = ...;

     // Instantiate a BIT file reader
     BitFileReader reader = new BitFileReader(file);

     // Read logical files. Include bulk data.
     boolean shouldReadBulkData = true;
     List<BitFile> bitFiles = reader.readFiles(shouldReadBulkData);

     // Loop over all logical files
     for (BitFile bitFile : bitFiles) {
       System.out.println("File name: " + bitFile.getName());

       // Get file header containing logging meta-data
       LisGeneralHeadingRecord header = bitFile.getHeader();
       System.out.println("Company..: " + header.getCompany());
       System.out.println("Well.....: " + header.getWellName());
       :
       :

       // Loop over all curves
       for (BitCurve curve : bitFile.getCurves()) {
         System.out.println("Curve name..: " + curve.getName());
         System.out.println("Unit........: " + curve.getUnit());

         // List all values
         for (int index = 0 : index < curve.getNValues()) {
           System.out.println(curve.getValue(index));
       }
     }
  


SPWLA

SPWLA is a format for core log data. It was developed by the Aberdeen Well Log Analysis Society (a chapter of the Society of Petrophysics and Well Log Analysts) in 1985.

SPWLA files are text based and coded as ASCII or EBCDIC (IBM 500).

An SPWLA file consist of a set of measurements for a predefined set of properties associated with cores and plugs along a borehole.

     import no.petroware.logio.spwla.*;
     :

     File file = ...;

     // Instantiate a LIS file reader
     SpwlaFileReader reader = new SpwlaFileReader(file);

     // Read file content.
     SpwlaFile spwlaFile = reader.read();

     System.out.println("Title: " + spwlaFile.getTitle());

     // Get well header meta-data.
     SpwlaWellHeader wellHeader = spwlaFile.getWellHeader();
     System.out.println("Well name..: " + wellHeader.getWellName());
     System.out.println("Field......: " + wellHeader.getField());
     System.out.println("Country....: " + wellHeader.getCountry());
     :

     // Loop over all curves
     for (SpwlaCurve curve : spwlaFile.getCurves()) {
       System.out.println("Curve name..: " + curve.getName());
       System.out.println("Description.: " + curve.getDescription());
       System.out.println("Unit........: " + curve.getUnit());
       System.out.println("value type..: " + curve.getvalueType());

       // The curve values are accessed by curve.getValue(index)
       :
       :
     }
  


ASC

ASC is a collective term used in the industry for denoting any ASCII based file that may contain well log information.

The Log I/O ASC reader uses advanced pattern recognising technology in order to automatically digest the vast number of different inputs it may be passed. It will handle column based, token based or delimiter (CSV) based bulk input through a best effort approach, and it also handles provided header information. The ASC reader may be used to read any spreadsheet files saved as CSV.

The associated ASC writer may produce pretty printed column based or CSV output as well as condensed CSV output if required.

The code example below illustrates the simple approach for accessing an ASC file using Log I/O:

     import no.petroware.logio.asc.*;
     :

     File file = ...;

     // Instantiate a reader and read the ASC file
     AscFileReader reader = new AscFileReader(file);
     AscFile ascFile = reader.read();

     // Loop over all meta data
     for (String metaDataKey : ascFile.getMetaData()) {
       System.out.println(metaDataKey + " = " + ascFile.getMetaData(metaDataKey));

     // Loop over all curves
     for (AscCurve curve : ascFile.getCurves()) {
       System.out.println("Curve name..: " + curve.getName());
       System.out.println("Description.: " + curve.getDescription());
       System.out.println("Unit........: " + curve.getUnit());
       System.out.println("value type..: " + curve.getvalueType());

       // The curve values are accessed by curve.getValue(index)
       :
       :
     }
  


Log conversion service

In need for a log file conversion service?

Through Log I/O, Petroware AS provides conversions between any of the logging formats listed above as well as WITSML or even proprietary formats and ER-databases. Conversions are performed through fast bulk operations or through custom client controlled processes. Please contact Petroware AS for more information.

Contact

Petroware AS does not currently have the resources to take on licensing of the Log I/O library, but it may still be available on request.

For more information, please contact: