subsurface-terra 2025.1.0rc14__py3-none-any.whl → 2025.1.0rc16__py3-none-any.whl
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.
- subsurface/__init__.py +31 -31
- subsurface/_version.py +34 -21
- subsurface/api/__init__.py +13 -13
- subsurface/api/interfaces/__init__.py +3 -3
- subsurface/api/interfaces/stream.py +136 -136
- subsurface/api/reader/read_wells.py +78 -78
- subsurface/core/geological_formats/boreholes/_combine_trajectories.py +117 -117
- subsurface/core/geological_formats/boreholes/_map_attrs_to_survey.py +236 -0
- subsurface/core/geological_formats/boreholes/_survey_to_unstruct.py +163 -0
- subsurface/core/geological_formats/boreholes/boreholes.py +140 -116
- subsurface/core/geological_formats/boreholes/collars.py +26 -26
- subsurface/core/geological_formats/boreholes/survey.py +86 -380
- subsurface/core/geological_formats/fault.py +47 -47
- subsurface/core/reader_helpers/reader_unstruct.py +11 -11
- subsurface/core/reader_helpers/readers_data.py +130 -130
- subsurface/core/reader_helpers/readers_wells.py +13 -13
- subsurface/core/structs/__init__.py +3 -3
- subsurface/core/structs/base_structures/__init__.py +2 -2
- subsurface/core/structs/base_structures/_liquid_earth_mesh.py +121 -121
- subsurface/core/structs/base_structures/_unstructured_data_constructor.py +70 -70
- subsurface/core/structs/base_structures/base_structures_enum.py +6 -6
- subsurface/core/structs/base_structures/structured_data.py +282 -282
- subsurface/core/structs/base_structures/unstructured_data.py +319 -319
- subsurface/core/structs/structured_elements/octree_mesh.py +10 -10
- subsurface/core/structs/structured_elements/structured_grid.py +59 -59
- subsurface/core/structs/structured_elements/structured_mesh.py +9 -9
- subsurface/core/structs/unstructured_elements/__init__.py +3 -3
- subsurface/core/structs/unstructured_elements/line_set.py +72 -72
- subsurface/core/structs/unstructured_elements/point_set.py +43 -43
- subsurface/core/structs/unstructured_elements/tetrahedron_mesh.py +35 -35
- subsurface/core/structs/unstructured_elements/triangular_surface.py +62 -62
- subsurface/core/utils/utils_core.py +38 -38
- subsurface/modules/reader/__init__.py +13 -13
- subsurface/modules/reader/faults/faults.py +80 -80
- subsurface/modules/reader/from_binary.py +46 -46
- subsurface/modules/reader/mesh/_GOCAD_mesh.py +82 -82
- subsurface/modules/reader/mesh/_trimesh_reader.py +447 -447
- subsurface/modules/reader/mesh/csv_mesh_reader.py +53 -53
- subsurface/modules/reader/mesh/dxf_reader.py +177 -177
- subsurface/modules/reader/mesh/glb_reader.py +30 -30
- subsurface/modules/reader/mesh/mx_reader.py +232 -232
- subsurface/modules/reader/mesh/obj_reader.py +53 -53
- subsurface/modules/reader/mesh/omf_mesh_reader.py +43 -43
- subsurface/modules/reader/mesh/surface_reader.py +56 -56
- subsurface/modules/reader/mesh/surfaces_api.py +41 -41
- subsurface/modules/reader/profiles/__init__.py +3 -3
- subsurface/modules/reader/profiles/profiles_core.py +197 -197
- subsurface/modules/reader/read_netcdf.py +38 -38
- subsurface/modules/reader/topography/__init__.py +7 -7
- subsurface/modules/reader/topography/topo_core.py +100 -100
- subsurface/modules/reader/volume/read_grav3d.py +478 -428
- subsurface/modules/reader/volume/read_volume.py +327 -230
- subsurface/modules/reader/volume/segy_reader.py +105 -105
- subsurface/modules/reader/volume/seismic.py +173 -173
- subsurface/modules/reader/volume/volume_utils.py +43 -43
- subsurface/modules/reader/wells/DEP/__init__.py +43 -43
- subsurface/modules/reader/wells/DEP/_well_files_reader.py +167 -167
- subsurface/modules/reader/wells/DEP/_wells_api.py +61 -61
- subsurface/modules/reader/wells/DEP/_welly_reader.py +180 -180
- subsurface/modules/reader/wells/DEP/pandas_to_welly.py +212 -212
- subsurface/modules/reader/wells/_read_to_df.py +57 -57
- subsurface/modules/reader/wells/read_borehole_interface.py +148 -148
- subsurface/modules/reader/wells/wells_utils.py +68 -68
- subsurface/modules/tools/mocking_aux.py +104 -104
- subsurface/modules/visualization/__init__.py +2 -2
- subsurface/modules/visualization/to_pyvista.py +320 -320
- subsurface/modules/writer/to_binary.py +12 -12
- subsurface/modules/writer/to_rex/common.py +78 -78
- subsurface/modules/writer/to_rex/data_struct.py +74 -74
- subsurface/modules/writer/to_rex/gempy_to_rexfile.py +791 -791
- subsurface/modules/writer/to_rex/material_encoder.py +44 -44
- subsurface/modules/writer/to_rex/mesh_encoder.py +152 -152
- subsurface/modules/writer/to_rex/to_rex.py +115 -115
- subsurface/modules/writer/to_rex/utils.py +15 -15
- subsurface/optional_requirements.py +116 -116
- {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/METADATA +194 -194
- subsurface_terra-2025.1.0rc16.dist-info/RECORD +98 -0
- {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/WHEEL +1 -1
- {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/licenses/LICENSE +203 -203
- subsurface_terra-2025.1.0rc14.dist-info/RECORD +0 -96
- {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/top_level.txt +0 -0
|
@@ -1,116 +1,140 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import pandas as pd
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import Hashable
|
|
5
|
-
|
|
6
|
-
from ._combine_trajectories import create_combined_trajectory, MergeOptions
|
|
7
|
-
from .collars import Collars
|
|
8
|
-
from .survey import Survey
|
|
9
|
-
from ...structs import LineSet
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@dataclass
|
|
13
|
-
class BoreholeSet:
|
|
14
|
-
"""
|
|
15
|
-
This module provides a class, `BoreholeSet`, that represents a collection of boreholes. It contains methods for accessing coordinate data for each lithology in the boreholes.
|
|
16
|
-
|
|
17
|
-
Notes:
|
|
18
|
-
- Collars is defined as 1 UnstructuredData
|
|
19
|
-
- Combined trajectory is defined as 1 UnstructuredData
|
|
20
|
-
|
|
21
|
-
Classes:
|
|
22
|
-
- `BoreholeSet`: Represents a collection of boreholes.
|
|
23
|
-
|
|
24
|
-
Methods:
|
|
25
|
-
- `__init__`: Initializes a new `BoreholeSet` object with the specified input parameters.
|
|
26
|
-
- `get_top_coords_for_each_lith`: Returns a dictionary of top coordinates for each lithology in the boreholes.
|
|
27
|
-
- `get_bottom_coords_for_each_lith`: Returns a dictionary of bottom coordinates for each lithology in the boreholes.
|
|
28
|
-
|
|
29
|
-
Attributes:
|
|
30
|
-
- `collars`: A `Collars` object representing the collar information for the boreholes.
|
|
31
|
-
- `survey`: A `Survey` object representing the survey information for the boreholes.
|
|
32
|
-
- `combined_trajectory`: A `LineSet` object representing the combined trajectory of the boreholes.
|
|
33
|
-
|
|
34
|
-
Usage:
|
|
35
|
-
```
|
|
36
|
-
borehole_set = BoreholeSet(collars, survey, merge_option)
|
|
37
|
-
top_coords = borehole_set.get_top_coords_for_each_lith()
|
|
38
|
-
bottom_coords = borehole_set.get_bottom_coords_for_each_lith()
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Note: The example usage code provided above is for demonstration purposes only. Please replace `collars`, `survey`, and `merge_option` with the actual input parameters when using the `BoreholeSet` class.
|
|
42
|
-
|
|
43
|
-
"""
|
|
44
|
-
__slots__ = ['collars', 'survey', 'combined_trajectory']
|
|
45
|
-
collars: Collars
|
|
46
|
-
survey: Survey
|
|
47
|
-
combined_trajectory: LineSet
|
|
48
|
-
|
|
49
|
-
def __init__(self, collars: Collars, survey: Survey, merge_option: MergeOptions, slice_=slice(None)):
|
|
50
|
-
|
|
51
|
-
new_collars = self._remap_collars_with_survey(collars, survey)
|
|
52
|
-
|
|
53
|
-
self.collars = new_collars
|
|
54
|
-
self.survey = survey
|
|
55
|
-
self.combined_trajectory: LineSet = create_combined_trajectory(collars, survey, merge_option, slice_)
|
|
56
|
-
|
|
57
|
-
@staticmethod
|
|
58
|
-
def _remap_collars_with_survey(collars, survey):
|
|
59
|
-
import pandas as pd
|
|
60
|
-
# Create a DataFrame from your first list
|
|
61
|
-
df1 = pd.DataFrame({'name': collars.ids, 'x': collars.data.vertex[:, 0], 'y': collars.data.vertex[:, 1], 'z': collars.data.vertex[:, 2]})
|
|
62
|
-
df1 = df1.set_index('name')
|
|
63
|
-
# Reindex to match the second list of names
|
|
64
|
-
df_reindexed = df1.reindex(survey.well_id_mapper.keys())
|
|
65
|
-
new_collars = Collars.from_df(df_reindexed)
|
|
66
|
-
return new_collars
|
|
67
|
-
|
|
68
|
-
def to_binary(self, path: str) -> bool:
|
|
69
|
-
# I need to implement the survey to and then name the files accordingly
|
|
70
|
-
bytearray_le_collars: bytes = self.collars.data.to_binary()
|
|
71
|
-
bytearray_le_trajectory: bytes = self.combined_trajectory.data.to_binary()
|
|
72
|
-
|
|
73
|
-
new_file = open(f"{path}_collars.le", "wb")
|
|
74
|
-
new_file.write(bytearray_le_collars)
|
|
75
|
-
|
|
76
|
-
new_file = open(f"{path}_trajectory.le", "wb")
|
|
77
|
-
new_file.write(bytearray_le_trajectory)
|
|
78
|
-
return True
|
|
79
|
-
|
|
80
|
-
def get_top_coords_for_each_lith(self) -> dict[Hashable, np.ndarray]:
|
|
81
|
-
merged_df = self._merge_vertex_data_arrays_to_dataframe()
|
|
82
|
-
component_lith_arrays = {}
|
|
83
|
-
for lith, group in merged_df.groupby('lith_ids'):
|
|
84
|
-
lith = int(lith)
|
|
85
|
-
first_vertices = group.groupby('well_id').first().reset_index()
|
|
86
|
-
array = first_vertices[['X', 'Y', 'Z']].values
|
|
87
|
-
component_lith_arrays[lith] = array
|
|
88
|
-
|
|
89
|
-
return component_lith_arrays
|
|
90
|
-
|
|
91
|
-
def get_bottom_coords_for_each_lith(self) -> dict[Hashable, np.ndarray]:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
for
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Hashable, Literal
|
|
5
|
+
|
|
6
|
+
from ._combine_trajectories import create_combined_trajectory, MergeOptions
|
|
7
|
+
from .collars import Collars
|
|
8
|
+
from .survey import Survey
|
|
9
|
+
from ...structs import LineSet
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class BoreholeSet:
|
|
14
|
+
"""
|
|
15
|
+
This module provides a class, `BoreholeSet`, that represents a collection of boreholes. It contains methods for accessing coordinate data for each lithology in the boreholes.
|
|
16
|
+
|
|
17
|
+
Notes:
|
|
18
|
+
- Collars is defined as 1 UnstructuredData
|
|
19
|
+
- Combined trajectory is defined as 1 UnstructuredData
|
|
20
|
+
|
|
21
|
+
Classes:
|
|
22
|
+
- `BoreholeSet`: Represents a collection of boreholes.
|
|
23
|
+
|
|
24
|
+
Methods:
|
|
25
|
+
- `__init__`: Initializes a new `BoreholeSet` object with the specified input parameters.
|
|
26
|
+
- `get_top_coords_for_each_lith`: Returns a dictionary of top coordinates for each lithology in the boreholes.
|
|
27
|
+
- `get_bottom_coords_for_each_lith`: Returns a dictionary of bottom coordinates for each lithology in the boreholes.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
- `collars`: A `Collars` object representing the collar information for the boreholes.
|
|
31
|
+
- `survey`: A `Survey` object representing the survey information for the boreholes.
|
|
32
|
+
- `combined_trajectory`: A `LineSet` object representing the combined trajectory of the boreholes.
|
|
33
|
+
|
|
34
|
+
Usage:
|
|
35
|
+
```
|
|
36
|
+
borehole_set = BoreholeSet(collars, survey, merge_option)
|
|
37
|
+
top_coords = borehole_set.get_top_coords_for_each_lith()
|
|
38
|
+
bottom_coords = borehole_set.get_bottom_coords_for_each_lith()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Note: The example usage code provided above is for demonstration purposes only. Please replace `collars`, `survey`, and `merge_option` with the actual input parameters when using the `BoreholeSet` class.
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
__slots__ = ['collars', 'survey', 'combined_trajectory']
|
|
45
|
+
collars: Collars
|
|
46
|
+
survey: Survey
|
|
47
|
+
combined_trajectory: LineSet
|
|
48
|
+
|
|
49
|
+
def __init__(self, collars: Collars, survey: Survey, merge_option: MergeOptions, slice_=slice(None)):
|
|
50
|
+
|
|
51
|
+
new_collars = self._remap_collars_with_survey(collars, survey)
|
|
52
|
+
|
|
53
|
+
self.collars = new_collars
|
|
54
|
+
self.survey = survey
|
|
55
|
+
self.combined_trajectory: LineSet = create_combined_trajectory(collars, survey, merge_option, slice_)
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def _remap_collars_with_survey(collars, survey):
|
|
59
|
+
import pandas as pd
|
|
60
|
+
# Create a DataFrame from your first list
|
|
61
|
+
df1 = pd.DataFrame({'name': collars.ids, 'x': collars.data.vertex[:, 0], 'y': collars.data.vertex[:, 1], 'z': collars.data.vertex[:, 2]})
|
|
62
|
+
df1 = df1.set_index('name')
|
|
63
|
+
# Reindex to match the second list of names
|
|
64
|
+
df_reindexed = df1.reindex(survey.well_id_mapper.keys())
|
|
65
|
+
new_collars = Collars.from_df(df_reindexed)
|
|
66
|
+
return new_collars
|
|
67
|
+
|
|
68
|
+
def to_binary(self, path: str) -> bool:
|
|
69
|
+
# I need to implement the survey to and then name the files accordingly
|
|
70
|
+
bytearray_le_collars: bytes = self.collars.data.to_binary()
|
|
71
|
+
bytearray_le_trajectory: bytes = self.combined_trajectory.data.to_binary()
|
|
72
|
+
|
|
73
|
+
new_file = open(f"{path}_collars.le", "wb")
|
|
74
|
+
new_file.write(bytearray_le_collars)
|
|
75
|
+
|
|
76
|
+
new_file = open(f"{path}_trajectory.le", "wb")
|
|
77
|
+
new_file.write(bytearray_le_trajectory)
|
|
78
|
+
return True
|
|
79
|
+
|
|
80
|
+
def get_top_coords_for_each_lith(self) -> dict[Hashable, np.ndarray]:
|
|
81
|
+
merged_df = self._merge_vertex_data_arrays_to_dataframe()
|
|
82
|
+
component_lith_arrays = {}
|
|
83
|
+
for lith, group in merged_df.groupby('lith_ids'):
|
|
84
|
+
lith = int(lith)
|
|
85
|
+
first_vertices = group.groupby('well_id').first().reset_index()
|
|
86
|
+
array = first_vertices[['X', 'Y', 'Z']].values
|
|
87
|
+
component_lith_arrays[lith] = array
|
|
88
|
+
|
|
89
|
+
return component_lith_arrays
|
|
90
|
+
|
|
91
|
+
def get_bottom_coords_for_each_lith(self, group_by: Literal['component lith', 'lith_ids'] = 'lith_ids') -> dict[Hashable, np.ndarray]:
|
|
92
|
+
"""
|
|
93
|
+
Retrieves the bottom coordinates for each lithological component or lith ID from
|
|
94
|
+
the merged vertex data arrays.
|
|
95
|
+
|
|
96
|
+
This function groups the merged data by either 'component lith' or 'lith_ids',
|
|
97
|
+
then extracts the coordinates of the bottommost vertices for each well. It
|
|
98
|
+
returns a dictionary where keys are either lithological component identifiers
|
|
99
|
+
or lith IDs, and values are arrays of 3D coordinates representing the bottom
|
|
100
|
+
vertices.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
group_by (Literal['component lith', 'lith_ids']): Specifies the grouping
|
|
104
|
+
column to use for lithological components. Acceptable values are either
|
|
105
|
+
'component lith' or 'lith_ids'. Defaults to 'lith_ids'.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
dict[Hashable, np.ndarray]: A dictionary mapping the lithological component
|
|
109
|
+
or lith ID to an array of 3D coordinates ([X, Y, Z]) corresponding to the
|
|
110
|
+
bottom vertices for each well.
|
|
111
|
+
|
|
112
|
+
Raises:
|
|
113
|
+
ValueError: If no groups are found from the specified `group_by` column.
|
|
114
|
+
"""
|
|
115
|
+
merged_df = self._merge_vertex_data_arrays_to_dataframe()
|
|
116
|
+
component_lith_arrays = {}
|
|
117
|
+
group = merged_df.groupby(group_by)
|
|
118
|
+
|
|
119
|
+
if group.ngroups == 0:
|
|
120
|
+
raise ValueError("No components found")
|
|
121
|
+
for lith, group in group:
|
|
122
|
+
lith = int(lith)
|
|
123
|
+
first_vertices = group.groupby('well_id').last().reset_index()
|
|
124
|
+
array = first_vertices[['X', 'Y', 'Z']].values
|
|
125
|
+
component_lith_arrays[lith] = array
|
|
126
|
+
|
|
127
|
+
return component_lith_arrays
|
|
128
|
+
|
|
129
|
+
def _merge_vertex_data_arrays_to_dataframe(self):
|
|
130
|
+
ds = self.combined_trajectory.data.data
|
|
131
|
+
# Convert vertex attributes to a DataFrame for easier manipulation
|
|
132
|
+
vertex_attrs_df = ds['vertex_attrs'].to_dataframe().reset_index()
|
|
133
|
+
vertex_attrs_df = vertex_attrs_df.pivot(index='points', columns='vertex_attr', values='vertex_attrs').reset_index()
|
|
134
|
+
# Convert vertex coordinates to a DataFrame
|
|
135
|
+
vertex_df = ds['vertex'].to_dataframe().reset_index()
|
|
136
|
+
vertex_df = vertex_df.pivot(index='points', columns='XYZ', values='vertex').reset_index()
|
|
137
|
+
# Merge the attributes with the vertex coordinates
|
|
138
|
+
merged_df = pd.merge(vertex_df, vertex_attrs_df, on='points')
|
|
139
|
+
# Create a dictionary to hold the numpy arrays for each component lith
|
|
140
|
+
return merged_df
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
|
|
4
|
-
from ...structs.base_structures import UnstructuredData
|
|
5
|
-
from ...structs.base_structures.base_structures_enum import SpecialCellCase
|
|
6
|
-
from ...structs.unstructured_elements import PointSet
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@dataclass
|
|
10
|
-
class Collars:
|
|
11
|
-
ids: list[str]
|
|
12
|
-
collar_loc: PointSet
|
|
13
|
-
|
|
14
|
-
@classmethod
|
|
15
|
-
def from_df(cls, df: pd.DataFrame):
|
|
16
|
-
unstruc: UnstructuredData = UnstructuredData.from_array(
|
|
17
|
-
vertex=df[["x", "y", "z"]].values,
|
|
18
|
-
cells=SpecialCellCase.POINTS
|
|
19
|
-
)
|
|
20
|
-
return cls(
|
|
21
|
-
ids=df.index.to_list(),
|
|
22
|
-
collar_loc=PointSet(data=unstruc)
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
def data(self):
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from ...structs.base_structures import UnstructuredData
|
|
5
|
+
from ...structs.base_structures.base_structures_enum import SpecialCellCase
|
|
6
|
+
from ...structs.unstructured_elements import PointSet
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Collars:
|
|
11
|
+
ids: list[str]
|
|
12
|
+
collar_loc: PointSet
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def from_df(cls, df: pd.DataFrame):
|
|
16
|
+
unstruc: UnstructuredData = UnstructuredData.from_array(
|
|
17
|
+
vertex=df[["x", "y", "z"]].values,
|
|
18
|
+
cells=SpecialCellCase.POINTS
|
|
19
|
+
)
|
|
20
|
+
return cls(
|
|
21
|
+
ids=df.index.to_list(),
|
|
22
|
+
collar_loc=PointSet(data=unstruc)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def data(self):
|
|
27
27
|
return self.collar_loc.data
|