stoneforge 0.2.0b2__tar.gz → 0.2.0b3__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.
- {stoneforge-0.2.0b2/stoneforge.egg-info → stoneforge-0.2.0b3}/PKG-INFO +1 -2
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/pyproject.toml +1 -2
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/__init__.py +2 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/dlisio_r.py +65 -3
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/las2.py +75 -4
- stoneforge-0.2.0b3/stoneforge/io/las3.py +180 -0
- stoneforge-0.2.0b3/stoneforge/io/tabr.py +95 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3/stoneforge.egg-info}/PKG-INFO +1 -2
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/SOURCES.txt +2 -11
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/requires.txt +0 -1
- stoneforge-0.2.0b2/docs/_build/html/_sources/index.rst.txt +0 -43
- stoneforge-0.2.0b2/docs/_build/html/_sources/modules/machinelearning/classification.rst.txt +0 -39
- stoneforge-0.2.0b2/docs/_build/html/_sources/modules/machinelearning/index.rst.txt +0 -10
- stoneforge-0.2.0b2/docs/_build/html/_sources/modules/machinelearning/regression.rst.txt +0 -39
- stoneforge-0.2.0b2/docs/_build/html/_sources/modules/petrophysics.rst.txt +0 -39
- stoneforge-0.2.0b2/docs/_build/html/_sources/modules/preprocessing.rst.txt +0 -28
- stoneforge-0.2.0b2/docs/_build/html/_sources/modules/pseudowells.rst.txt +0 -23
- stoneforge-0.2.0b2/docs/_build/html/_sources/modules/rockphysics.rst.txt +0 -47
- stoneforge-0.2.0b2/docs/_build/html/_sources/usage/installation.rst.txt +0 -40
- stoneforge-0.2.0b2/docs/_build/html/_sources/usage/quickstart.rst.txt +0 -28
- stoneforge-0.2.0b2/stoneforge/io/lasparser.py +0 -74
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/CHANGELOG.txt +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/LICENSE +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/MANIFEST.in +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/README.md +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/docs/conf.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/setup.cfg +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/datasets/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/datasets/data_info.txt +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/datasets/dataload.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/regularized_acoustic_reflectivy_inversion.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/viability_study/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/viability_study/bayes.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/csv.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/evaluation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/fit.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/predict.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/settings.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/validation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/evaluation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/fit.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/predict.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/settings.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/validation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/evaluation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/fit.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/predict.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/settings.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/validation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/evaluation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/fit.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/mldr_project.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/predict.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/settings.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/helpers.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/porosity.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/shale_volume.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/total_organic_carbon_content.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/water_saturation.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/data_management.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/data_processing.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/las2.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/las_pandas.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/lithology_generator.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/monte_carlo_simulations.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/pseudo_tools.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/elastic_constants.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/fluid_substitution.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/gem.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/inclusion.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/rock_physics_bounds.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/vis/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/vis/img.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/__init__.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/butterworth.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/ormsby.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/ricker.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/dependency_links.txt +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/top_level.txt +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_ml/test_classification.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_ml/test_regression.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_porosity/parameters_p.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_porosity/test_porosity.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_rock_physics/test_elastic_constants.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_rock_physics/test_fluid_substitution.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_rock_physics/test_gem.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_water_saturation/parameters_ws.py +0 -0
- {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_water_saturation/test_water_saturation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stoneforge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.0b3
|
|
4
4
|
Summary: Geophysics equations, algorithms and methods
|
|
5
5
|
Author: GIECAR - UFF, Wagner M. Lupinacci, Fernando Vizeu, Fábio Júnior D Fernandes, José A. V. Dias, Mario M. Ramos, Jordan S. Cuno, João Vitor A. Estrella, Ana Carolina, Breno D. Chrispim
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,7 +21,6 @@ Requires-Dist: matplotlib>=3.10.0
|
|
|
21
21
|
Requires-Dist: pandas>=2.2.2
|
|
22
22
|
Requires-Dist: lightgbm>=4.5.0
|
|
23
23
|
Requires-Dist: ipympl>=0.8.4
|
|
24
|
-
Requires-Dist: ipykernel>=6.30.0
|
|
25
24
|
Dynamic: license-file
|
|
26
25
|
|
|
27
26
|
<p align="center">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "stoneforge"
|
|
3
|
-
version = "0.2.0-beta.
|
|
3
|
+
version = "0.2.0-beta.3"
|
|
4
4
|
authors = [
|
|
5
5
|
{name = "GIECAR - UFF"},
|
|
6
6
|
{name = "Wagner M. Lupinacci"},
|
|
@@ -27,7 +27,6 @@ dependencies = [
|
|
|
27
27
|
"pandas>=2.2.2",
|
|
28
28
|
"lightgbm>=4.5.0",
|
|
29
29
|
"ipympl>=0.8.4",
|
|
30
|
-
"ipykernel>=6.30.0",
|
|
31
30
|
]
|
|
32
31
|
classifiers = [
|
|
33
32
|
"Development Status :: 5 - Production/Stable",
|
|
@@ -37,7 +37,69 @@ class DLISAccess:
|
|
|
37
37
|
return self.selected_header_df
|
|
38
38
|
|
|
39
39
|
def get_info(self):
|
|
40
|
-
|
|
40
|
+
"""Module to get the DLIS file structure in a dictionary format."""
|
|
41
|
+
info = self.dlis_dict_headers
|
|
42
|
+
index = 0
|
|
43
|
+
d_file_data = {} # store DataFrames per frame
|
|
44
|
+
|
|
45
|
+
for d_file in info:
|
|
46
|
+
frames_data = {}
|
|
47
|
+
for frame in info[d_file]:
|
|
48
|
+
rows = []
|
|
49
|
+
for mnemonic in info[d_file][frame]:
|
|
50
|
+
_data_info = info[d_file][frame][mnemonic]
|
|
51
|
+
_unit = _data_info['unit']
|
|
52
|
+
_dim = _data_info['dim']
|
|
53
|
+
_min = _data_info['min']
|
|
54
|
+
_max = _data_info['max']
|
|
55
|
+
_long_name = _data_info['long_name']
|
|
56
|
+
rows.append((index, mnemonic, _unit, _dim, _min, _max, _long_name))
|
|
57
|
+
index += 1
|
|
58
|
+
|
|
59
|
+
# Create DataFrame for this frame
|
|
60
|
+
df = pd.DataFrame(rows, columns=["Index", "Mnemonic", "Unit", "Dim", "Min", "Max", "Long Name"])
|
|
61
|
+
df.set_index('Index', inplace=True)
|
|
62
|
+
|
|
63
|
+
frames_data[frame] = df
|
|
64
|
+
d_file_data[d_file] = frames_data
|
|
65
|
+
return d_file_data
|
|
66
|
+
|
|
67
|
+
def mnemonic_search(self, mnemonics_list):
|
|
68
|
+
""""Module to search for mnemonics in the DLIS file headers.
|
|
69
|
+
The search is case-sensitive and returns data for the matching mnemonics.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
mnemonics_list : list
|
|
74
|
+
List of mnemonics to search for in the DLIS file headers.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
dict
|
|
79
|
+
A dictionary containing the parsed DLIS data based on the searched mnemonics with the structure
|
|
80
|
+
{digital_file: {frame_name: {mnemonic: {unit, values}}}}
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
info = self.dlis_dict_headers
|
|
84
|
+
index = 0
|
|
85
|
+
full_mnemonics = [] # store DataFrames per frame
|
|
86
|
+
|
|
87
|
+
for d_file in info:
|
|
88
|
+
frames_data = {}
|
|
89
|
+
for frame in info[d_file]:
|
|
90
|
+
rows = []
|
|
91
|
+
for mnemonic in info[d_file][frame]:
|
|
92
|
+
full_mnemonics.append(mnemonic)
|
|
93
|
+
|
|
94
|
+
# find positions of matches
|
|
95
|
+
positions = [i for mnemonic in mnemonics_list
|
|
96
|
+
for i, val in enumerate(full_mnemonics) if val == mnemonic]
|
|
97
|
+
|
|
98
|
+
positions = sorted(positions)
|
|
99
|
+
|
|
100
|
+
self.select_header(idx=positions)
|
|
101
|
+
return self.get_data()
|
|
102
|
+
|
|
41
103
|
|
|
42
104
|
def get_data(self):
|
|
43
105
|
"""Module to get the data selected in the checkbox.
|
|
@@ -311,8 +373,8 @@ class DLISAccess:
|
|
|
311
373
|
values = np.array(channel.curves()) # Convert to numpy array
|
|
312
374
|
|
|
313
375
|
extracted_data[logical_file_id][frame_name][mnemonic] = {
|
|
314
|
-
'
|
|
315
|
-
'
|
|
376
|
+
'values': values,
|
|
377
|
+
'unit': unit
|
|
316
378
|
}
|
|
317
379
|
|
|
318
380
|
return extracted_data
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import numpy as np
|
|
3
3
|
import io
|
|
4
|
+
import pandas as pd
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class LAS2Error(Exception):
|
|
7
8
|
pass
|
|
8
9
|
|
|
9
|
-
|
|
10
10
|
_default_line_format_format = (
|
|
11
11
|
"{{mnemonic:<{mnemonic}}}."
|
|
12
12
|
"{{unit:<{unit}}} "
|
|
@@ -84,6 +84,77 @@ _parsers = {
|
|
|
84
84
|
"data": _parse_data_section,
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
class LAS2Parser:
|
|
88
|
+
|
|
89
|
+
def __init__(self, file_path):
|
|
90
|
+
"""Manages the contents of a LAS 2.0 file
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
file_path : str
|
|
95
|
+
The path to the LAS 2.0 file to be read.
|
|
96
|
+
|
|
97
|
+
Attributes
|
|
98
|
+
----------
|
|
99
|
+
data : dict
|
|
100
|
+
A dictionary containing the well log data and metadata.
|
|
101
|
+
header : dict
|
|
102
|
+
A dictionary containing the header information of the LAS file.
|
|
103
|
+
|
|
104
|
+
Notes
|
|
105
|
+
-----
|
|
106
|
+
The structure of the returned dictionary is specified below.
|
|
107
|
+
The dictionary keys are the section names: 'version', 'well', 'parameter', 'curve', 'other', 'data'.
|
|
108
|
+
Not all sections must be present on a LAS 2.0 file.
|
|
109
|
+
For more information on the contents of each section, please refer to the LAS 2.0 standard [1]_.
|
|
110
|
+
|
|
111
|
+
The value of the 'data' section is a numpy ndarray where each row contains the data for a well log.
|
|
112
|
+
|
|
113
|
+
The value of the 'other' section is a list of lines exactly as found on the original file.
|
|
114
|
+
|
|
115
|
+
For all other sections, the values are dictionaries containing four keys: 'mnemonic', 'unit', 'value' and
|
|
116
|
+
'description'.
|
|
117
|
+
For information on the structure of a LAS 2.0 line, please also refer to its specification [1]_.
|
|
118
|
+
|
|
119
|
+
References
|
|
120
|
+
----------
|
|
121
|
+
.. [1] LAS 2.0 standard - http://www.cwls.org/wp-content/uploads/2017/02/Las2_Update_Feb2017.pdf -
|
|
122
|
+
Retrieved August 14, 2019
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
self.filepath = file_path
|
|
126
|
+
self.data = {}
|
|
127
|
+
self.header = {}
|
|
128
|
+
|
|
129
|
+
self._parser()
|
|
130
|
+
|
|
131
|
+
def _parser(self):
|
|
132
|
+
las2_file_path = self.filepath
|
|
133
|
+
las_data = read(las2_file_path)
|
|
134
|
+
header = {}
|
|
135
|
+
for key in las_data:
|
|
136
|
+
if key not in ['data']:
|
|
137
|
+
df = pd.DataFrame(las_data[key])
|
|
138
|
+
header[key] = df
|
|
139
|
+
data_header = list(las_data['curve'])
|
|
140
|
+
|
|
141
|
+
log_main_data = {}
|
|
142
|
+
ii = 0
|
|
143
|
+
log_data = las_data['data']
|
|
144
|
+
for _log in data_header:
|
|
145
|
+
_mnem = _log['mnemonic']
|
|
146
|
+
_unit = _log['unit']
|
|
147
|
+
try:
|
|
148
|
+
_descr = _log['description']
|
|
149
|
+
except:
|
|
150
|
+
_descr = 'NONE'
|
|
151
|
+
_data = log_data[ii]
|
|
152
|
+
log_main_data[_mnem] = {'values':_data,'unit':_unit,'description':_descr}
|
|
153
|
+
ii += 1
|
|
154
|
+
|
|
155
|
+
self.data = log_main_data
|
|
156
|
+
self.header = header
|
|
157
|
+
|
|
87
158
|
|
|
88
159
|
def read(lasfile):
|
|
89
160
|
"""Reads the contents of a LAS 2.0 file.
|
|
@@ -93,12 +164,12 @@ def read(lasfile):
|
|
|
93
164
|
lasfile : string or file-like object
|
|
94
165
|
The path of the file to read or an existing file-like object to read from.
|
|
95
166
|
|
|
96
|
-
Returns
|
|
167
|
+
Returns
|
|
97
168
|
-------
|
|
98
169
|
dict
|
|
99
170
|
A dictionary containing the sections of the LAS file.
|
|
100
171
|
|
|
101
|
-
Notes
|
|
172
|
+
Notes
|
|
102
173
|
-----
|
|
103
174
|
The structure of the returned dictionary is specified below.
|
|
104
175
|
The dictionary keys are the section names: 'version', 'well', 'parameter', 'curve', 'other', 'data'.
|
|
@@ -113,7 +184,7 @@ def read(lasfile):
|
|
|
113
184
|
'description'.
|
|
114
185
|
For information on the structure of a LAS 2.0 line, please also refer to its specification [1]_.
|
|
115
186
|
|
|
116
|
-
References
|
|
187
|
+
References
|
|
117
188
|
----------
|
|
118
189
|
.. [1] LAS 2.0 standard - http://www.cwls.org/wp-content/uploads/2017/02/Las2_Update_Feb2017.pdf -
|
|
119
190
|
Retrieved August 14, 2019
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import numpy as np
|
|
3
|
+
from collections import Counter
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
class LAS3Parser:
|
|
7
|
+
|
|
8
|
+
def __init__(self, las3_file_path):
|
|
9
|
+
self.filepath = las3_file_path
|
|
10
|
+
self.data = self.parse_las3()
|
|
11
|
+
self.tables = list(self.data.keys())
|
|
12
|
+
|
|
13
|
+
def force_association(self, to_dict = True, forced=True, sep = "|"):
|
|
14
|
+
"""
|
|
15
|
+
Given the parsed data dictionary and a description string,
|
|
16
|
+
return the associated DataFrame if it exists.
|
|
17
|
+
This method forces the association even if the description is not found.
|
|
18
|
+
"""
|
|
19
|
+
_data = []
|
|
20
|
+
_desc = []
|
|
21
|
+
_clen = []
|
|
22
|
+
|
|
23
|
+
for i, k1 in enumerate(self.tables):
|
|
24
|
+
for j, k2 in enumerate(self.tables):
|
|
25
|
+
if i != j:
|
|
26
|
+
# clean k2 if it has "|"
|
|
27
|
+
k2_clean = k2.split("|")[0].strip()
|
|
28
|
+
if k1 in k2:
|
|
29
|
+
_data.append(k2)
|
|
30
|
+
_desc.append(k1)
|
|
31
|
+
_clen.append(k2_clean)
|
|
32
|
+
|
|
33
|
+
# --- remove all duplicates in _desc completely ---
|
|
34
|
+
counts = Counter(_desc)
|
|
35
|
+
|
|
36
|
+
_data_unique = []
|
|
37
|
+
_desc_unique = []
|
|
38
|
+
_clen_unique = []
|
|
39
|
+
|
|
40
|
+
for d, desc, c in zip(_data, _desc, _clen):
|
|
41
|
+
if counts[desc] == 1: # keep only if desc is unique
|
|
42
|
+
_data_unique.append(d)
|
|
43
|
+
_desc_unique.append(desc)
|
|
44
|
+
_clen_unique.append(c)
|
|
45
|
+
|
|
46
|
+
for i in range(len(_desc_unique)):
|
|
47
|
+
_name = _clen_unique[i]
|
|
48
|
+
_key = _data_unique[i]
|
|
49
|
+
_val = _desc_unique[i]
|
|
50
|
+
|
|
51
|
+
self.data[_name] = self.table_association(_key, _val, forced=forced, to_dict = to_dict)
|
|
52
|
+
self.data.pop(_key)
|
|
53
|
+
self.data.pop(_val)
|
|
54
|
+
|
|
55
|
+
self.tables = list(self.data.keys())
|
|
56
|
+
|
|
57
|
+
def table_association(self, data, description, forced=True, to_dict = True):
|
|
58
|
+
"""
|
|
59
|
+
Given the parsed data dictionary and a description string,
|
|
60
|
+
return the associated DataFrame if it exists.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
if forced:
|
|
64
|
+
try:
|
|
65
|
+
_desc = list(self.data[description][0])
|
|
66
|
+
_mnem = []
|
|
67
|
+
_unit = []
|
|
68
|
+
|
|
69
|
+
for item in _desc:
|
|
70
|
+
# split only on first "."
|
|
71
|
+
parts = item.split('.', 1)
|
|
72
|
+
left = parts[0].strip().replace(" ", "") # remove blanks and dot
|
|
73
|
+
right = '.' + parts[1].strip() if len(parts) > 1 else '' # keep dot, strip spaces
|
|
74
|
+
|
|
75
|
+
_mnem.append(left)
|
|
76
|
+
_unit.append(right)
|
|
77
|
+
except KeyError:
|
|
78
|
+
Warning (f"Description '{description}' not found in data. Using raw mnemonics and units.")
|
|
79
|
+
_mnem = list(_desc = list(self.data[description][0]))
|
|
80
|
+
_unit = list(_desc = list(self.data[description][1]))
|
|
81
|
+
else:
|
|
82
|
+
_mnem = list(_desc = list(self.data[description][0]))
|
|
83
|
+
_unit = list(_desc = list(self.data[description][1]))
|
|
84
|
+
|
|
85
|
+
self.data[data].columns = _mnem
|
|
86
|
+
main_data = self.data[data]
|
|
87
|
+
if to_dict:
|
|
88
|
+
main_data = main_data.to_dict(orient="list")
|
|
89
|
+
|
|
90
|
+
converted_data = {}
|
|
91
|
+
for key, values in main_data.items():
|
|
92
|
+
try:
|
|
93
|
+
# Try converting to float
|
|
94
|
+
converted_data[key] = np.array(values, dtype=float)
|
|
95
|
+
except ValueError:
|
|
96
|
+
Warning(f"Could not convert column '{key}' to float. Keeping as string array.")
|
|
97
|
+
# If fails, keep as string array
|
|
98
|
+
converted_data[key] = np.array(values, dtype=str)
|
|
99
|
+
|
|
100
|
+
main_data = converted_data
|
|
101
|
+
|
|
102
|
+
overall_data = {}
|
|
103
|
+
for i in range(len(_mnem)):
|
|
104
|
+
_m = _mnem[i]
|
|
105
|
+
_u = _unit[i]
|
|
106
|
+
overall_data[_m] = {'values': main_data[_m], 'unit': _u}
|
|
107
|
+
|
|
108
|
+
return overall_data
|
|
109
|
+
|
|
110
|
+
def parse_las3(self):
|
|
111
|
+
"Take the path to a LAS3 file and return a dictionary of DataFrames, one for each section. utf-8 based"
|
|
112
|
+
data_sections = {}
|
|
113
|
+
current_key = None
|
|
114
|
+
current_data_lines = []
|
|
115
|
+
|
|
116
|
+
with open(self.filepath, 'r', encoding='utf-8') as file:
|
|
117
|
+
for line in file:
|
|
118
|
+
stripped = line.strip()
|
|
119
|
+
|
|
120
|
+
# Skip blank lines and comments
|
|
121
|
+
if not stripped or stripped.startswith('#'):
|
|
122
|
+
continue
|
|
123
|
+
|
|
124
|
+
if stripped.startswith('~'):
|
|
125
|
+
# Save previous section
|
|
126
|
+
if current_key and current_data_lines:
|
|
127
|
+
df = self._parse_data_block(current_data_lines)
|
|
128
|
+
data_sections[current_key] = df
|
|
129
|
+
current_data_lines = []
|
|
130
|
+
|
|
131
|
+
current_key = stripped.lstrip('~').strip()
|
|
132
|
+
else:
|
|
133
|
+
current_data_lines.append(stripped)
|
|
134
|
+
|
|
135
|
+
# Add the final section
|
|
136
|
+
if current_key and current_data_lines:
|
|
137
|
+
df = self._parse_data_block(current_data_lines)
|
|
138
|
+
data_sections[current_key] = df
|
|
139
|
+
|
|
140
|
+
return data_sections
|
|
141
|
+
|
|
142
|
+
def _parse_data_block(self, lines):
|
|
143
|
+
"Try to read the elements of a data block, first with default tab/space/colon logic, then with comma."
|
|
144
|
+
structured_data = []
|
|
145
|
+
|
|
146
|
+
# First parse with default (tab/space/colon) logic
|
|
147
|
+
for line in lines:
|
|
148
|
+
line = line.rstrip()
|
|
149
|
+
if not line.strip():
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
parts = re.split(r'(?:\t| {4,})', line, maxsplit=1)
|
|
153
|
+
|
|
154
|
+
if len(parts) == 2:
|
|
155
|
+
key = parts[0].strip()
|
|
156
|
+
rest = parts[1].strip()
|
|
157
|
+
rest_parts = re.split(r'\s*:\s*', rest, maxsplit=1)
|
|
158
|
+
|
|
159
|
+
if len(rest_parts) == 2:
|
|
160
|
+
structured_data.append([key, rest_parts[0].strip(), rest_parts[1].strip()])
|
|
161
|
+
else:
|
|
162
|
+
structured_data.append([key, rest.strip(), ""])
|
|
163
|
+
else:
|
|
164
|
+
structured_data.append([parts[0].strip(), "", ""])
|
|
165
|
+
|
|
166
|
+
# Create initial DataFrame and drop empty columns
|
|
167
|
+
df_original = pd.DataFrame(structured_data)
|
|
168
|
+
df_original = df_original.loc[:, ~df_original.apply(lambda col: col.astype(str).str.strip().eq('').all(), axis=0)]
|
|
169
|
+
n_original_cols = df_original.shape[1]
|
|
170
|
+
|
|
171
|
+
# Try parsing with comma separator
|
|
172
|
+
comma_data = [line.split(",") for line in lines if line.strip()]
|
|
173
|
+
df_comma = pd.DataFrame(comma_data)
|
|
174
|
+
df_comma = df_comma.loc[:, ~df_comma.apply(lambda col: col.astype(str).str.strip().eq('').all(), axis=0)]
|
|
175
|
+
|
|
176
|
+
# Use the comma-parsed version only if it has more columns
|
|
177
|
+
if df_comma.shape[1] > n_original_cols:
|
|
178
|
+
return df_comma
|
|
179
|
+
else:
|
|
180
|
+
return df_original
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
import re
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
class TABParser:
|
|
6
|
+
def __init__(self, file_path, sep=",", std="US"):
|
|
7
|
+
"""
|
|
8
|
+
Initializes the TabularDataLoader with the given file path, separator, and numeric format.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
file_path (str): Path to the CSV/TSV file.
|
|
12
|
+
sep (str): Field separator (default is ",").
|
|
13
|
+
std (str): Numeric formatting standard, either "US" [standard one] (1,234.56) or "BR" (1.234,56).
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
None
|
|
17
|
+
"""
|
|
18
|
+
self.file_path = file_path
|
|
19
|
+
self.data = self._load_csv_as_dict(file_path = file_path, sep=sep, std=std)
|
|
20
|
+
|
|
21
|
+
def _load_csv_as_dict(self, file_path, sep=",", std="US"):
|
|
22
|
+
"""
|
|
23
|
+
Reads a CSV/TSV file line by line, robust against malformed rows.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
file_path (str): path to file
|
|
27
|
+
sep (str): field separator (default ",")
|
|
28
|
+
std (str): "US" (1,234.56) or "BR" (1.234,56) numeric formatting
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
dict: { column_name: {"unit": str, "values": np.ndarray or list[str]} }
|
|
32
|
+
"""
|
|
33
|
+
data_dict = {}
|
|
34
|
+
|
|
35
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
36
|
+
lines = f.readlines()
|
|
37
|
+
|
|
38
|
+
# --- Step 1: extract header
|
|
39
|
+
header_line = lines[0].strip()
|
|
40
|
+
headers = header_line.split(sep)
|
|
41
|
+
|
|
42
|
+
for col in headers:
|
|
43
|
+
col = col.strip()
|
|
44
|
+
name = col.split(" ", 1)[0].strip()
|
|
45
|
+
data_dict[name] = {"unit": "", "values": []}
|
|
46
|
+
|
|
47
|
+
# --- Step 2: normalization helper
|
|
48
|
+
def normalize_value(val):
|
|
49
|
+
val = val.strip().strip('"')
|
|
50
|
+
if re.match(r"^-?\d+[.,]?\d*$", val): # numeric-like
|
|
51
|
+
if std.upper() == "US":
|
|
52
|
+
val = val.replace(",", "")
|
|
53
|
+
elif std.upper() == "BR":
|
|
54
|
+
val = val.replace(".", "").replace(",", ".")
|
|
55
|
+
return val
|
|
56
|
+
|
|
57
|
+
# --- Step 3: process rows
|
|
58
|
+
for i, line in enumerate(lines[1:], start=2):
|
|
59
|
+
row = line.strip().split(sep)
|
|
60
|
+
if len(row) != len(headers):
|
|
61
|
+
warnings.warn(
|
|
62
|
+
f"Skipping line {i}: expected {len(headers)} fields, got {len(row)}"
|
|
63
|
+
)
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
# units row
|
|
67
|
+
if i == 2:
|
|
68
|
+
for col_name, value in zip(headers, row):
|
|
69
|
+
col_name = col_name.split(" ", 1)[0].strip()
|
|
70
|
+
data_dict[col_name]["unit"] = value.strip().strip('"')
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
# values rows
|
|
74
|
+
for col_name, value in zip(headers, row):
|
|
75
|
+
col_name = col_name.split(" ", 1)[0].strip()
|
|
76
|
+
data_dict[col_name]["values"].append(normalize_value(value))
|
|
77
|
+
|
|
78
|
+
# --- Step 4: convert lists to numpy arrays
|
|
79
|
+
for col, content in data_dict.items():
|
|
80
|
+
vals = content["values"]
|
|
81
|
+
try:
|
|
82
|
+
arr = np.array(vals, dtype=int)
|
|
83
|
+
data_dict[col]["values"] = arr
|
|
84
|
+
except ValueError:
|
|
85
|
+
try:
|
|
86
|
+
arr = np.array(vals, dtype=float)
|
|
87
|
+
data_dict[col]["values"] = arr
|
|
88
|
+
except ValueError:
|
|
89
|
+
data_dict[col]["values"] = np.array(vals, dtype=str)
|
|
90
|
+
|
|
91
|
+
ordered_data_dict = {}
|
|
92
|
+
for k in data_dict.keys():
|
|
93
|
+
ordered_data_dict[k] = {'values' : data_dict[k]['values'], 'unit' : data_dict[k]['unit'], 'description' : ''}
|
|
94
|
+
|
|
95
|
+
return ordered_data_dict
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stoneforge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.0b3
|
|
4
4
|
Summary: Geophysics equations, algorithms and methods
|
|
5
5
|
Author: GIECAR - UFF, Wagner M. Lupinacci, Fernando Vizeu, Fábio Júnior D Fernandes, José A. V. Dias, Mario M. Ramos, Jordan S. Cuno, João Vitor A. Estrella, Ana Carolina, Breno D. Chrispim
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,7 +21,6 @@ Requires-Dist: matplotlib>=3.10.0
|
|
|
21
21
|
Requires-Dist: pandas>=2.2.2
|
|
22
22
|
Requires-Dist: lightgbm>=4.5.0
|
|
23
23
|
Requires-Dist: ipympl>=0.8.4
|
|
24
|
-
Requires-Dist: ipykernel>=6.30.0
|
|
25
24
|
Dynamic: license-file
|
|
26
25
|
|
|
27
26
|
<p align="center">
|
|
@@ -4,16 +4,6 @@ MANIFEST.in
|
|
|
4
4
|
README.md
|
|
5
5
|
pyproject.toml
|
|
6
6
|
docs/conf.py
|
|
7
|
-
docs/_build/html/_sources/index.rst.txt
|
|
8
|
-
docs/_build/html/_sources/modules/petrophysics.rst.txt
|
|
9
|
-
docs/_build/html/_sources/modules/preprocessing.rst.txt
|
|
10
|
-
docs/_build/html/_sources/modules/pseudowells.rst.txt
|
|
11
|
-
docs/_build/html/_sources/modules/rockphysics.rst.txt
|
|
12
|
-
docs/_build/html/_sources/modules/machinelearning/classification.rst.txt
|
|
13
|
-
docs/_build/html/_sources/modules/machinelearning/index.rst.txt
|
|
14
|
-
docs/_build/html/_sources/modules/machinelearning/regression.rst.txt
|
|
15
|
-
docs/_build/html/_sources/usage/installation.rst.txt
|
|
16
|
-
docs/_build/html/_sources/usage/quickstart.rst.txt
|
|
17
7
|
stoneforge/__init__.py
|
|
18
8
|
stoneforge.egg-info/PKG-INFO
|
|
19
9
|
stoneforge.egg-info/SOURCES.txt
|
|
@@ -31,7 +21,8 @@ stoneforge/io/__init__.py
|
|
|
31
21
|
stoneforge/io/csv.py
|
|
32
22
|
stoneforge/io/dlisio_r.py
|
|
33
23
|
stoneforge/io/las2.py
|
|
34
|
-
stoneforge/io/
|
|
24
|
+
stoneforge/io/las3.py
|
|
25
|
+
stoneforge/io/tabr.py
|
|
35
26
|
stoneforge/machine_learning/__init__.py
|
|
36
27
|
stoneforge/machine_learning/classification/__init__.py
|
|
37
28
|
stoneforge/machine_learning/classification/evaluation.py
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
.. Stoneforge documentation master file, created by
|
|
2
|
-
sphinx-quickstart on Mon May 27 13:42:11 2024.
|
|
3
|
-
You can adapt this file completely to your liking, but it should at least
|
|
4
|
-
contain the root `toctree` directive.
|
|
5
|
-
|
|
6
|
-
Welcome to Stoneforge's documentation!
|
|
7
|
-
======================================
|
|
8
|
-
|
|
9
|
-
**Version**: 1.4
|
|
10
|
-
|
|
11
|
-
**Stoneforge** is a Python library for geophysics equations, algorithms and methods that also,
|
|
12
|
-
are used in the software Appy. It is linked to the GIECAR laboratory at the Universidade Federal
|
|
13
|
-
Fluminense (UFF) related to the Geology and Geophysics Departament (GGO), and its purpose is to teach
|
|
14
|
-
and develop routines in Python to solve geological and geophysical problems. Main APPy references are :footcite:t:`estrella2022sbgf,estrella2022seg`.
|
|
15
|
-
|
|
16
|
-
.. note::
|
|
17
|
-
This project is under active development as of May 2024.
|
|
18
|
-
|
|
19
|
-
.. toctree::
|
|
20
|
-
:maxdepth: 2
|
|
21
|
-
:caption: Contents:
|
|
22
|
-
|
|
23
|
-
usage/installation
|
|
24
|
-
usage/quickstart
|
|
25
|
-
|
|
26
|
-
modules/petrophysics
|
|
27
|
-
modules/rockphysics
|
|
28
|
-
modules/pseudowells
|
|
29
|
-
modules/machinelearning/index
|
|
30
|
-
modules/preprocessing
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Indices and tables
|
|
34
|
-
==================
|
|
35
|
-
|
|
36
|
-
* :ref:`genindex`
|
|
37
|
-
* :ref:`modindex`
|
|
38
|
-
* :ref:`search`
|
|
39
|
-
|
|
40
|
-
References
|
|
41
|
-
----------------
|
|
42
|
-
|
|
43
|
-
.. footbibliography::
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
=========================
|
|
2
|
-
Classification
|
|
3
|
-
=========================
|
|
4
|
-
|
|
5
|
-
This section contains documentation for the Classification module (Machine learning).
|
|
6
|
-
|
|
7
|
-
.. automodule:: stoneforge.machine_learning.classification
|
|
8
|
-
:members:
|
|
9
|
-
:undoc-members:
|
|
10
|
-
:show-inheritance:
|
|
11
|
-
|
|
12
|
-
Settings (Classification)
|
|
13
|
-
--------------------------------
|
|
14
|
-
|
|
15
|
-
.. automodule:: stoneforge.machine_learning.classification.settings
|
|
16
|
-
:members:
|
|
17
|
-
:undoc-members:
|
|
18
|
-
:show-inheritance:
|
|
19
|
-
|
|
20
|
-
Fit (Classification)
|
|
21
|
-
--------------------------------
|
|
22
|
-
|
|
23
|
-
.. automodule:: stoneforge.machine_learning.classification.fit
|
|
24
|
-
:members:
|
|
25
|
-
:undoc-members:
|
|
26
|
-
:show-inheritance:
|
|
27
|
-
|
|
28
|
-
Predict (Classification)
|
|
29
|
-
--------------------------------
|
|
30
|
-
|
|
31
|
-
.. automodule:: stoneforge.machine_learning.classification.predict
|
|
32
|
-
:members:
|
|
33
|
-
:undoc-members:
|
|
34
|
-
:show-inheritance:
|
|
35
|
-
|
|
36
|
-
References
|
|
37
|
-
--------------------------------
|
|
38
|
-
|
|
39
|
-
.. footbibliography::
|