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.
Files changed (99) hide show
  1. {stoneforge-0.2.0b2/stoneforge.egg-info → stoneforge-0.2.0b3}/PKG-INFO +1 -2
  2. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/pyproject.toml +1 -2
  3. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/__init__.py +2 -0
  4. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/dlisio_r.py +65 -3
  5. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/las2.py +75 -4
  6. stoneforge-0.2.0b3/stoneforge/io/las3.py +180 -0
  7. stoneforge-0.2.0b3/stoneforge/io/tabr.py +95 -0
  8. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3/stoneforge.egg-info}/PKG-INFO +1 -2
  9. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/SOURCES.txt +2 -11
  10. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/requires.txt +0 -1
  11. stoneforge-0.2.0b2/docs/_build/html/_sources/index.rst.txt +0 -43
  12. stoneforge-0.2.0b2/docs/_build/html/_sources/modules/machinelearning/classification.rst.txt +0 -39
  13. stoneforge-0.2.0b2/docs/_build/html/_sources/modules/machinelearning/index.rst.txt +0 -10
  14. stoneforge-0.2.0b2/docs/_build/html/_sources/modules/machinelearning/regression.rst.txt +0 -39
  15. stoneforge-0.2.0b2/docs/_build/html/_sources/modules/petrophysics.rst.txt +0 -39
  16. stoneforge-0.2.0b2/docs/_build/html/_sources/modules/preprocessing.rst.txt +0 -28
  17. stoneforge-0.2.0b2/docs/_build/html/_sources/modules/pseudowells.rst.txt +0 -23
  18. stoneforge-0.2.0b2/docs/_build/html/_sources/modules/rockphysics.rst.txt +0 -47
  19. stoneforge-0.2.0b2/docs/_build/html/_sources/usage/installation.rst.txt +0 -40
  20. stoneforge-0.2.0b2/docs/_build/html/_sources/usage/quickstart.rst.txt +0 -28
  21. stoneforge-0.2.0b2/stoneforge/io/lasparser.py +0 -74
  22. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/CHANGELOG.txt +0 -0
  23. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/LICENSE +0 -0
  24. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/MANIFEST.in +0 -0
  25. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/README.md +0 -0
  26. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/docs/conf.py +0 -0
  27. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/setup.cfg +0 -0
  28. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/__init__.py +0 -0
  29. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/datasets/__init__.py +0 -0
  30. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/datasets/data_info.txt +0 -0
  31. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/datasets/dataload.py +0 -0
  32. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/__init__.py +0 -0
  33. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/regularized_acoustic_reflectivy_inversion.py +0 -0
  34. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/viability_study/__init__.py +0 -0
  35. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/inversion/viability_study/bayes.py +0 -0
  36. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/io/csv.py +0 -0
  37. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/__init__.py +0 -0
  38. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/__init__.py +0 -0
  39. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/evaluation.py +0 -0
  40. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/fit.py +0 -0
  41. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/predict.py +0 -0
  42. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/settings.py +0 -0
  43. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/classification/validation.py +0 -0
  44. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/__init__.py +0 -0
  45. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/evaluation.py +0 -0
  46. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/fit.py +0 -0
  47. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/predict.py +0 -0
  48. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/settings.py +0 -0
  49. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_classification/validation.py +0 -0
  50. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/__init__.py +0 -0
  51. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/evaluation.py +0 -0
  52. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/fit.py +0 -0
  53. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/predict.py +0 -0
  54. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/settings.py +0 -0
  55. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/mlp_regression/validation.py +0 -0
  56. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/__init__.py +0 -0
  57. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/evaluation.py +0 -0
  58. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/fit.py +0 -0
  59. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/mldr_project.py +0 -0
  60. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/predict.py +0 -0
  61. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/machine_learning/regression/settings.py +0 -0
  62. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/__init__.py +0 -0
  63. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/helpers.py +0 -0
  64. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/porosity.py +0 -0
  65. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/shale_volume.py +0 -0
  66. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/total_organic_carbon_content.py +0 -0
  67. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/petrophysics/water_saturation.py +0 -0
  68. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/__init__.py +0 -0
  69. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/data_management.py +0 -0
  70. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/data_processing.py +0 -0
  71. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/las2.py +0 -0
  72. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/preprocessing/las_pandas.py +0 -0
  73. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/__init__.py +0 -0
  74. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/lithology_generator.py +0 -0
  75. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/monte_carlo_simulations.py +0 -0
  76. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/pseudo_wells/pseudo_tools.py +0 -0
  77. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/__init__.py +0 -0
  78. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/elastic_constants.py +0 -0
  79. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/fluid_substitution.py +0 -0
  80. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/gem.py +0 -0
  81. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/inclusion.py +0 -0
  82. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/rock_physics/rock_physics_bounds.py +0 -0
  83. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/vis/__init__.py +0 -0
  84. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/vis/img.py +0 -0
  85. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/__init__.py +0 -0
  86. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/butterworth.py +0 -0
  87. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/ormsby.py +0 -0
  88. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge/wavelets/ricker.py +0 -0
  89. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/dependency_links.txt +0 -0
  90. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/stoneforge.egg-info/top_level.txt +0 -0
  91. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_ml/test_classification.py +0 -0
  92. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_ml/test_regression.py +0 -0
  93. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_porosity/parameters_p.py +0 -0
  94. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_porosity/test_porosity.py +0 -0
  95. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_rock_physics/test_elastic_constants.py +0 -0
  96. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_rock_physics/test_fluid_substitution.py +0 -0
  97. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_rock_physics/test_gem.py +0 -0
  98. {stoneforge-0.2.0b2 → stoneforge-0.2.0b3}/tests/tests_water_saturation/parameters_ws.py +0 -0
  99. {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.0b2
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.2"
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",
@@ -1,3 +1,5 @@
1
1
  from . import dlisio_r # noqa: F401
2
2
  from . import las2 # noqa: F401
3
+ from . import las3 # noqa: F401
4
+ from . import tabr # noqa: F401
3
5
  from . import csv # noqa: F401
@@ -37,7 +37,69 @@ class DLISAccess:
37
37
  return self.selected_header_df
38
38
 
39
39
  def get_info(self):
40
- return self.dlis_dict_headers
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
- 'unit': unit,
315
- 'values': values
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.0b2
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/lasparser.py
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
@@ -7,4 +7,3 @@ matplotlib>=3.10.0
7
7
  pandas>=2.2.2
8
8
  lightgbm>=4.5.0
9
9
  ipympl>=0.8.4
10
- ipykernel>=6.30.0
@@ -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::
@@ -1,10 +0,0 @@
1
- Machine Learning
2
- ================
3
-
4
- This section contains machine learning methods used in Stoneforge.
5
-
6
- .. toctree::
7
- :maxdepth: 1
8
-
9
- classification
10
- regression