subsurface-terra 2025.1.0rc15__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.
Files changed (81) 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/_liquid_earth_mesh.py +121 -121
  20. subsurface/core/structs/base_structures/_unstructured_data_constructor.py +70 -70
  21. subsurface/core/structs/base_structures/base_structures_enum.py +6 -6
  22. subsurface/core/structs/base_structures/structured_data.py +282 -282
  23. subsurface/core/structs/base_structures/unstructured_data.py +319 -319
  24. subsurface/core/structs/structured_elements/octree_mesh.py +10 -10
  25. subsurface/core/structs/structured_elements/structured_grid.py +59 -59
  26. subsurface/core/structs/structured_elements/structured_mesh.py +9 -9
  27. subsurface/core/structs/unstructured_elements/__init__.py +3 -3
  28. subsurface/core/structs/unstructured_elements/line_set.py +72 -72
  29. subsurface/core/structs/unstructured_elements/point_set.py +43 -43
  30. subsurface/core/structs/unstructured_elements/tetrahedron_mesh.py +35 -35
  31. subsurface/core/structs/unstructured_elements/triangular_surface.py +62 -62
  32. subsurface/core/utils/utils_core.py +38 -38
  33. subsurface/modules/reader/__init__.py +13 -13
  34. subsurface/modules/reader/faults/faults.py +80 -80
  35. subsurface/modules/reader/from_binary.py +46 -46
  36. subsurface/modules/reader/mesh/_GOCAD_mesh.py +82 -82
  37. subsurface/modules/reader/mesh/_trimesh_reader.py +447 -447
  38. subsurface/modules/reader/mesh/csv_mesh_reader.py +53 -53
  39. subsurface/modules/reader/mesh/dxf_reader.py +177 -177
  40. subsurface/modules/reader/mesh/glb_reader.py +30 -30
  41. subsurface/modules/reader/mesh/mx_reader.py +232 -232
  42. subsurface/modules/reader/mesh/obj_reader.py +53 -53
  43. subsurface/modules/reader/mesh/omf_mesh_reader.py +43 -43
  44. subsurface/modules/reader/mesh/surface_reader.py +56 -56
  45. subsurface/modules/reader/mesh/surfaces_api.py +41 -41
  46. subsurface/modules/reader/profiles/__init__.py +3 -3
  47. subsurface/modules/reader/profiles/profiles_core.py +197 -197
  48. subsurface/modules/reader/read_netcdf.py +38 -38
  49. subsurface/modules/reader/topography/__init__.py +7 -7
  50. subsurface/modules/reader/topography/topo_core.py +100 -100
  51. subsurface/modules/reader/volume/read_grav3d.py +478 -428
  52. subsurface/modules/reader/volume/read_volume.py +327 -230
  53. subsurface/modules/reader/volume/segy_reader.py +105 -105
  54. subsurface/modules/reader/volume/seismic.py +173 -173
  55. subsurface/modules/reader/volume/volume_utils.py +43 -43
  56. subsurface/modules/reader/wells/DEP/__init__.py +43 -43
  57. subsurface/modules/reader/wells/DEP/_well_files_reader.py +167 -167
  58. subsurface/modules/reader/wells/DEP/_wells_api.py +61 -61
  59. subsurface/modules/reader/wells/DEP/_welly_reader.py +180 -180
  60. subsurface/modules/reader/wells/DEP/pandas_to_welly.py +212 -212
  61. subsurface/modules/reader/wells/_read_to_df.py +57 -57
  62. subsurface/modules/reader/wells/read_borehole_interface.py +148 -148
  63. subsurface/modules/reader/wells/wells_utils.py +68 -68
  64. subsurface/modules/tools/mocking_aux.py +104 -104
  65. subsurface/modules/visualization/__init__.py +2 -2
  66. subsurface/modules/visualization/to_pyvista.py +320 -320
  67. subsurface/modules/writer/to_binary.py +12 -12
  68. subsurface/modules/writer/to_rex/common.py +78 -78
  69. subsurface/modules/writer/to_rex/data_struct.py +74 -74
  70. subsurface/modules/writer/to_rex/gempy_to_rexfile.py +791 -791
  71. subsurface/modules/writer/to_rex/material_encoder.py +44 -44
  72. subsurface/modules/writer/to_rex/mesh_encoder.py +152 -152
  73. subsurface/modules/writer/to_rex/to_rex.py +115 -115
  74. subsurface/modules/writer/to_rex/utils.py +15 -15
  75. subsurface/optional_requirements.py +116 -116
  76. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/METADATA +194 -194
  77. subsurface_terra-2025.1.0rc16.dist-info/RECORD +98 -0
  78. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/WHEEL +1 -1
  79. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/licenses/LICENSE +203 -203
  80. subsurface_terra-2025.1.0rc15.dist-info/RECORD +0 -98
  81. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc16.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