Last updated

LAS Support

This tutorial demonstrates how to:

  • Parse a local LAS3.0 (or LAS2.0) file, then put its sections data to DataTable-s;

  • Display the sections data read as DataTableView-s;

  • Write the tables' data back to LAS3.0 (or LAS2.0) file. Note that when a LAS3.0 file previously opened is written back as LAS2.0 file then some data sections are going to be lost due to LAS2.0-format limitations.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { HttpClient } from "@int/geotoolkit/http/HttpClient.ts";
import { LineReader } from "@int/geotoolkit/util/stream/LineReader.ts";
import { BrowserFileStream } from "@int/geotoolkit/util/stream/BrowserFileStream.ts";
import { Las20Stream } from "@int/geotoolkit/las/Las20Stream.ts";
import { DataTable } from "@int/geotoolkit/data/DataTable.ts";
import { DataSeries } from "@int/geotoolkit/data/DataSeries.ts";
import { NumericalDataSeries } from "@int/geotoolkit/data/NumericalDataSeries.ts";
import { LasSectionGroup } from "@int/geotoolkit/las/LasSectionGroup.ts";
import { Las30Writer } from "@int/geotoolkit/las/Las30Writer.ts";
import { Las20Writer } from "@int/geotoolkit/las/Las20Writer.ts";
import { StringStream } from "@int/geotoolkit/util/stream/StringStream.ts";
import { LasWellSection } from "@int/geotoolkit/las/LasWellSection.ts";
import { LasVersionSection } from "@int/geotoolkit/las/LasVersionSection.ts";
import { log } from "@int/geotoolkit/base.js";
import { LasParser } from "@int/geotoolkit/las/LasParser.ts";
import { TableView } from "@int/geotoolkit/widgets/TableView.ts";
import { DataTableAdapter } from "@int/geotoolkit/widgets/data/DataTableAdapter.ts";
import { LasParameterSection } from "@int/geotoolkit/las/LasParameterSection.ts";
import { LasDataSection } from "@int/geotoolkit/las/LasDataSection.ts";
import { Las30Consts } from "@int/geotoolkit/las/Las30Consts.ts";
import { ParserFactory } from "@int/geotoolkit/welllog/data/las/ParserFactory.ts";
const http = HttpClient.getInstance().getHttp();
let delimiterName, delimiterDescription;
let dataTables = [];
let plots = [];
let tableParentDivs = [];
let asciiSectionGroupName = null;
function emptyParameterSection(parameterSection) {
  return !parameterSection || !parameterSection.getData() || parameterSection.getData().length < 1;
}
function tableToParameterSection(table, parameterSection, uniqueMnemonics) {
  const nRows = table.getNumberOfRows();
  if (nRows < 1) {
    log("Table " + table.getName() + ": NO rows found");
    return;
  }
  if (table.getRow(0).length !== 4) {
    log("Table " + table.getName() + ": row length == " + table.getRow(0).length + " vs. expected 4");
    return;
  }
  const meta = table.getMetaData();
  const comments = meta && meta["comments"] ? meta["comments"] : null;
  if (comments && !comments.empty()) {
    for (let i = comments.getMinPosition(); i <= comments.getMaxPosition(); ++i) {
      const strComment = comments.getComment(i);
      if (strComment != null) {
        parameterSection.addComment(i, strComment);
      }
    }
  }
  for (let i = 0; i < nRows; ++i) {
    const row = table.getRow(i);
    if (row.length === 4) {
      const mnemonic = row[0];
      parameterSection.setParameter(
        mnemonic,
        row[1],
        row[2],
        row[3],
        uniqueMnemonics != null && uniqueMnemonics.indexOf(mnemonic) > -1 ? false : true
      );
    }
  }
}
function tableToDataSection(dataTable, dataSection) {
  const sectionData = [];
  for (let i = 0; i < dataTable.getNumberOfColumns(); i++) {
    const column = dataTable.getColumn(i);
    const columnData = column.toArray(true);
    sectionData.push(columnData);
  }
  dataSection.setData(sectionData);
}
function onFileOpen(evt, canvasesParent, fileInfo) {
  evt.stopPropagation();
  evt.preventDefault();
  const files = evt.target.files;
  return handleFileSelect(files, canvasesParent, fileInfo);
}
function isAsciiSectionName(name) {
  name = name.toLowerCase();
  if (LasParser.isDataMainSectionName(name) || name === "las2" || name === "main section" || name === "log" || name.startsWith("curve_data") || name.startsWith("log_data")) {
    return true;
  }
  return false;
}
function getAsciiSectionGroup(sections) {
  for (let i = 0; i < sections.length; ++i) {
    if (isAsciiSectionName(sections[i].getName())) {
      return sections[i];
    }
  }
  return null;
}
function createLAS20Writer() {
  const res = dataTables.filter((t) => isAsciiSectionName(t.getName()));
  if (!res || res.length < 1) {
    return null;
  }
  const table = res[0];
  const metaData = table.getMetaData();
  const indexDataSeries = metaData["index"] ? table.getColumnByName(metaData["index"]) : table.getColumn(0);
  const lasWriter = new Las20Writer(indexDataSeries);
  return lasWriter;
}
function createLAS30Writer() {
  const lasWriter = new Las30Writer();
  lasWriter.setDataValuesDelimiter(
    delimiterName,
    delimiterDescription
  );
  return lasWriter;
}
function dataToLASWriter(lasWriterVersion) {
  const lasWriter = lasWriterVersion === "2.0" ? createLAS20Writer() : createLAS30Writer();
  if (!lasWriter) {
    return null;
  }
  let lasDataVersion;
  let write30dataTo20file;
  const sectionGroupsInfos = {};
  for (let i = 0; i < dataTables.length; ++i) {
    const dataTable = dataTables[i];
    const name = dataTable.getName().trim().toUpperCase();
    if (LasParser.isVersionSectionName(name)) {
      const versionSection = new LasVersionSection();
      tableToParameterSection(dataTable, versionSection);
      lasDataVersion = versionSection.getParameter(Las30Consts.MNEMONIC_VERSION).getValue();
      write30dataTo20file = lasWriterVersion === "2.0" && lasDataVersion === "3.0";
      if (lasDataVersion !== lasWriterVersion) {
        continue;
      }
      lasWriter.setVersionSection(versionSection);
    } else if (LasParser.isWellSectionName(name)) {
      const wellSection = new LasWellSection();
      tableToParameterSection(dataTable, wellSection, [
        Las30Consts.MNEMONIC_START,
        Las30Consts.MNEMONIC_STOP,
        Las30Consts.MNEMONIC_STEP,
        Las30Consts.MNEMONIC_NULL
      ]);
      lasWriter.setWellSection(wellSection);
    } else {
      const sectionGroupName = dataTable.getMetaData()["sectionGroupName"];
      if (write30dataTo20file && sectionGroupName !== asciiSectionGroupName) {
        continue;
      }
      if (name.indexOf("ASCII") === 0 || name.split("_").length > 1 && name.split("_")[1].indexOf("DATA") !== -1 || name.split("|").length > 1 && name.split("|")[1].indexOf("DEFINITION") !== -1) {
        const dataSection = new LasDataSection({
          "name": write30dataTo20file ? "ASCII" : dataTable.getName()
        });
        tableToDataSection(dataTable, dataSection);
        if (sectionGroupsInfos[sectionGroupName] === void 0) {
          sectionGroupsInfos[sectionGroupName] = {};
        }
        sectionGroupsInfos[sectionGroupName]["data"] = dataSection;
        if (lasWriterVersion === "2.0") {
          break;
        }
      } else if (name.indexOf("PARAMETER") === 0 || name.split("_").length > 1 && name.split("_")[1].indexOf("PARAMETER") !== -1) {
        const parameterSection = new LasParameterSection({
          "name": write30dataTo20file ? "PARAMETER" : dataTable.getName()
        });
        tableToParameterSection(dataTable, parameterSection);
        if (sectionGroupsInfos[sectionGroupName] === void 0) {
          sectionGroupsInfos[sectionGroupName] = {};
        }
        sectionGroupsInfos[sectionGroupName]["parameter"] = parameterSection;
      } else if (name.indexOf("CURVE") === 0 || name.split("_").length > 1 && name.split("_")[1].indexOf("DEFINITION") !== -1) {
        const parameterSection = new LasParameterSection({
          "name": write30dataTo20file ? "CURVE" : dataTable.getName()
        });
        tableToParameterSection(dataTable, parameterSection);
        if (sectionGroupsInfos[sectionGroupName] === void 0) {
          sectionGroupsInfos[sectionGroupName] = {};
        }
        sectionGroupsInfos[sectionGroupName]["definition"] = parameterSection;
      } else {
        log("Unrecognized Section Type: " + dataTable.getName());
      }
    }
  }
  for (const name in sectionGroupsInfos) {
    if (sectionGroupsInfos.hasOwnProperty(name)) {
      const info = sectionGroupsInfos[name];
      const sectionGroup = new LasSectionGroup(
        name,
        info["parameter"],
        info["definition"],
        info["data"]
      );
      if (lasWriter instanceof Las30Writer) {
        lasWriter.setDataSectionGroup(sectionGroup);
      } else if (lasWriter instanceof Las20Writer) {
        lasWriter.setDataSectionGroup(sectionGroup);
      }
    }
  }
  return lasWriter;
}
function onFileSave(lasWriterVersion) {
  if (!dataTables || dataTables.length === 0) {
    log("No data loaded to save");
    return;
  }
  if (lasWriterVersion !== "2.0" && lasWriterVersion !== "3.0") {
    log("Unsupported LAS-version: " + lasWriterVersion);
    return;
  }
  const lasWriter = dataToLASWriter(lasWriterVersion);
  if (!lasWriter) {
    log("Writer NOT created for LAS-version: " + lasWriterVersion);
    return;
  }
  const stream = new StringStream().setSaveOptions({
    "type": "text/plain",
    "popupblockedmessage": "Popup-blocker blocked export window."
  });
  lasWriter.save(stream);
  stream.close().save("saved_as_" + lasWriterVersion + ".las", true);
}
function onFileDrop(evt, canvasesParent, fileInfo) {
  evt.stopPropagation();
  evt.preventDefault();
  const files = evt.dataTransfer.files;
  evt.dataTransfer.dropEffect = "copy";
  return handleFileSelect(files, canvasesParent, fileInfo);
}
function loadFile(fileName, canvasesParent, fileInfo) {
  http.get(fileName, {
    "responsetype": "blob"
  }).then((response) => {
    handleFileSelect([new File([response.data], fileName)], canvasesParent, fileInfo);
  });
}
function getParameterSectionByName(sections, name) {
  for (let i = 0; i < sections.length; ++i) {
    if (sections[i].getName().toLowerCase().indexOf(name.toLowerCase()) >= 0) {
      return sections[i];
    }
  }
  return null;
}
function loadWellOrVersionSectionTable(section) {
  const name = section.getName().trim().toUpperCase();
  const table = new DataTable({
    "name": name
  });
  const parameters = section.getData();
  const mnemonics = [];
  const units = [];
  const values = [];
  const descriptions = [];
  for (let i = 0; i < parameters.length; ++i) {
    const parameter = parameters[i];
    mnemonics.push(parameter.getMnemonic());
    units.push(parameter.getUnit());
    values.push(parameter.getValue());
    descriptions.push(parameter.getDescription());
  }
  table.addColumn(new DataSeries({
    "id": "mnemonic",
    "name": "mnemonic",
    "data": mnemonics
  }));
  table.addColumn(new DataSeries({
    "id": "unit",
    "name": "unit",
    "data": units
  }));
  table.addColumn(new DataSeries({
    "id": "value",
    "name": "value",
    "data": values
  }));
  table.addColumn(new DataSeries({
    "id": "description",
    "name": "description",
    "data": descriptions
  }));
  return table;
}
function loadParameterSectionTable(parameterSection) {
  const table = new DataTable({ "name": parameterSection.getName() });
  const parameters = parameterSection.getData();
  const mnemonics = [];
  const units = [];
  const values = [];
  const descriptions = [];
  for (let i = 0; i < parameters.length; ++i) {
    const parameter = parameters[i];
    mnemonics.push(parameter.getMnemonic());
    units.push(parameter.getUnit());
    values.push(parameter.getValue());
    descriptions.push(parameter.getDescription());
  }
  table.addColumn(new DataSeries({
    "id": "mnemonic",
    "name": "mnemonic",
    "data": mnemonics
  }));
  table.addColumn(new DataSeries({
    "id": "unit",
    "name": "unit",
    "data": units
  }));
  table.addColumn(new DataSeries({
    "id": "value",
    "name": "value",
    "data": values
  }));
  table.addColumn(new DataSeries({
    "id": "description",
    "name": "description",
    "data": descriptions
  }));
  return table;
}
function loadDataSectionTable(sectionGroup) {
  const dataSection = sectionGroup.getSections()["data"];
  const table = new DataTable({ "name": dataSection.getName() });
  const curveNames = sectionGroup.getCurveMnemonics();
  for (let i = 0; i < curveNames.length; ++i) {
    const data = sectionGroup.getCurveData(i);
    const info = sectionGroup.getCurveInfo(i);
    let curve;
    if (sectionGroup.isCurveNumeric(i)) {
      curve = new NumericalDataSeries({
        "name": info.getMnemonic(),
        "data": data,
        "id": info.getMnemonic(),
        "unit": info.getUnit()
      });
    } else {
      const strData = [];
      data.forEach((e) => {
        strData.push(e.toString());
      });
      curve = new DataSeries({
        "name": info.getMnemonic(),
        "data": strData,
        "id": info.getMnemonic(),
        "unit": info.getUnit()
      });
    }
    table.addColumn(curve);
  }
  return table;
}
function legacyParse(file, resolve, reject) {
  const reader = new FileReader();
  reader.onload = function(e) {
    const parser = ParserFactory.getParser(e.target.result, false);
    if (parser == null) {
      reject("unknown file format");
      return;
    }
    parser.parse(e.target.result);
    const sections = parser.getSections();
    const versionSection = getParameterSectionByName(sections, "VERSION");
    if (versionSection == null) {
      reject("VERSION data NOT found");
      return;
    }
    const wellSection = getParameterSectionByName(sections, "WELL");
    if (wellSection == null) {
      reject("WELL data not found");
      return;
    }
    const sectionGroups = parser.getSectionGroups();
    const asciiSectionGroup = getAsciiSectionGroup(sectionGroups);
    if (asciiSectionGroup == null) {
      asciiSectionGroupName = null;
      reject("No ASCII-section data is found");
      return;
    }
    asciiSectionGroupName = asciiSectionGroup.getName();
    for (let is = 0; is < sections.length; ++is) {
      const tableS = loadWellOrVersionSectionTable(sections[is]);
      tableS.setMetaData({ "comments": sections[is].getComments() });
      resolve(tableS);
      dataTables.push(tableS);
    }
    for (let isg = 0; isg < sectionGroups.length; ++isg) {
      const sectionGroup = sectionGroups[isg];
      const parameters = sectionGroup.getSections()["parameters"];
      if (!emptyParameterSection(parameters)) {
        const tablePars = loadParameterSectionTable(parameters);
        tablePars.setMetaData({
          "sectionGroupName": sectionGroup.getName(),
          "comments": parameters.getComments()
        });
        resolve(tablePars);
        dataTables.push(tablePars);
      }
      const definition = sectionGroup.getSections()["curves"];
      if (!emptyParameterSection(definition)) {
        const tableDefs = loadParameterSectionTable(definition);
        tableDefs.setMetaData({
          "sectionGroupName": sectionGroup.getName(),
          "comments": definition.getComments()
        });
        resolve(tableDefs);
        dataTables.push(tableDefs);
      }
      const tableData = loadDataSectionTable(sectionGroup);
      tableData.setMetaData({
        "sectionGroupName": sectionGroup.getName()
      });
      resolve(tableData);
      dataTables.push(tableData);
    }
    const parameterDLM = versionSection.getParameter(Las30Consts.MNEMONIC_DATA_VALUES_DELIMITER);
    if (parameterDLM != null) {
      const v = parameterDLM.getValue();
      delimiterName = v != null && v.length > 0 ? v : Las30Consts.DATA_VALUES_DELIMITER_NAME_SPACE;
      delimiterDescription = parameterDLM.getDescription();
    } else {
      delimiterName = Las30Consts.DATA_VALUES_DELIMITER_NAME_SPACE;
    }
  };
  reader.readAsText(file);
}
function visualizeTables(dataTables2, canvasesParent) {
  for (let i = 0; i < dataTables2.length; ++i) {
    const dataTable = dataTables2[i];
    const tableParentDiv = document.createElement("div");
    tableParentDiv.style.height = "200px";
    tableParentDiv.style.color = "red";
    const tableName = document.createElement("textarea");
    tableName.value = dataTable.getName();
    tableName.style.backgroundColor = "lightgray";
    tableName.style.borderRadius = "6px";
    tableName.style.borderWidth = "1px";
    tableName.style.position = "absolute";
    tableName.style.height = "20px";
    tableName.style.width = "100%";
    tableParentDiv.appendChild(tableName);
    const tableCanvas = document.createElement("canvas");
    tableCanvas.style.height = "180px";
    tableCanvas.style.width = "100%";
    tableCanvas.style.backgroundColor = "yellow";
    tableParentDiv.appendChild(tableCanvas);
    canvasesParent.appendChild(tableParentDiv);
    const tableAdapter = new DataTableAdapter({
      "datatable": dataTable
    });
    const tableViewWidget = new TableView({
      "border": {
        "color": "lightgray",
        "pixelsnapmode": true
      },
      "fitborder": true,
      "horizontalscroll": "floating",
      "verticalscroll": "floating"
    }).setData(tableAdapter);
    plots.push(new Plot({
      "canvaselement": tableCanvas,
      "root": tableViewWidget
    }));
    tableParentDivs.push(tableParentDiv);
    tableViewWidget.fitToWidth(false);
  }
}
function clear(canvasesParent) {
  dataTables.forEach((dataTables2) => {
    dataTables2.dispose();
  });
  dataTables = [];
  plots.forEach((plot) => {
    plot.dispose(true);
  });
  plots = [];
  if (canvasesParent != null) {
    for (let i = 0; i < tableParentDivs.length; ++i) {
      canvasesParent.removeChild(tableParentDivs[i]);
    }
  }
  tableParentDivs = [];
}
function handleFileSelect(files, canvasesParent, fileInfo) {
  let output = "";
  if (files.length > 0) {
    clear(canvasesParent);
    fileInfo.text = "";
    const file = files[0];
    const lineReader = new LineReader({
      "stream": new BrowserFileStream({
        "file": file
      })
    });
    new Promise((resolve, reject) => {
      Las20Stream.isLAS20(lineReader).then((result) => {
        legacyParse(file, resolve, reject);
        output = file.name;
        output += result["isLAS20"] ? " [LAS20]" : " [LAS30]";
        fileInfo.text = output;
      }).catch((result) => reject(result));
    }).then(() => {
      visualizeTables(dataTables, canvasesParent);
    });
  }
}
export { clear, loadFile, onFileDrop, onFileOpen, onFileSave };

createScene();