log2frame 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {log2frame-0.2.2/src/log2frame.egg-info → log2frame-0.2.3}/PKG-INFO +7 -1
- {log2frame-0.2.2 → log2frame-0.2.3}/README.md +6 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/pyproject.toml +1 -1
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/__init__.py +77 -9
- log2frame-0.2.3/src/log2frame/dictionaries/units.py +69 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/dlis.py +16 -12
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/las.py +13 -10
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/lis.py +69 -10
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/log.py +151 -5
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/pack.py +218 -7
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/rft.py +146 -2
- log2frame-0.2.3/src/log2frame/writer.py +192 -0
- {log2frame-0.2.2 → log2frame-0.2.3/src/log2frame.egg-info}/PKG-INFO +7 -1
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame.egg-info/SOURCES.txt +3 -2
- {log2frame-0.2.2 → log2frame-0.2.3}/test/test_readers.py +1 -2
- log2frame-0.2.3/test/test_writer.py +215 -0
- log2frame-0.2.2/src/log2frame/debug.py +0 -5
- log2frame-0.2.2/src/log2frame/dictionaries/units.py +0 -37
- {log2frame-0.2.2 → log2frame-0.2.3}/LICENSE +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/setup.cfg +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/dictionaries/__init__.py +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame/dictionaries/units_dictionary.json +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame.egg-info/dependency_links.txt +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame.egg-info/requires.txt +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/src/log2frame.egg-info/top_level.txt +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/test/test_log.py +0 -0
- {log2frame-0.2.2 → log2frame-0.2.3}/test/test_pack.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: log2frame
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A function to facilitate loading well log data, in las or dlis format, as dataframe.
|
|
5
5
|
Author-email: Martin Carlos Araya <martinaraya@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -63,6 +63,12 @@ When `simpandas` is installed, `log2frame` can preserve curve units and index un
|
|
|
63
63
|
# to read log files
|
|
64
64
|
Simply call the function `read()` with the path or path pattern as argument:
|
|
65
65
|
|
|
66
|
+
# to export / write LAS files
|
|
67
|
+
Use `write_las()` to export a `Log` back to a LAS file:
|
|
68
|
+
- `log2frame.write_las( log, path_to_file )` — writes LAS 2.0 by default
|
|
69
|
+
- `log2frame.write_las( log, path_to_file, version=1.2 )` — LAS 1.2
|
|
70
|
+
- `log.to_las( path_to_file )` — equivalent convenience method on `Log`
|
|
71
|
+
|
|
66
72
|
## a single log file
|
|
67
73
|
To load a single _.las_, _.lis_ or _.dlis_ file. The function will return a `Log` instance containing the data:
|
|
68
74
|
- `log2frame.read( path_to_file )`
|
|
@@ -16,6 +16,12 @@ When `simpandas` is installed, `log2frame` can preserve curve units and index un
|
|
|
16
16
|
# to read log files
|
|
17
17
|
Simply call the function `read()` with the path or path pattern as argument:
|
|
18
18
|
|
|
19
|
+
# to export / write LAS files
|
|
20
|
+
Use `write_las()` to export a `Log` back to a LAS file:
|
|
21
|
+
- `log2frame.write_las( log, path_to_file )` — writes LAS 2.0 by default
|
|
22
|
+
- `log2frame.write_las( log, path_to_file, version=1.2 )` — LAS 1.2
|
|
23
|
+
- `log.to_las( path_to_file )` — equivalent convenience method on `Log`
|
|
24
|
+
|
|
19
25
|
## a single log file
|
|
20
26
|
To load a single _.las_, _.lis_ or _.dlis_ file. The function will return a `Log` instance containing the data:
|
|
21
27
|
- `log2frame.read( path_to_file )`
|
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
|
|
2
|
+
"""log2frame — well-log data reader and writer.
|
|
3
|
+
|
|
4
|
+
This package reads well-log files in LAS, DLIS, and LIS formats and
|
|
5
|
+
returns the curve data as unit-aware :class:`Log` (single file) or
|
|
6
|
+
:class:`Pack` (multiple files) containers built on top of
|
|
7
|
+
:class:`pandas.DataFrame` (or :class:`simpandas.SimDataFrame` when the
|
|
8
|
+
optional ``simpandas`` package is installed).
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
The package also provides :func:`write_las` to export any :class:`Log`
|
|
11
|
+
back to a LAS 1.2 / 2.0 file.
|
|
12
|
+
|
|
13
|
+
Public API
|
|
14
|
+
----------
|
|
15
|
+
read(path, ...) Read one or many log files.
|
|
16
|
+
write_las(log, path) Write a Log to a LAS file.
|
|
17
|
+
concat(logs) Concatenate a list of Log objects into a single DataFrame.
|
|
6
18
|
"""
|
|
19
|
+
# Created on Thu Jan 19 19:01:21 2023
|
|
20
|
+
# @author: Martín Carlos Araya <martinaraya@gmail.com>
|
|
7
21
|
from .las import las2frame
|
|
8
22
|
from .dlis import dlis2frame
|
|
9
23
|
from .lis import lis2frame
|
|
10
24
|
from .pack import Pack, concat
|
|
11
25
|
from .log import Log
|
|
26
|
+
from .writer import write_las
|
|
12
27
|
import glob
|
|
13
28
|
import os.path
|
|
14
29
|
import logging
|
|
@@ -17,12 +32,26 @@ from .rft import *
|
|
|
17
32
|
for name in ("lasio", "lasio.reader", "lasio.las", "unyts"):
|
|
18
33
|
logging.getLogger(name).setLevel(logging.WARNING)
|
|
19
34
|
|
|
20
|
-
__version__ = '0.2.
|
|
21
|
-
__release__ =
|
|
22
|
-
__all__ = ['read', 'concat']
|
|
35
|
+
__version__ = '0.2.3'
|
|
36
|
+
__release__ = 20260503
|
|
37
|
+
__all__ = ['read', 'concat', 'write_las']
|
|
23
38
|
|
|
24
39
|
|
|
25
40
|
class _Log2FrameParams(object):
|
|
41
|
+
"""Package-level singleton holding runtime configuration flags.
|
|
42
|
+
|
|
43
|
+
Attributes
|
|
44
|
+
----------
|
|
45
|
+
simpandas_ : bool
|
|
46
|
+
``True`` when the optional ``simpandas`` package is importable.
|
|
47
|
+
Used by all readers to decide whether to return a
|
|
48
|
+
:class:`simpandas.SimDataFrame` or a plain
|
|
49
|
+
:class:`pandas.DataFrame`.
|
|
50
|
+
raise_error_ : bool
|
|
51
|
+
Default value for the *raise_error* parameter of :func:`read`.
|
|
52
|
+
Set to ``True`` to propagate parse errors; ``False`` silently
|
|
53
|
+
skips unreadable files.
|
|
54
|
+
"""
|
|
26
55
|
def __init__(self):
|
|
27
56
|
try:
|
|
28
57
|
import simpandas as spd
|
|
@@ -36,6 +65,23 @@ _params_ = _Log2FrameParams()
|
|
|
36
65
|
|
|
37
66
|
|
|
38
67
|
def _read_one(path: str, raise_error=True, use_simpandas=None, correct_units=True):
|
|
68
|
+
"""Dispatch a single file path to the appropriate format reader.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
path : str
|
|
73
|
+
Path to a ``.las``, ``.dlis``, or ``.lis`` / ``.lti`` file.
|
|
74
|
+
raise_error : bool, default True
|
|
75
|
+
Whether to propagate parse errors or return ``None``.
|
|
76
|
+
use_simpandas : bool | None, default None
|
|
77
|
+
Passed through to the format-specific reader.
|
|
78
|
+
correct_units : bool, default True
|
|
79
|
+
Passed through to the format-specific reader.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
Log | None
|
|
84
|
+
"""
|
|
39
85
|
if use_simpandas is not None and use_simpandas is True and not _params_.simpandas_:
|
|
40
86
|
raise ModuleNotFoundError("SimPandas is not installed, please install it or set parameter `use_simpandas` to False.")
|
|
41
87
|
use_simpandas = _params_.simpandas_ if use_simpandas is None else bool(use_simpandas)
|
|
@@ -66,14 +112,36 @@ def read(path: str, recursive=True, raise_error=False, squeeze=True, use_simpand
|
|
|
66
112
|
Parameters
|
|
67
113
|
----------
|
|
68
114
|
path : str | list[str]
|
|
69
|
-
Path to the ``.las``, ``.dlis``, or ``.lis`` file(s).
|
|
115
|
+
Path to the ``.las``, ``.dlis``, or ``.lis`` file(s). Glob
|
|
116
|
+
expressions (``**/*.*``) and bare directory paths are supported.
|
|
70
117
|
recursive : bool, default True
|
|
71
|
-
|
|
118
|
+
Whether ``**`` glob patterns recurse into subdirectories.
|
|
72
119
|
squeeze : bool, default True
|
|
73
|
-
|
|
120
|
+
Return a single :class:`Log` directly when the result would be a
|
|
121
|
+
one-entry :class:`Pack`.
|
|
74
122
|
use_simpandas : bool | None, default None
|
|
123
|
+
Use :class:`simpandas.SimDataFrame` for curve storage when
|
|
124
|
+
``True``; plain :class:`pandas.DataFrame` when ``False``;
|
|
125
|
+
auto-detect when ``None`` (default).
|
|
75
126
|
raise_error : bool, default False
|
|
127
|
+
Raise exceptions for unreadable files. When ``False`` (default)
|
|
128
|
+
unreadable files are silently skipped.
|
|
76
129
|
correct_units : bool, default True
|
|
130
|
+
Normalise unit strings using the built-in correction dictionary
|
|
131
|
+
(e.g. ``GAPI`` → ``gAPI``).
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
Log | Pack
|
|
136
|
+
A :class:`Log` if a single file was resolved; a :class:`Pack`
|
|
137
|
+
otherwise (unless *squeeze* collapses a one-entry Pack).
|
|
138
|
+
|
|
139
|
+
Examples
|
|
140
|
+
--------
|
|
141
|
+
>>> import log2frame
|
|
142
|
+
>>> log = log2frame.read('well.las')
|
|
143
|
+
>>> pack = log2frame.read('data/**/*.las')
|
|
144
|
+
>>> log = log2frame.read(['run1.las', 'run2.las'], squeeze=False)
|
|
77
145
|
"""
|
|
78
146
|
if use_simpandas is not None and use_simpandas is True and not _params_.simpandas_:
|
|
79
147
|
raise ModuleNotFoundError("SimPandas is not installed, please install it or set parameter `use_simpandas` to False.")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Unit-name correction mapping for LAS/DLIS/LIS mnemonics.
|
|
3
|
+
|
|
4
|
+
Loads ``units_dictionary.json`` (stored alongside this file) and
|
|
5
|
+
exposes :func:`correct_units` to normalise non-standard unit strings to
|
|
6
|
+
their canonical forms (e.g. ``'GAPI'`` → ``'gAPI'``,
|
|
7
|
+
``'OHMM'`` → ``'ohm.m'``).
|
|
8
|
+
|
|
9
|
+
Module-level attributes
|
|
10
|
+
-----------------------
|
|
11
|
+
units_correction_dict_ : dict
|
|
12
|
+
The raw ``{non_canonical: canonical}`` mapping loaded from the JSON
|
|
13
|
+
dictionary. An empty dict is used as a safe fallback when the file
|
|
14
|
+
is missing or malformed (a :class:`UserWarning` is emitted).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from os.path import dirname
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
this_path_ = Path(__file__).with_name('units_dictionary.json').absolute()
|
|
22
|
+
this_path_ = dirname(this_path_) + '/'
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
with open(this_path_ + 'units_dictionary.json', 'r') as f:
|
|
26
|
+
units_correction_dict_ = json.load(f)
|
|
27
|
+
except (FileNotFoundError, json.JSONDecodeError) as e:
|
|
28
|
+
import warnings
|
|
29
|
+
warnings.warn(
|
|
30
|
+
f"log2frame: units-correction dictionary not found "
|
|
31
|
+
f"({type(e).__name__}: {e}); proceeding with unit-correction disabled.",
|
|
32
|
+
UserWarning,
|
|
33
|
+
)
|
|
34
|
+
units_correction_dict_ = {}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def correct_units(units):
|
|
38
|
+
"""Normalise unit strings using the built-in correction dictionary.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
units : str | dict
|
|
43
|
+
A single unit string, or a ``{mnemonic: unit}`` dict whose
|
|
44
|
+
values are corrected. Any other type is returned unchanged.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
str | dict
|
|
49
|
+
The corrected unit string (when *units* is a ``str``) or a new
|
|
50
|
+
dict with corrected values (when *units* is a ``dict``). Returns
|
|
51
|
+
the input unchanged when *units* is neither.
|
|
52
|
+
|
|
53
|
+
Examples
|
|
54
|
+
--------
|
|
55
|
+
>>> from log2frame.dictionaries.units import correct_units
|
|
56
|
+
>>> correct_units('GAPI')
|
|
57
|
+
'gAPI'
|
|
58
|
+
>>> correct_units({'GR': 'GAPI', 'RHOB': 'G/C3'})
|
|
59
|
+
{'GR': 'gAPI', 'RHOB': 'g/c3'}
|
|
60
|
+
"""
|
|
61
|
+
if type(units) is dict:
|
|
62
|
+
return {k: (units_correction_dict_[u]
|
|
63
|
+
if u in units_correction_dict_
|
|
64
|
+
else u)
|
|
65
|
+
for k, u in units.items()}
|
|
66
|
+
elif type(units) is str and units in units_correction_dict_:
|
|
67
|
+
return units_correction_dict_[units]
|
|
68
|
+
else:
|
|
69
|
+
return units
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
|
|
2
|
+
"""DLIS reader — parse DLIS files into :class:`Log` or :class:`Pack` containers.
|
|
3
|
+
|
|
4
|
+
This module wraps ``dlisio`` to provide curve data and metadata as
|
|
5
|
+
unit-aware :class:`Log` objects. When a DLIS file contains multiple
|
|
6
|
+
logical files or frames, a :class:`Pack` grouping all frames is returned.
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
Public API
|
|
9
|
+
----------
|
|
10
|
+
dlis2frame(path, ...) Read a ``.dlis`` file.
|
|
6
11
|
"""
|
|
7
12
|
|
|
8
13
|
import logging
|
|
@@ -19,16 +24,14 @@ try:
|
|
|
19
24
|
except ModuleNotFoundError:
|
|
20
25
|
pass
|
|
21
26
|
|
|
22
|
-
__version__ = '0.2.
|
|
23
|
-
__release__ =
|
|
27
|
+
__version__ = '0.2.3'
|
|
28
|
+
__release__ = 20260503
|
|
24
29
|
|
|
25
30
|
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
|
|
26
31
|
|
|
27
32
|
|
|
28
33
|
class DLISIOError(Exception):
|
|
29
|
-
"""
|
|
30
|
-
Error raised while reading LAS file.
|
|
31
|
-
"""
|
|
34
|
+
"""Raised when ``dlisio`` fails to parse a DLIS file."""
|
|
32
35
|
def __init__(self, message='raised by dlisio.'):
|
|
33
36
|
self.message = 'ERROR: reading DLIS file ' + message
|
|
34
37
|
|
|
@@ -61,6 +64,7 @@ def dlis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tr
|
|
|
61
64
|
"""
|
|
62
65
|
if not os.path.isfile(path):
|
|
63
66
|
raise FileNotFoundError("The provided path can't be found:\n" + str(path))
|
|
67
|
+
original_path = path
|
|
64
68
|
if type(path) is str:
|
|
65
69
|
path = path.replace('\\', '/')
|
|
66
70
|
|
|
@@ -154,10 +158,10 @@ def dlis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tr
|
|
|
154
158
|
data=data[0] if not use_simpandas else spd.SimDataFrame(data=data[0], units=data[2].to_dict(),
|
|
155
159
|
name=data[3],
|
|
156
160
|
meta=data[1],
|
|
157
|
-
source=str(
|
|
161
|
+
source=str(original_path)),
|
|
158
162
|
header=data[1],
|
|
159
163
|
units=data[2],
|
|
160
|
-
source=str(
|
|
164
|
+
source=str(original_path),
|
|
161
165
|
well=data[3]) for name, data in frames.items()}
|
|
162
166
|
return frames[list(frames.keys())[0]]
|
|
163
167
|
else:
|
|
@@ -167,11 +171,11 @@ def dlis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tr
|
|
|
167
171
|
meta=data[1],
|
|
168
172
|
source='logical file ' + str(name[0]) +
|
|
169
173
|
', frame ' + str(name[1]) +
|
|
170
|
-
' in: ' +
|
|
174
|
+
' in: ' + str(original_path)),
|
|
171
175
|
header=data[1],
|
|
172
176
|
units=data[2],
|
|
173
177
|
source='logical file ' + str(name[0]) +
|
|
174
178
|
', frame ' + str(name[1]) +
|
|
175
|
-
' in: ' +
|
|
179
|
+
' in: ' + str(original_path),
|
|
176
180
|
well=data[3]) for name, data in frames.items()}
|
|
177
181
|
return Pack(frames)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
|
|
2
|
+
"""LAS reader — parse LAS 1.2, 2.0, and 3.0 files into :class:`Log` containers.
|
|
3
|
+
|
|
4
|
+
This module wraps ``lasio`` to provide curve data and metadata as
|
|
5
|
+
unit-aware :class:`Log` objects.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Public API
|
|
8
|
+
----------
|
|
9
|
+
las2frame(path, ...) Read a ``.las`` file.
|
|
6
10
|
"""
|
|
7
11
|
import logging
|
|
8
12
|
import lasio
|
|
@@ -18,16 +22,14 @@ try:
|
|
|
18
22
|
except ModuleNotFoundError:
|
|
19
23
|
pass
|
|
20
24
|
|
|
21
|
-
__version__ = '0.2.
|
|
22
|
-
__release__ =
|
|
25
|
+
__version__ = '0.2.3'
|
|
26
|
+
__release__ = 20260503
|
|
23
27
|
|
|
24
28
|
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
class LASIOError(Exception):
|
|
28
|
-
"""
|
|
29
|
-
Error raised while reading LAS file.
|
|
30
|
-
"""
|
|
32
|
+
"""Raised when ``lasio`` fails to parse a LAS file."""
|
|
31
33
|
def __init__(self, message='raised by lasio.'):
|
|
32
34
|
self.message = 'ERROR: reading LAS file ' + message
|
|
33
35
|
|
|
@@ -68,6 +70,7 @@ def las2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tru
|
|
|
68
70
|
"""
|
|
69
71
|
if not os.path.isfile(path):
|
|
70
72
|
raise FileNotFoundError("The provided path can't be found:\n" + str(path))
|
|
73
|
+
original_path = path
|
|
71
74
|
if type(path) is str:
|
|
72
75
|
path = path.replace('\\', '/')
|
|
73
76
|
|
|
@@ -125,10 +128,10 @@ def las2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tru
|
|
|
125
128
|
units=las_units,
|
|
126
129
|
name=well_name,
|
|
127
130
|
meta=las_header,
|
|
128
|
-
source=
|
|
131
|
+
source=original_path)
|
|
129
132
|
|
|
130
133
|
return Log(data=data,
|
|
131
134
|
header=las_header,
|
|
132
135
|
units=pd.Series(las_units, name='curves_units'),
|
|
133
|
-
source=
|
|
136
|
+
source=original_path,
|
|
134
137
|
well=well_name)
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
|
|
2
|
+
"""LIS reader — parse LIS files into :class:`Log` or :class:`Pack` containers.
|
|
3
|
+
|
|
4
|
+
This module wraps ``dlisio.lis`` to provide curve data and metadata as
|
|
5
|
+
unit-aware :class:`Log` objects. When a LIS file contains multiple
|
|
6
|
+
logical files or format specs with different sample rates, each
|
|
7
|
+
combination is returned as a separate :class:`Log` grouped in a
|
|
8
|
+
:class:`Pack`.
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
Public API
|
|
11
|
+
----------
|
|
12
|
+
lis2frame(path, ...) Read a ``.lis`` or ``.lti`` file.
|
|
6
13
|
"""
|
|
7
14
|
|
|
8
15
|
import logging
|
|
@@ -18,16 +25,14 @@ try:
|
|
|
18
25
|
except ModuleNotFoundError:
|
|
19
26
|
pass
|
|
20
27
|
|
|
21
|
-
__version__ = '0.2.
|
|
22
|
-
__release__ =
|
|
28
|
+
__version__ = '0.2.3'
|
|
29
|
+
__release__ = 20260503
|
|
23
30
|
|
|
24
31
|
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
|
|
25
32
|
|
|
26
33
|
|
|
27
34
|
class DLISIOError(Exception):
|
|
28
|
-
"""
|
|
29
|
-
Error raised while reading LAS file.
|
|
30
|
-
"""
|
|
35
|
+
"""Raised when ``dlisio`` fails to parse a LIS file."""
|
|
31
36
|
def __init__(self, message='raised by dlisio.'):
|
|
32
37
|
self.message = 'ERROR: reading LIS file ' + message
|
|
33
38
|
|
|
@@ -59,6 +64,7 @@ def lis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tru
|
|
|
59
64
|
"""
|
|
60
65
|
if not os.path.isfile(path):
|
|
61
66
|
raise FileNotFoundError("The provided path can't be found:\n" + str(path))
|
|
67
|
+
original_path = path
|
|
62
68
|
if type(path) is str:
|
|
63
69
|
path = path.replace('\\', '/')
|
|
64
70
|
|
|
@@ -69,6 +75,28 @@ def lis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tru
|
|
|
69
75
|
raise ModuleNotFoundError("SimPandas is not installed, please install it or set parameter `use_simpandas` to False.")
|
|
70
76
|
|
|
71
77
|
def _get_frame(data, l_count, i, sr):
|
|
78
|
+
"""Return the curve data for one format spec and sample rate.
|
|
79
|
+
|
|
80
|
+
When *use_simpandas* is ``True``, wraps the raw structured array
|
|
81
|
+
in a :class:`simpandas.SimDataFrame` with units and index
|
|
82
|
+
settings applied. Otherwise returns a plain
|
|
83
|
+
:class:`pandas.DataFrame` with the index set to the depth column.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
data : pandas.DataFrame
|
|
88
|
+
Raw DataFrame produced from :func:`dlisio.lis.curves`.
|
|
89
|
+
l_count : int
|
|
90
|
+
Logical-file counter key into ``frames``.
|
|
91
|
+
i : int
|
|
92
|
+
Format-spec index within the logical file.
|
|
93
|
+
sr : int | float
|
|
94
|
+
Sample-rate key within the format spec.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
pandas.DataFrame | simpandas.SimDataFrame
|
|
99
|
+
"""
|
|
72
100
|
if frames[l_count][i]['index_name'] in data:
|
|
73
101
|
index_name = frames[l_count][i]['index_name']
|
|
74
102
|
elif len([c for c in data.columns if c.startswith(frames[l_count][i]['index_name'])]) > 0:
|
|
@@ -90,12 +118,31 @@ def lis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tru
|
|
|
90
118
|
if frames[l_count]['header']['name'] is not None
|
|
91
119
|
and len(frames[l_count]['header']['name']) > 0 else None),
|
|
92
120
|
meta=_make_header(l_count=l_count, i=i, sr=sr),
|
|
93
|
-
source='logical file ' + str(l_count) + ', frame ' + str(i) + ', sample rate ' + str(sr) + ' in: ' + str(
|
|
121
|
+
source='logical file ' + str(l_count) + ', frame ' + str(i) + ', sample rate ' + str(sr) + ' in: ' + str(original_path))
|
|
94
122
|
else:
|
|
95
123
|
return data.set_index(index_name)
|
|
96
124
|
|
|
97
125
|
|
|
98
126
|
def _make_header(l_count, i, sr):
|
|
127
|
+
"""Build a merged header DataFrame for one logical file / frame / sample rate.
|
|
128
|
+
|
|
129
|
+
Concatenates curve units, wellsite data, and LIS file/reel header
|
|
130
|
+
into a single :class:`pandas.DataFrame` indexed by mnemonic.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
l_count : int
|
|
135
|
+
Logical-file index.
|
|
136
|
+
i : int
|
|
137
|
+
Format-spec index within the logical file.
|
|
138
|
+
sr : int | float
|
|
139
|
+
Sample-rate key.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
pandas.DataFrame
|
|
144
|
+
Combined header table; empty cells are replaced with ``''``.
|
|
145
|
+
"""
|
|
99
146
|
to_concat = []
|
|
100
147
|
if 'curves_units' in frames[l_count][i] and sr in frames[l_count][i]['curves_units']:
|
|
101
148
|
to_concat.append(pd.DataFrame(frames[l_count][i]['curves_units'][sr],
|
|
@@ -110,6 +157,18 @@ def lis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tru
|
|
|
110
157
|
return pd.concat(to_concat, axis=0).fillna(value='')
|
|
111
158
|
|
|
112
159
|
def _try_frame(data):
|
|
160
|
+
"""Attempt to wrap *data* in a :class:`pandas.DataFrame`.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
data : structured numpy array or similar
|
|
165
|
+
Raw curve data returned by :func:`dlisio.lis.curves`.
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
pandas.DataFrame | None
|
|
170
|
+
``None`` when the conversion raises any exception.
|
|
171
|
+
"""
|
|
113
172
|
try:
|
|
114
173
|
return pd.DataFrame(data)
|
|
115
174
|
except:
|
|
@@ -186,7 +245,7 @@ def lis2frame(path: str, use_simpandas=None, raise_error=True, correct_units=Tru
|
|
|
186
245
|
source='logical file ' + str(l_count) +
|
|
187
246
|
', frame ' + str(i) +
|
|
188
247
|
', sample rate ' + str(sr) +
|
|
189
|
-
' in: ' + str(
|
|
248
|
+
' in: ' + str(original_path),
|
|
190
249
|
well=(
|
|
191
250
|
frames[l_count]['header']['service_name'] if frames[l_count]['header']['service_name'] is not None and len(
|
|
192
251
|
frames[l_count]['header']['service_name']) > 0 else
|