subsurface-terra 2025.1.0rc15__py3-none-any.whl → 2025.1.0rc17__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.
Files changed (82) hide show
  1. subsurface/__init__.py +31 -31
  2. subsurface/_version.py +34 -21
  3. subsurface/api/__init__.py +13 -13
  4. subsurface/api/interfaces/__init__.py +3 -3
  5. subsurface/api/interfaces/stream.py +136 -136
  6. subsurface/api/reader/read_wells.py +78 -78
  7. subsurface/core/geological_formats/boreholes/_combine_trajectories.py +117 -117
  8. subsurface/core/geological_formats/boreholes/_map_attrs_to_survey.py +236 -234
  9. subsurface/core/geological_formats/boreholes/_survey_to_unstruct.py +163 -163
  10. subsurface/core/geological_formats/boreholes/boreholes.py +140 -140
  11. subsurface/core/geological_formats/boreholes/collars.py +26 -26
  12. subsurface/core/geological_formats/boreholes/survey.py +86 -86
  13. subsurface/core/geological_formats/fault.py +47 -47
  14. subsurface/core/reader_helpers/reader_unstruct.py +11 -11
  15. subsurface/core/reader_helpers/readers_data.py +130 -130
  16. subsurface/core/reader_helpers/readers_wells.py +13 -13
  17. subsurface/core/structs/__init__.py +3 -3
  18. subsurface/core/structs/base_structures/__init__.py +2 -2
  19. subsurface/core/structs/base_structures/_aux.py +69 -0
  20. subsurface/core/structs/base_structures/_liquid_earth_mesh.py +121 -121
  21. subsurface/core/structs/base_structures/_unstructured_data_constructor.py +70 -70
  22. subsurface/core/structs/base_structures/base_structures_enum.py +6 -6
  23. subsurface/core/structs/base_structures/structured_data.py +282 -282
  24. subsurface/core/structs/base_structures/unstructured_data.py +338 -319
  25. subsurface/core/structs/structured_elements/octree_mesh.py +10 -10
  26. subsurface/core/structs/structured_elements/structured_grid.py +59 -59
  27. subsurface/core/structs/structured_elements/structured_mesh.py +9 -9
  28. subsurface/core/structs/unstructured_elements/__init__.py +3 -3
  29. subsurface/core/structs/unstructured_elements/line_set.py +72 -72
  30. subsurface/core/structs/unstructured_elements/point_set.py +43 -43
  31. subsurface/core/structs/unstructured_elements/tetrahedron_mesh.py +35 -35
  32. subsurface/core/structs/unstructured_elements/triangular_surface.py +62 -62
  33. subsurface/core/utils/utils_core.py +38 -38
  34. subsurface/modules/reader/__init__.py +13 -13
  35. subsurface/modules/reader/faults/faults.py +80 -80
  36. subsurface/modules/reader/from_binary.py +46 -46
  37. subsurface/modules/reader/mesh/_GOCAD_mesh.py +82 -82
  38. subsurface/modules/reader/mesh/_trimesh_reader.py +447 -447
  39. subsurface/modules/reader/mesh/csv_mesh_reader.py +53 -53
  40. subsurface/modules/reader/mesh/dxf_reader.py +177 -177
  41. subsurface/modules/reader/mesh/glb_reader.py +30 -30
  42. subsurface/modules/reader/mesh/mx_reader.py +232 -232
  43. subsurface/modules/reader/mesh/obj_reader.py +53 -53
  44. subsurface/modules/reader/mesh/omf_mesh_reader.py +43 -43
  45. subsurface/modules/reader/mesh/surface_reader.py +56 -56
  46. subsurface/modules/reader/mesh/surfaces_api.py +41 -41
  47. subsurface/modules/reader/profiles/__init__.py +3 -3
  48. subsurface/modules/reader/profiles/profiles_core.py +197 -197
  49. subsurface/modules/reader/read_netcdf.py +38 -38
  50. subsurface/modules/reader/topography/__init__.py +7 -7
  51. subsurface/modules/reader/topography/topo_core.py +100 -100
  52. subsurface/modules/reader/volume/read_grav3d.py +447 -428
  53. subsurface/modules/reader/volume/read_volume.py +327 -230
  54. subsurface/modules/reader/volume/segy_reader.py +105 -105
  55. subsurface/modules/reader/volume/seismic.py +173 -173
  56. subsurface/modules/reader/volume/volume_utils.py +43 -43
  57. subsurface/modules/reader/wells/DEP/__init__.py +43 -43
  58. subsurface/modules/reader/wells/DEP/_well_files_reader.py +167 -167
  59. subsurface/modules/reader/wells/DEP/_wells_api.py +61 -61
  60. subsurface/modules/reader/wells/DEP/_welly_reader.py +180 -180
  61. subsurface/modules/reader/wells/DEP/pandas_to_welly.py +212 -212
  62. subsurface/modules/reader/wells/_read_to_df.py +57 -57
  63. subsurface/modules/reader/wells/read_borehole_interface.py +148 -148
  64. subsurface/modules/reader/wells/wells_utils.py +68 -68
  65. subsurface/modules/tools/mocking_aux.py +104 -104
  66. subsurface/modules/visualization/__init__.py +2 -2
  67. subsurface/modules/visualization/to_pyvista.py +320 -320
  68. subsurface/modules/writer/to_binary.py +12 -12
  69. subsurface/modules/writer/to_rex/common.py +78 -78
  70. subsurface/modules/writer/to_rex/data_struct.py +74 -74
  71. subsurface/modules/writer/to_rex/gempy_to_rexfile.py +791 -791
  72. subsurface/modules/writer/to_rex/material_encoder.py +44 -44
  73. subsurface/modules/writer/to_rex/mesh_encoder.py +152 -152
  74. subsurface/modules/writer/to_rex/to_rex.py +115 -115
  75. subsurface/modules/writer/to_rex/utils.py +15 -15
  76. subsurface/optional_requirements.py +116 -116
  77. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/METADATA +194 -194
  78. subsurface_terra-2025.1.0rc17.dist-info/RECORD +99 -0
  79. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/WHEEL +1 -1
  80. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/licenses/LICENSE +203 -203
  81. subsurface_terra-2025.1.0rc15.dist-info/RECORD +0 -98
  82. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/top_level.txt +0 -0
@@ -1,180 +1,180 @@
1
- import glob
2
- from typing import List
3
-
4
- import warnings
5
-
6
- from pandas import DataFrame
7
-
8
- from subsurface import optional_requirements
9
- from subsurface.reader.wells.pandas_to_welly import WellyToSubsurfaceHelper
10
- import numpy as np
11
-
12
- from subsurface.structs.base_structures import UnstructuredData
13
-
14
- welly = optional_requirements.require_welly()
15
- striplog = optional_requirements.require_striplog()
16
-
17
-
18
- def welly_to_subsurface(
19
- wts: WellyToSubsurfaceHelper,
20
- elev=True,
21
- n_vertex_per_well=50,
22
- convert_lith=True,
23
- table: List[striplog.Component] = None,
24
- **kwargs) -> UnstructuredData:
25
- """Method to convert well data to `subsurface.UnstructuredData`
26
-
27
- Args:
28
- elev (bool): In general the (x, y, z) array of positions will have
29
- z as TVD, which is positive down. If `elev` is True, positive
30
- will be upwards.
31
- n_vertex_per_well (int): Number of vertex used to describe the geometry of the
32
- well.
33
- return_element (bool): if True return a `subsurface.LineSet` instead
34
- convert_lith (bool): if True convert lith from stiplog to curve
35
- table (List[Striplog.Component]): List of components to map lithologies
36
- to value.
37
- **kwargs:
38
- `Well.location.trajectory` kwargs
39
-
40
- Returns:
41
-
42
- """
43
- vertex = np.zeros((0, 3))
44
- cells = np.zeros((0, 2), dtype=int)
45
-
46
- last_index = 0
47
- missed_wells = []
48
-
49
- for w in wts.p.get_wells():
50
- if well_without_valid_survey(w, missed_wells): continue
51
-
52
- cells, vertex, last_index = vertex_and_cells_from_welly_trajectory(
53
- cells, elev, kwargs, last_index, n_vertex_per_well, vertex, w)
54
-
55
- change_curve_basis_to_n_vertex_per_well_inplace(n_vertex_per_well, w, wts)
56
-
57
- # Convert striplog into Curve
58
- if convert_lith is True:
59
- if 'lith' in w.data:
60
- if table is None: table = wts.lith_component_table
61
- w.data['lith_log'] = striplog_to_curve_log(n_vertex_per_well, table, w, wts)
62
- else:
63
- w.data["lith_log"] = welly.Curve(-1 * np.ones(n_vertex_per_well - 1, dtype=int))
64
-
65
- if w.data["lith_log"].shape[0] != n_vertex_per_well - 1:
66
- raise ValueError("Cell_attr does not match cells")
67
-
68
- try:
69
- df = wts.p.df()
70
- except ValueError as e:
71
- if 'objects passed' in str(e):
72
- df = None
73
- else:
74
- raise ValueError
75
-
76
- print('The following boreholes failed being processed: ', missed_wells)
77
-
78
- unstructured_data = UnstructuredData.from_array(vertex, cells, df)
79
- return unstructured_data
80
-
81
-
82
- def striplog_to_curve_log(n_vertex_per_well, table, w: welly.Well, wts: WellyToSubsurfaceHelper) -> welly.Curve:
83
- start, stop, step_size = wts._calculate_basis_parameters(w, n_vertex_per_well - 1)
84
- s_log, basis, _table = w.data['lith'].to_log(step_size, start, stop, table=table, return_meta=True)
85
- return welly.Curve(s_log, basis)
86
-
87
-
88
- def change_curve_basis_to_n_vertex_per_well_inplace(n_points, w, wts):
89
- start, stop, step_size = wts._calculate_basis_parameters(w, n_points)
90
- basis = np.arange(start, stop, step_size)
91
- w.unify_basis(keys=None, basis=basis)
92
-
93
-
94
- def vertex_and_cells_from_welly_trajectory(
95
- cells: np.ndarray, elev: bool,
96
- welly_trajectory_kwargs: dict,
97
- last_index: int, n_vertex_for_well: int,
98
- vertex: np.ndarray, w: welly.Well):
99
- try:
100
- datum = w.location.datum
101
- except AttributeError:
102
- datum = None
103
-
104
- xyz = w.location.trajectory(datum=datum, elev=elev, points=n_vertex_for_well, **welly_trajectory_kwargs) # w.location.position
105
- # Make sure deviation is there
106
- a = np.arange(0 + last_index, xyz.shape[0] - 1 + last_index, dtype=np.int_)
107
- b = np.arange(1 + last_index, xyz.shape[0] + last_index, dtype=np.int_)
108
- cells_b = np.vstack([a, b]).T
109
-
110
- vertex = np.vstack((vertex, xyz))
111
- cells = np.vstack((cells, cells_b))
112
- last_index += xyz.shape[0]
113
-
114
- return cells, vertex, last_index
115
-
116
-
117
- def well_without_valid_survey(w: welly.Well, missed_wells: List[str]):
118
- well_without_position = w.location.position is None
119
- if well_without_position:
120
- warnings.warn(f'At least one of the wells do not have '
121
- 'assigned a survey. Borehole name: {w.name}')
122
- missed_wells.append(w.name)
123
- return well_without_position
124
-
125
-
126
- def _create_welly_well_from_las(well_name: str, las_folder: str):
127
- """
128
- Add well from welly las file.
129
-
130
- Args:
131
- well_name (str): Well name
132
- las_folder (str): Path to las file
133
-
134
- Returns:
135
-
136
- """
137
-
138
- def _create_well(uwi: str = 'dummy_uwi'):
139
- w = welly.Well()
140
- w.location.uwi = well_name
141
- w.location.name = well_name
142
-
143
- return w
144
-
145
- well = _create_well(well_name)
146
- return add_curves_from_las(well, las_folder)
147
-
148
-
149
- def add_curves_from_las(w: welly.Well, las_folder: str) -> welly.Well:
150
- """ Add curves from las file. """
151
-
152
- def _read_curves_to_welly_object(well: welly.Well, curve_path: str = '.') -> welly.Well:
153
- las_files = glob.glob(curve_path + '*.las')
154
- # throw error if no las files found
155
- if len(las_files) == 0:
156
- raise Exception('No las files found in ' + curve_path)
157
-
158
- for curve in las_files:
159
- well.add_curves_from_las(curve)
160
- return well
161
-
162
- _read_curves_to_welly_object(w, curve_path=las_folder)
163
-
164
- w_df = w.df()
165
- deviation_df = _make_deviation_df(w_df, inclination_header='IMG_INCL', azimuth_header='IMG_AZ')
166
- w.location.add_deviation(deviation_df)
167
- return w
168
-
169
-
170
- def _make_deviation_df(well_df: DataFrame, inclination_header: str, azimuth_header: str,
171
- depth_header: str = '', depth_index=True):
172
- if depth_index:
173
- deviation_data = well_df[[inclination_header, azimuth_header]].to_numpy()
174
- deviation_index = well_df.index.to_numpy()
175
- deviation_complete = np.insert(deviation_data, 0, deviation_index, axis=1)
176
- deviation_complete = deviation_complete[~np.isnan(deviation_complete).any(axis=1), :]
177
- else:
178
- deviation_complete = well_df[[depth_header, inclination_header, azimuth_header]].to_numpy()
179
- deviation_complete = deviation_complete[~np.isnan(deviation_complete).any(axis=1), :]
180
- return deviation_complete
1
+ import glob
2
+ from typing import List
3
+
4
+ import warnings
5
+
6
+ from pandas import DataFrame
7
+
8
+ from subsurface import optional_requirements
9
+ from subsurface.reader.wells.pandas_to_welly import WellyToSubsurfaceHelper
10
+ import numpy as np
11
+
12
+ from subsurface.structs.base_structures import UnstructuredData
13
+
14
+ welly = optional_requirements.require_welly()
15
+ striplog = optional_requirements.require_striplog()
16
+
17
+
18
+ def welly_to_subsurface(
19
+ wts: WellyToSubsurfaceHelper,
20
+ elev=True,
21
+ n_vertex_per_well=50,
22
+ convert_lith=True,
23
+ table: List[striplog.Component] = None,
24
+ **kwargs) -> UnstructuredData:
25
+ """Method to convert well data to `subsurface.UnstructuredData`
26
+
27
+ Args:
28
+ elev (bool): In general the (x, y, z) array of positions will have
29
+ z as TVD, which is positive down. If `elev` is True, positive
30
+ will be upwards.
31
+ n_vertex_per_well (int): Number of vertex used to describe the geometry of the
32
+ well.
33
+ return_element (bool): if True return a `subsurface.LineSet` instead
34
+ convert_lith (bool): if True convert lith from stiplog to curve
35
+ table (List[Striplog.Component]): List of components to map lithologies
36
+ to value.
37
+ **kwargs:
38
+ `Well.location.trajectory` kwargs
39
+
40
+ Returns:
41
+
42
+ """
43
+ vertex = np.zeros((0, 3))
44
+ cells = np.zeros((0, 2), dtype=int)
45
+
46
+ last_index = 0
47
+ missed_wells = []
48
+
49
+ for w in wts.p.get_wells():
50
+ if well_without_valid_survey(w, missed_wells): continue
51
+
52
+ cells, vertex, last_index = vertex_and_cells_from_welly_trajectory(
53
+ cells, elev, kwargs, last_index, n_vertex_per_well, vertex, w)
54
+
55
+ change_curve_basis_to_n_vertex_per_well_inplace(n_vertex_per_well, w, wts)
56
+
57
+ # Convert striplog into Curve
58
+ if convert_lith is True:
59
+ if 'lith' in w.data:
60
+ if table is None: table = wts.lith_component_table
61
+ w.data['lith_log'] = striplog_to_curve_log(n_vertex_per_well, table, w, wts)
62
+ else:
63
+ w.data["lith_log"] = welly.Curve(-1 * np.ones(n_vertex_per_well - 1, dtype=int))
64
+
65
+ if w.data["lith_log"].shape[0] != n_vertex_per_well - 1:
66
+ raise ValueError("Cell_attr does not match cells")
67
+
68
+ try:
69
+ df = wts.p.df()
70
+ except ValueError as e:
71
+ if 'objects passed' in str(e):
72
+ df = None
73
+ else:
74
+ raise ValueError
75
+
76
+ print('The following boreholes failed being processed: ', missed_wells)
77
+
78
+ unstructured_data = UnstructuredData.from_array(vertex, cells, df)
79
+ return unstructured_data
80
+
81
+
82
+ def striplog_to_curve_log(n_vertex_per_well, table, w: welly.Well, wts: WellyToSubsurfaceHelper) -> welly.Curve:
83
+ start, stop, step_size = wts._calculate_basis_parameters(w, n_vertex_per_well - 1)
84
+ s_log, basis, _table = w.data['lith'].to_log(step_size, start, stop, table=table, return_meta=True)
85
+ return welly.Curve(s_log, basis)
86
+
87
+
88
+ def change_curve_basis_to_n_vertex_per_well_inplace(n_points, w, wts):
89
+ start, stop, step_size = wts._calculate_basis_parameters(w, n_points)
90
+ basis = np.arange(start, stop, step_size)
91
+ w.unify_basis(keys=None, basis=basis)
92
+
93
+
94
+ def vertex_and_cells_from_welly_trajectory(
95
+ cells: np.ndarray, elev: bool,
96
+ welly_trajectory_kwargs: dict,
97
+ last_index: int, n_vertex_for_well: int,
98
+ vertex: np.ndarray, w: welly.Well):
99
+ try:
100
+ datum = w.location.datum
101
+ except AttributeError:
102
+ datum = None
103
+
104
+ xyz = w.location.trajectory(datum=datum, elev=elev, points=n_vertex_for_well, **welly_trajectory_kwargs) # w.location.position
105
+ # Make sure deviation is there
106
+ a = np.arange(0 + last_index, xyz.shape[0] - 1 + last_index, dtype=np.int_)
107
+ b = np.arange(1 + last_index, xyz.shape[0] + last_index, dtype=np.int_)
108
+ cells_b = np.vstack([a, b]).T
109
+
110
+ vertex = np.vstack((vertex, xyz))
111
+ cells = np.vstack((cells, cells_b))
112
+ last_index += xyz.shape[0]
113
+
114
+ return cells, vertex, last_index
115
+
116
+
117
+ def well_without_valid_survey(w: welly.Well, missed_wells: List[str]):
118
+ well_without_position = w.location.position is None
119
+ if well_without_position:
120
+ warnings.warn(f'At least one of the wells do not have '
121
+ 'assigned a survey. Borehole name: {w.name}')
122
+ missed_wells.append(w.name)
123
+ return well_without_position
124
+
125
+
126
+ def _create_welly_well_from_las(well_name: str, las_folder: str):
127
+ """
128
+ Add well from welly las file.
129
+
130
+ Args:
131
+ well_name (str): Well name
132
+ las_folder (str): Path to las file
133
+
134
+ Returns:
135
+
136
+ """
137
+
138
+ def _create_well(uwi: str = 'dummy_uwi'):
139
+ w = welly.Well()
140
+ w.location.uwi = well_name
141
+ w.location.name = well_name
142
+
143
+ return w
144
+
145
+ well = _create_well(well_name)
146
+ return add_curves_from_las(well, las_folder)
147
+
148
+
149
+ def add_curves_from_las(w: welly.Well, las_folder: str) -> welly.Well:
150
+ """ Add curves from las file. """
151
+
152
+ def _read_curves_to_welly_object(well: welly.Well, curve_path: str = '.') -> welly.Well:
153
+ las_files = glob.glob(curve_path + '*.las')
154
+ # throw error if no las files found
155
+ if len(las_files) == 0:
156
+ raise Exception('No las files found in ' + curve_path)
157
+
158
+ for curve in las_files:
159
+ well.add_curves_from_las(curve)
160
+ return well
161
+
162
+ _read_curves_to_welly_object(w, curve_path=las_folder)
163
+
164
+ w_df = w.df()
165
+ deviation_df = _make_deviation_df(w_df, inclination_header='IMG_INCL', azimuth_header='IMG_AZ')
166
+ w.location.add_deviation(deviation_df)
167
+ return w
168
+
169
+
170
+ def _make_deviation_df(well_df: DataFrame, inclination_header: str, azimuth_header: str,
171
+ depth_header: str = '', depth_index=True):
172
+ if depth_index:
173
+ deviation_data = well_df[[inclination_header, azimuth_header]].to_numpy()
174
+ deviation_index = well_df.index.to_numpy()
175
+ deviation_complete = np.insert(deviation_data, 0, deviation_index, axis=1)
176
+ deviation_complete = deviation_complete[~np.isnan(deviation_complete).any(axis=1), :]
177
+ else:
178
+ deviation_complete = well_df[[depth_header, inclination_header, azimuth_header]].to_numpy()
179
+ deviation_complete = deviation_complete[~np.isnan(deviation_complete).any(axis=1), :]
180
+ return deviation_complete