lasmnemonicsid 0.0.1rc0__tar.gz → 0.0.3rc0__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 (23) hide show
  1. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/PKG-INFO +38 -11
  2. lasmnemonicsid-0.0.3rc0/README.md +72 -0
  3. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/pyproject.toml +1 -1
  4. lasmnemonicsid-0.0.3rc0/src/LASMnemonicsID/LAS/LAS.py +194 -0
  5. lasmnemonicsid-0.0.3rc0/src/LASMnemonicsID/LAS/__init__.py +13 -0
  6. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/LASMnemonicsID/utils/mnemonics.py +2 -0
  7. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/lasmnemonicsid.egg-info/PKG-INFO +38 -11
  8. lasmnemonicsid-0.0.3rc0/tests/test_las.py +42 -0
  9. lasmnemonicsid-0.0.1rc0/README.md +0 -45
  10. lasmnemonicsid-0.0.1rc0/src/LASMnemonicsID/LAS/LAS.py +0 -148
  11. lasmnemonicsid-0.0.1rc0/src/LASMnemonicsID/LAS/__init__.py +0 -12
  12. lasmnemonicsid-0.0.1rc0/tests/test_las.py +0 -63
  13. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/LICENSE +0 -0
  14. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/setup.cfg +0 -0
  15. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/LASMnemonicsID/DLIS/__init__.py +0 -0
  16. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/LASMnemonicsID/__init__.py +0 -0
  17. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/LASMnemonicsID/utils/__init__.py +0 -0
  18. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/lasmnemonicsid.egg-info/SOURCES.txt +0 -0
  19. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/lasmnemonicsid.egg-info/dependency_links.txt +0 -0
  20. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/lasmnemonicsid.egg-info/requires.txt +0 -0
  21. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/src/lasmnemonicsid.egg-info/top_level.txt +0 -0
  22. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/tests/test_dlis.py +0 -0
  23. {lasmnemonicsid-0.0.1rc0 → lasmnemonicsid-0.0.3rc0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lasmnemonicsid
3
- Version: 0.0.1rc0
3
+ Version: 0.0.3rc0
4
4
  Summary: Well log mnemonic identification using lasio and dlisio to load LAS/DLIS files into DataFrames
5
5
  Author-email: Nobleza Energy <info@nobleza-energy.com>
6
6
  License: MIT
@@ -36,7 +36,6 @@ Requires-Dist: flake8>=6.0.0; extra == "dev"
36
36
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
37
37
  Dynamic: license-file
38
38
 
39
-
40
39
  <p align="center">
41
40
  <img src="https://raw.githubusercontent.com/Nobleza-Energy/LASMnemonicsID/main/logo.png" alt="LASMnemonicsID Logo" width="200"/>
42
41
  </p>
@@ -61,10 +60,9 @@ Dynamic: license-file
61
60
  pip install lasmnemonicsid
62
61
  ```
63
62
 
64
-
65
-
66
63
  ## 🚀 QuickStart
67
- ```
64
+
65
+ ```python
68
66
  from LASMnemonicsID.LAS import parseLAS
69
67
 
70
68
  # Load LAS file
@@ -72,12 +70,41 @@ df = parseLAS("your_well.las")
72
70
  print(df.head())
73
71
  ```
74
72
 
75
- ## 🧪 Test with your Data
76
- ```
73
+ ## 🧪 Test with your Data: Multiple files will load into a dictionary
74
+
75
+ ```python
77
76
  from LASMnemonicsID.LAS import parseLAS
78
77
 
79
- # Load and inspect
80
- df = parseLAS("path/to/well.las")
81
- print(f"✅ {len(df)} rows, {len(df.columns)} curves")
82
- print(df.columns.tolist())
78
+ # Load all .las within the Directory → {filename: df}
79
+ data = parseLAS("/path/to/your/data/")
80
+ print("Files:", list(data.keys()))
81
+
82
+ # Dataframes
83
+ df = parseLAS('/path/to/yourfile.las')
84
+ print(df.head())
83
85
  ```
86
+
87
+ ## 📈 Star History
88
+
89
+ [![Star History Chart](https://api.star-history.com/svg?repos=Nobleza-Energy/LASMnemonicsID&type=Date)](https://star-history.com/#Nobleza-Energy/LASMnemonicsID&Date)
90
+
91
+
92
+ ## 📄 How to Cite
93
+
94
+ If you use `LASMnemonicsID` in your research or project, please cite it as follows:
95
+
96
+ **APA**
97
+
98
+ > Nobleza Energy. (2025). LASMnemonicsID: Well log mnemonic identification using lasio and dlisio [Software]. GitHub. https://github.com/Nobleza-Energy/LASMnemonicsID
99
+
100
+ **BibTeX**
101
+
102
+ ```bibtex
103
+ @software{LASMnemonicsID,
104
+ author = {Nobleza Energy},
105
+ title = {LASMnemonicsID: Well log mnemonic identification using lasio and dlisio},
106
+ year = {2025},
107
+ publisher = {GitHub},
108
+ journal = {GitHub repository},
109
+ url = {https://github.com/Nobleza-Energy/LASMnemonicsID}
110
+ }
@@ -0,0 +1,72 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/Nobleza-Energy/LASMnemonicsID/main/logo.png" alt="LASMnemonicsID Logo" width="200"/>
3
+ </p>
4
+
5
+ <h1 align="center">LASMnemonicsID</h1>
6
+
7
+ <p align="center">
8
+ <b>Well log mnemonic identification using lasio and dlisio</b>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://pypi.org/project/lasmnemonicsid/"><img src="https://img.shields.io/pypi/v/lasmnemonicsid.svg" alt="PyPI"></a>
13
+ <a href="https://pypi.org/project/lasmnemonicsid/"><img src="https://img.shields.io/pypi/pyversions/lasmnemonicsid.svg" alt="Python Versions"></a>
14
+ <a href="https://github.com/Nobleza-Energy/LASMnemonicsID/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Nobleza-Energy/LASMnemonicsID.svg" alt="License"></a>
15
+ </p>
16
+
17
+ ---
18
+
19
+ ## 📦 Installation
20
+
21
+ ```bash
22
+ pip install lasmnemonicsid
23
+ ```
24
+
25
+ ## 🚀 QuickStart
26
+
27
+ ```python
28
+ from LASMnemonicsID.LAS import parseLAS
29
+
30
+ # Load LAS file
31
+ df = parseLAS("your_well.las")
32
+ print(df.head())
33
+ ```
34
+
35
+ ## 🧪 Test with your Data: Multiple files will load into a dictionary
36
+
37
+ ```python
38
+ from LASMnemonicsID.LAS import parseLAS
39
+
40
+ # Load all .las within the Directory → {filename: df}
41
+ data = parseLAS("/path/to/your/data/")
42
+ print("Files:", list(data.keys()))
43
+
44
+ # Dataframes
45
+ df = parseLAS('/path/to/yourfile.las')
46
+ print(df.head())
47
+ ```
48
+
49
+ ## 📈 Star History
50
+
51
+ [![Star History Chart](https://api.star-history.com/svg?repos=Nobleza-Energy/LASMnemonicsID&type=Date)](https://star-history.com/#Nobleza-Energy/LASMnemonicsID&Date)
52
+
53
+
54
+ ## 📄 How to Cite
55
+
56
+ If you use `LASMnemonicsID` in your research or project, please cite it as follows:
57
+
58
+ **APA**
59
+
60
+ > Nobleza Energy. (2025). LASMnemonicsID: Well log mnemonic identification using lasio and dlisio [Software]. GitHub. https://github.com/Nobleza-Energy/LASMnemonicsID
61
+
62
+ **BibTeX**
63
+
64
+ ```bibtex
65
+ @software{LASMnemonicsID,
66
+ author = {Nobleza Energy},
67
+ title = {LASMnemonicsID: Well log mnemonic identification using lasio and dlisio},
68
+ year = {2025},
69
+ publisher = {GitHub},
70
+ journal = {GitHub repository},
71
+ url = {https://github.com/Nobleza-Energy/LASMnemonicsID}
72
+ }
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lasmnemonicsid"
7
- version = "0.0.1c" # ← NEW tag version
7
+ version = "0.0.3c"
8
8
  description = "Well log mnemonic identification using lasio and dlisio to load LAS/DLIS files into DataFrames"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -0,0 +1,194 @@
1
+ import LASMnemonicsID.utils.mnemonics as mnm
2
+ from LASMnemonicsID.utils.mnemonics import (
3
+ gamma_names,
4
+ sp_names,
5
+ caliper_names,
6
+ deepres_names,
7
+ rxo_names,
8
+ density_names,
9
+ density_correction_names,
10
+ neutron_names,
11
+ dtc_names,
12
+ dts_names,
13
+ pe_names,
14
+ )
15
+ import os
16
+ import pathlib
17
+ import pandas as pd
18
+ import lasio
19
+ from os.path import join
20
+ from sys import stdout
21
+ from pathlib import Path
22
+
23
+ # Function that creates the mnemonic dictionary
24
+ def create_mnemonic_dict(
25
+ gamma_names,
26
+ sp_names,
27
+ caliper_names,
28
+ deepres_names,
29
+ rxo_names,
30
+ density_names,
31
+ density_correction_names,
32
+ neutron_names,
33
+ dtc_names,
34
+ dts_names,
35
+ pe_names,
36
+ ):
37
+ """
38
+ Function that creates the mnemonic dictionary with the mnemonics per log type.
39
+ """
40
+ mnemonic_dict = {
41
+ "gamma": gamma_names,
42
+ "sp": sp_names,
43
+ "caliper": caliper_names,
44
+ "deepres": deepres_names,
45
+ "rxo": rxo_names,
46
+ "density": density_names,
47
+ "density_correction": density_correction_names,
48
+ "neutron": neutron_names,
49
+ "dtc": dtc_names,
50
+ "dts": dts_names,
51
+ "pe": pe_names,
52
+ }
53
+ return mnemonic_dict
54
+
55
+ def parseLAS(input_path, verbose=True, preferred_names=None):
56
+ """
57
+ Parse LAS file or all in directory → DataFrame or {filename: df}.
58
+
59
+ Args:
60
+ input_path (str/Path): LAS file or directory
61
+ verbose (bool): Print info
62
+ preferred_names (dict, optional): Mapping of curve types to preferred column names and preferred original columns.
63
+ Example: {"deepres": "RT", "deepres_preferred_original": "AT90", "gamma": "GR"}
64
+ If not provided, defaults to standard petrophysical names.
65
+
66
+ Returns:
67
+ DataFrame (single) or dict {filename: df} (multiple/dir)
68
+ """
69
+ input_path = Path(input_path)
70
+
71
+ # Define default standard names
72
+ std_names = {
73
+ "gamma": "GR",
74
+ "sp": "SP",
75
+ "caliper": "CALI",
76
+ "deepres": "RT",
77
+ "rxo": "RXO",
78
+ "density": "RHOB",
79
+ "density_correction": "DRHO",
80
+ "neutron": "NPHI",
81
+ "dtc": "DT",
82
+ "dts": "DTS",
83
+ "pe": "PEF"
84
+ }
85
+
86
+ # Update with user preferences if provided
87
+ if preferred_names:
88
+ std_names.update(preferred_names)
89
+
90
+ # Case 1: Single File
91
+ if input_path.is_file() and input_path.suffix.lower() == '.las':
92
+ df = _read_single_las(input_path, verbose, std_names)
93
+ return df if df is not None else None
94
+
95
+ # Case 2: Directory (Recursive)
96
+ las_files = list(input_path.rglob("*.las"))
97
+ if not las_files:
98
+ if verbose:
99
+ print(f"No LAS files found in {input_path}")
100
+ return {}
101
+
102
+ las_dict = {}
103
+ for las_file in las_files:
104
+ df = _read_single_las(las_file, verbose, std_names)
105
+ if df is not None:
106
+ filename = las_file.name
107
+ las_dict[filename] = df
108
+
109
+ # Return single DF if only 1 file found, else dict
110
+ if len(las_dict) == 1:
111
+ return next(iter(las_dict.values()))
112
+
113
+ return las_dict
114
+
115
+ def _read_single_las(las_file_path, verbose, std_names):
116
+ """Read single LAS file to DataFrame and standardize ALL curves."""
117
+ try:
118
+ las_data = lasio.read(las_file_path)
119
+ df = las_data.df()
120
+
121
+ if df is None or df.empty:
122
+ if verbose:
123
+ print(f"✗ Empty DataFrame: {las_file_path.name}")
124
+ return None
125
+
126
+ # Ensure index is depth (float)
127
+ df.index = df.index.astype(float)
128
+
129
+ # Standardize ALL curves (GR, RHOB, NPHI, etc.)
130
+ _standardize_all_curves(las_data, df, std_names)
131
+
132
+ if verbose:
133
+ print(f"✓ {las_file_path.name}")
134
+ return df
135
+
136
+ except lasio.exceptions.LASHeaderError as e:
137
+ if verbose:
138
+ print(f"✗ LASHeaderError in {las_file_path.name}: {e}")
139
+ except Exception as e:
140
+ if verbose:
141
+ print(f"✗ Error in {las_file_path.name}: {type(e).__name__}: {e}")
142
+ return None
143
+
144
+ def _get_well_name(las_file_path):
145
+ """Extract well name from LAS file"""
146
+ try:
147
+ las_data = lasio.read(las_file_path)
148
+ return str(las_data.well.WELL.value).strip()
149
+ except:
150
+ return las_file_path.stem
151
+
152
+ def _standardize_all_curves(las_data, df, std_names):
153
+ """
154
+ Rename ALL curves in the DataFrame to standard abbreviations
155
+ based on the mnemonic dictionary.
156
+ """
157
+ # 1. Get the dictionary of aliases
158
+ mnem_dict = create_mnemonic_dict(
159
+ gamma_names, sp_names, caliper_names, deepres_names, rxo_names,
160
+ density_names, density_correction_names, neutron_names,
161
+ dtc_names, dts_names, pe_names
162
+ )
163
+
164
+ # 2. Track which columns we've already renamed to avoid duplicates
165
+ renamed = set()
166
+
167
+ # 3. For each curve type, find all aliases in the file
168
+ for curve_type, aliases in mnem_dict.items():
169
+ # Find all matching columns in df
170
+ matching = [col for col in df.columns if col.lower() in [a.lower() for a in aliases]]
171
+
172
+ if not matching:
173
+ continue
174
+
175
+ # Use standard name if provided, otherwise use curve_type.upper()
176
+ target_name = std_names.get(curve_type, curve_type.upper())
177
+
178
+ # If a preferred original column is specified, use it
179
+ preferred_original = std_names.get(f"{curve_type}_preferred_original")
180
+
181
+ if preferred_original and preferred_original in matching:
182
+ # Rename preferred original to target_name
183
+ df.rename(columns={preferred_original: target_name}, inplace=True)
184
+ renamed.add(target_name)
185
+ else:
186
+ # Otherwise, pick the first matching alias
187
+ df.rename(columns={matching[0]: target_name}, inplace=True)
188
+ renamed.add(target_name)
189
+
190
+ # Remove all other matching columns
191
+ for col in matching:
192
+ if col != target_name and col in df.columns:
193
+ df.drop(columns=[col], inplace=True)
194
+
@@ -0,0 +1,13 @@
1
+ from .LAS import (
2
+ parseLAS,
3
+ create_mnemonic_dict,
4
+ _get_well_name,
5
+ _read_single_las # Keep helpers if needed
6
+ )
7
+
8
+ __all__ = [
9
+ "parseLAS",
10
+ "create_mnemonic_dict",
11
+ "_get_well_name",
12
+ "_read_single_las"
13
+ ]
@@ -153,6 +153,8 @@ gamma_names = [
153
153
  "idgr",
154
154
  "gr_stgc",
155
155
  "gr_edtc_s",
156
+ "gradx",
157
+ "grarfm"
156
158
  ]
157
159
 
158
160
  # For spontanous potential logs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lasmnemonicsid
3
- Version: 0.0.1rc0
3
+ Version: 0.0.3rc0
4
4
  Summary: Well log mnemonic identification using lasio and dlisio to load LAS/DLIS files into DataFrames
5
5
  Author-email: Nobleza Energy <info@nobleza-energy.com>
6
6
  License: MIT
@@ -36,7 +36,6 @@ Requires-Dist: flake8>=6.0.0; extra == "dev"
36
36
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
37
37
  Dynamic: license-file
38
38
 
39
-
40
39
  <p align="center">
41
40
  <img src="https://raw.githubusercontent.com/Nobleza-Energy/LASMnemonicsID/main/logo.png" alt="LASMnemonicsID Logo" width="200"/>
42
41
  </p>
@@ -61,10 +60,9 @@ Dynamic: license-file
61
60
  pip install lasmnemonicsid
62
61
  ```
63
62
 
64
-
65
-
66
63
  ## 🚀 QuickStart
67
- ```
64
+
65
+ ```python
68
66
  from LASMnemonicsID.LAS import parseLAS
69
67
 
70
68
  # Load LAS file
@@ -72,12 +70,41 @@ df = parseLAS("your_well.las")
72
70
  print(df.head())
73
71
  ```
74
72
 
75
- ## 🧪 Test with your Data
76
- ```
73
+ ## 🧪 Test with your Data: Multiple files will load into a dictionary
74
+
75
+ ```python
77
76
  from LASMnemonicsID.LAS import parseLAS
78
77
 
79
- # Load and inspect
80
- df = parseLAS("path/to/well.las")
81
- print(f"✅ {len(df)} rows, {len(df.columns)} curves")
82
- print(df.columns.tolist())
78
+ # Load all .las within the Directory → {filename: df}
79
+ data = parseLAS("/path/to/your/data/")
80
+ print("Files:", list(data.keys()))
81
+
82
+ # Dataframes
83
+ df = parseLAS('/path/to/yourfile.las')
84
+ print(df.head())
83
85
  ```
86
+
87
+ ## 📈 Star History
88
+
89
+ [![Star History Chart](https://api.star-history.com/svg?repos=Nobleza-Energy/LASMnemonicsID&type=Date)](https://star-history.com/#Nobleza-Energy/LASMnemonicsID&Date)
90
+
91
+
92
+ ## 📄 How to Cite
93
+
94
+ If you use `LASMnemonicsID` in your research or project, please cite it as follows:
95
+
96
+ **APA**
97
+
98
+ > Nobleza Energy. (2025). LASMnemonicsID: Well log mnemonic identification using lasio and dlisio [Software]. GitHub. https://github.com/Nobleza-Energy/LASMnemonicsID
99
+
100
+ **BibTeX**
101
+
102
+ ```bibtex
103
+ @software{LASMnemonicsID,
104
+ author = {Nobleza Energy},
105
+ title = {LASMnemonicsID: Well log mnemonic identification using lasio and dlisio},
106
+ year = {2025},
107
+ publisher = {GitHub},
108
+ journal = {GitHub repository},
109
+ url = {https://github.com/Nobleza-Energy/LASMnemonicsID}
110
+ }
@@ -0,0 +1,42 @@
1
+
2
+ import lasio
3
+ import pytest
4
+ import pandas as pd
5
+ from pathlib import Path
6
+ from LASMnemonicsID.LAS import parseLAS
7
+ from LASMnemonicsID.utils.mnemonics import (
8
+ gamma_names, density_names, neutron_names,
9
+ dtc_names, sp_names, caliper_names # All types
10
+ )
11
+ from LASMnemonicsID.utils.mnemonics import find_column
12
+
13
+
14
+ def test_parseLAS_single_folder():
15
+ """Test directory → {filename: df} dict."""
16
+ data_dir = Path(__file__).parent / 'data'
17
+ result = parseLAS(data_dir, verbose=False)
18
+ assert isinstance(result, dict)
19
+ assert len(result) >= 1 # Adaptive: any # files
20
+ first_df = next(iter(result.values()))
21
+ assert isinstance(first_df, pd.DataFrame)
22
+ assert len(first_df) > 0
23
+ assert 'GR' in first_df.columns # Standardization ✓
24
+
25
+
26
+ def test_parseLAS_empty_dir():
27
+ empty_path = Path(__file__).parent / 'empty_dir'
28
+ empty_path.mkdir(exist_ok=True)
29
+ result = parseLAS(empty_path, verbose=False)
30
+ assert result == {}
31
+ empty_path.rmdir() # Cleanup
32
+
33
+
34
+ def test_parseLAS_single_file():
35
+ """Test single file → DataFrame."""
36
+ data_dir = Path(__file__).parent / 'data'
37
+ sample_las_paths = list(data_dir.glob('*.las'))
38
+ first_file = sample_las_paths[0]
39
+ df = parseLAS(first_file, verbose=False)
40
+ assert isinstance(df, pd.DataFrame)
41
+ assert len(df) > 0
42
+ assert 'GR' in df.columns # Standardization ✓
@@ -1,45 +0,0 @@
1
-
2
- <p align="center">
3
- <img src="https://raw.githubusercontent.com/Nobleza-Energy/LASMnemonicsID/main/logo.png" alt="LASMnemonicsID Logo" width="200"/>
4
- </p>
5
-
6
- <h1 align="center">LASMnemonicsID</h1>
7
-
8
- <p align="center">
9
- <b>Well log mnemonic identification using lasio and dlisio</b>
10
- </p>
11
-
12
- <p align="center">
13
- <a href="https://pypi.org/project/lasmnemonicsid/"><img src="https://img.shields.io/pypi/v/lasmnemonicsid.svg" alt="PyPI"></a>
14
- <a href="https://pypi.org/project/lasmnemonicsid/"><img src="https://img.shields.io/pypi/pyversions/lasmnemonicsid.svg" alt="Python Versions"></a>
15
- <a href="https://github.com/Nobleza-Energy/LASMnemonicsID/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Nobleza-Energy/LASMnemonicsID.svg" alt="License"></a>
16
- </p>
17
-
18
- ---
19
-
20
- ## 📦 Installation
21
-
22
- ```bash
23
- pip install lasmnemonicsid
24
- ```
25
-
26
-
27
-
28
- ## 🚀 QuickStart
29
- ```
30
- from LASMnemonicsID.LAS import parseLAS
31
-
32
- # Load LAS file
33
- df = parseLAS("your_well.las")
34
- print(df.head())
35
- ```
36
-
37
- ## 🧪 Test with your Data
38
- ```
39
- from LASMnemonicsID.LAS import parseLAS
40
-
41
- # Load and inspect
42
- df = parseLAS("path/to/well.las")
43
- print(f"✅ {len(df)} rows, {len(df.columns)} curves")
44
- print(df.columns.tolist())
45
- ```
@@ -1,148 +0,0 @@
1
- import LASMnemonicsID.utils.mnemonics as mnm
2
- from LASMnemonicsID.utils.mnemonics import (
3
- gamma_names,
4
- sp_names,
5
- caliper_names,
6
- deepres_names,
7
- rxo_names,
8
- density_names,
9
- density_correction_names,
10
- neutron_names,
11
- dtc_names,
12
- dts_names,
13
- pe_names,
14
- )
15
- import os
16
- import pathlib
17
- import pandas as pd
18
- import lasio
19
- from os.path import join
20
- from sys import stdout
21
- from pathlib import Path
22
-
23
-
24
-
25
-
26
-
27
- # Function that create the mnemonic dictionary
28
- def create_mnemonic_dict(
29
- gamma_names,
30
- sp_names,
31
- caliper_names,
32
- deepres_names,
33
- rxo_names,
34
- density_names,
35
- density_correction_names,
36
- neutron_names,
37
- dtc_names,
38
- dts_names,
39
- pe_names,
40
- ):
41
- """
42
- Function that create the mnemonic dictionary with the mnemonics per log type in the utils module
43
- """
44
-
45
- mnemonic_dict = {
46
- "gamma": gamma_names,
47
- "sp": sp_names,
48
- "caliper": caliper_names,
49
- "deepres": deepres_names,
50
- "rxo": rxo_names,
51
- "density": density_names,
52
- "density_correction": density_correction_names,
53
- "neutron": neutron_names,
54
- "dtc": dtc_names,
55
- "dts": dts_names,
56
- "pe": pe_names,
57
- }
58
- return mnemonic_dict
59
-
60
-
61
-
62
- def parseLAS(directory_path, verbose=True):
63
- """
64
- Parse all LAS files in directory (recursive) into dict of DataFrames or single DataFrame.
65
-
66
- Args:
67
- directory_path (str/Path): Directory containing LAS files
68
- verbose (bool): Print processing info
69
-
70
- Returns:
71
- dict or DataFrame: {folder: {well: df}} or single df if one file found
72
- """
73
- directory_path = Path(directory_path)
74
- well_logs = {}
75
-
76
- # Find all LAS files recursively
77
- las_files = list(directory_path.rglob("*.las"))
78
-
79
- if not las_files:
80
- if verbose:
81
- print("No LAS files found.")
82
- return {}
83
-
84
- if len(las_files) == 1:
85
- # Return single DataFrame if only one file
86
- return _read_single_las(las_files[0], verbose)
87
-
88
- # Multiple files: group by parent folder
89
- for las_file in las_files:
90
- folder_name = las_file.parent.name
91
- if folder_name not in well_logs:
92
- well_logs[folder_name] = {}
93
-
94
- df = _read_single_las(las_file, verbose)
95
- if df is not None:
96
- well_name = _get_well_name(las_file)
97
- well_logs[folder_name][well_name] = df
98
-
99
- return well_logs
100
-
101
-
102
- def _read_single_las(las_file_path, verbose):
103
- """Read single LAS file to DataFrame"""
104
- try:
105
- las_data = lasio.read(las_file_path)
106
- df = las_data.df()
107
- if df is None or df.empty:
108
- if verbose:
109
- print(f"✗ Empty DataFrame: {las_file_path.name}")
110
- return None
111
-
112
- df.index = df.index.astype(float)
113
- # df.dropna(inplace=True)
114
-
115
- # Standardize GR curve
116
- _standardize_gr_curve(las_data, df)
117
-
118
- if verbose:
119
- print(f"✓ {las_file_path.name}")
120
- return df
121
-
122
- except lasio.exceptions.LASHeaderError as e:
123
- if verbose:
124
- print(f"✗ LASHeaderError in {las_file_path.name}: {e}")
125
- except Exception as e:
126
- if verbose:
127
- print(f"✗ Error in {las_file_path.name}: {type(e).__name__}: {e}")
128
- return None
129
-
130
-
131
- def _get_well_name(las_file_path):
132
- """Extract well name from LAS file"""
133
- try:
134
- las_data = lasio.read(las_file_path)
135
- return str(las_data.well.WELL.value).strip()
136
- except:
137
- return las_file_path.stem
138
-
139
-
140
- def _standardize_gr_curve(las_data, df):
141
- """Rename gamma ray curve to GR"""
142
- global gamma_names # Assuming gamma_names defined elsewhere
143
- for curve in las_data.curves:
144
- if curve.mnemonic.lower() in gamma_names:
145
- df.rename(columns={curve.mnemonic: "GR"}, inplace=True)
146
- break
147
-
148
-
@@ -1,12 +0,0 @@
1
- from .LAS import (
2
- parseLAS,
3
- create_mnemonic_dict,
4
- _read_single_las,
5
- _get_well_name,
6
- _standardize_gr_curve
7
- )
8
-
9
- __all__ = [
10
- 'parseLAS',
11
- 'create_mnemonic_dict'
12
- ]
@@ -1,63 +0,0 @@
1
- import lasio
2
- import pytest
3
- import pandas as pd
4
- from pathlib import Path
5
- from LASMnemonicsID.LAS import parseLAS
6
- from LASMnemonicsID.utils.mnemonics import (
7
- gamma_names, density_names, neutron_names,
8
- dtc_names, sp_names, caliper_names # All types
9
- )
10
- from LASMnemonicsID.utils.mnemonics import find_column
11
-
12
-
13
- def test_parseLAS_single_folder(sample_las_paths):
14
- result = parseLAS(sample_las_paths[0].parent, verbose=False)
15
- assert isinstance(result, dict)
16
- assert len(result) == 1 # 'data' folder
17
- wells = result['data']
18
- assert len(wells) >= 10 # Multiple unique wells now
19
- first_df = next(iter(wells.values()))
20
- assert isinstance(first_df, pd.DataFrame)
21
- assert len(first_df) > 0 # New files have data!
22
- assert 'GR' in first_df.columns # GR standardization
23
-
24
- def test_parseLAS_empty_dir():
25
- result = parseLAS(Path(__file__).parent / 'empty_dir', verbose=False)
26
- assert result == {}
27
-
28
-
29
-
30
- # Test for parsing all curves and identifying and renaming all of them into a new dataframe
31
- def test_parse_all_curves_first_file():
32
- data_dir = Path(__file__).parent / 'data'
33
- first_file = next(data_dir.glob('*.las'))
34
-
35
- print(f"🔍 Parsing {first_file.name} for ALL curves...")
36
- las_data = lasio.read(first_file)
37
- df = las_data.df()
38
-
39
- # Test ALL curve types with find_column (your utils logic)
40
- curve_types = {
41
- 'gamma': gamma_names,
42
- 'density': density_names,
43
- 'neutron': neutron_names,
44
- 'dtc': dtc_names,
45
- 'sp': sp_names,
46
- 'caliper': caliper_names
47
- }
48
-
49
- found_curves = {}
50
- for curve_type, names in curve_types.items():
51
- col = find_column(df, curve_type)
52
- found_curves[curve_type] = col
53
- status = "✅" if col else "❌"
54
- print(f"{status} {curve_type.upper()}: {col}")
55
-
56
- print(f"\n📊 DataFrame: {df.shape}")
57
- print("Columns:", list(df.columns[:20]), "...")
58
- print("\nHead:")
59
- print(df.head(10))
60
-
61
- # Assert key curves found
62
- assert found_curves['gamma'] # GR required
63
- assert len(df.columns) > 20