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,320 +1,320 @@
1
- import enum
2
-
3
- import warnings
4
-
5
- from typing import Union, Tuple, Optional
6
-
7
- from ... import optional_requirements
8
- from ...core.structs.unstructured_elements import PointSet, TriSurf, LineSet, TetraMesh
9
- from ...core.structs.structured_elements.structured_grid import StructuredGrid
10
- import numpy as np
11
-
12
- try:
13
- import pyvista as pv
14
- except ImportError:
15
- warnings.warn('Pyvista is not installed. Some visualization functions will not work.')
16
-
17
-
18
- def pv_plot(meshes: list,
19
- image_2d=False,
20
- ve=None,
21
- cmap='viridis',
22
- plotter_kwargs: dict = None,
23
- add_mesh_kwargs: dict = None,
24
- background_plotter=False):
25
- """Function to plot meshes in vtk using pyvista
26
-
27
- Args:
28
- meshes (List[pv.PolyData]):
29
- image_2d (bool): If True convert plot to matplotlib imshow. This helps for visualizing
30
- the plot in IDEs
31
- ve (float): vertical exaggeration
32
- plotter_kwargs (dict): pyvista.Plotter kwargs
33
- add_mesh_kwargs (dict): pyvista.add_mesh kwargs
34
- background_plotter (bool): if true and pyvistaqt installed use pyvista
35
- backgroung plotter.
36
- """
37
-
38
- add_mesh_kwargs = dict() if add_mesh_kwargs is None else add_mesh_kwargs
39
- p: pv.Pll = init_plotter(image_2d, ve, plotter_kwargs)
40
-
41
- for m in meshes:
42
- # Check if m has texture data
43
- texture = None
44
- if hasattr(m, '_textures') and isinstance(m._textures, dict):
45
- texture = m._textures.get(0, None)
46
-
47
- p.add_mesh(
48
- mesh=m,
49
- cmap=cmap,
50
- categories=True,
51
- texture=texture,
52
- **add_mesh_kwargs
53
- )
54
-
55
- p.show_bounds()
56
-
57
- if image_2d is False:
58
- p.show()
59
- return p
60
- else:
61
- fig = pyvista_to_matplotlib(p)
62
- return fig
63
-
64
-
65
- def pyvista_to_matplotlib(p: "pv.Plotter"):
66
- try:
67
- import matplotlib.pyplot as plt
68
- except ImportError:
69
- raise ImportError('Matplotlib is necessary for generating a 2D image.')
70
- img = p.show(screenshot=True)
71
- img = p.last_image
72
- fig = plt.imshow(img)
73
- plt.axis('off')
74
- plt.show(block=False)
75
- p.close()
76
- return fig
77
-
78
-
79
- def init_plotter(
80
- image_2d=False,
81
- ve=None,
82
- plotter_kwargs: dict = None
83
- ) -> "pv.Plotter":
84
- plotter_kwargs = dict() if plotter_kwargs is None else plotter_kwargs
85
- off_screen = True if image_2d is True else None
86
- p = pv.Plotter(**plotter_kwargs, off_screen=off_screen)
87
- if ve is not None:
88
- p.set_scale(zscale=ve)
89
- return p
90
-
91
-
92
- def to_pyvista_points(point_set: PointSet):
93
- """Create pyvista.PolyData from PointSet
94
-
95
- Args:
96
- point_set (PointSet): Class for pointset based data structures.
97
-
98
- Returns:
99
- pv.PolyData
100
- """
101
- pv = optional_requirements.require_pyvista()
102
- poly: pv.PolyData = pv.PolyData(point_set.data.vertex)
103
- poly.point_data.update(point_set.data.attributes_to_dict)
104
-
105
- return poly
106
-
107
-
108
- def to_pyvista_mesh(triangular_surface: TriSurf) -> "pv.PolyData":
109
- """Create planar surface PolyData from unstructured element such as TriSurf
110
-
111
- Returns:
112
- mesh texture
113
- """
114
- nve = triangular_surface.mesh.n_vertex_per_element
115
- vertices = triangular_surface.mesh.vertex
116
-
117
- # ? We need better name for these variables
118
- num_vertex_elements = np.full(triangular_surface.mesh.n_elements, nve)
119
- x = triangular_surface.mesh.cells
120
-
121
- cells = np.c_[num_vertex_elements, x]
122
-
123
- pv = optional_requirements.require_pyvista()
124
- mesh = pv.PolyData(vertices, cells)
125
- mesh.cell_data.update(triangular_surface.mesh.attributes_to_dict)
126
- mesh.point_data.update(triangular_surface.mesh.points_attributes)
127
-
128
- # If UV coordinates exist in points_attributes, set them as texture coordinates
129
- if triangular_surface.has_texture_data_with_uv:
130
- uv = np.column_stack((
131
- triangular_surface.mesh.points_attributes['u'],
132
- triangular_surface.mesh.points_attributes['v']
133
- ))
134
- mesh.active_texture_coordinates = uv
135
- if triangular_surface.texture is not None:
136
- texture_data = np.asarray(triangular_surface.texture.values, dtype=np.float32)
137
- mesh._textures = {0: texture_data}
138
- mesh.active_scalars_name = None
139
-
140
- elif triangular_surface.has_texture_data_without_uv:
141
- mesh.texture_map_to_plane(
142
- inplace=True,
143
- origin=triangular_surface.texture_origin,
144
- point_u=triangular_surface.texture_point_u,
145
- point_v=triangular_surface.texture_point_v
146
- )
147
-
148
- texture_data = np.asarray(triangular_surface.texture.values, dtype=np.float32)
149
- mesh._textures = {0: texture_data}
150
- mesh.active_scalars_name = None
151
-
152
- return mesh
153
-
154
-
155
- def to_pyvista_mesh_and_texture(triangular_surface: Union[TriSurf], ) -> Tuple["pv.PolyData", Optional[np.array]]:
156
- """Create planar surface PolyData from unstructured element such as TriSurf
157
-
158
- Returns:
159
- mesh texture
160
- """
161
- mesh = to_pyvista_mesh(triangular_surface)
162
-
163
- if triangular_surface.texture is None:
164
- raise ValueError('unstructured_element needs texture data to be mapped.')
165
-
166
- mesh.texture_map_to_plane(
167
- inplace=True,
168
- origin=triangular_surface.texture_origin,
169
- point_u=triangular_surface.texture_point_u,
170
- point_v=triangular_surface.texture_point_v
171
- )
172
- tex = pv.numpy_to_texture(triangular_surface.texture.values)
173
- mesh._textures = {0: tex}
174
-
175
- from vtkmodules.util.numpy_support import vtk_to_numpy
176
- uv = vtk_to_numpy(mesh.GetPointData().GetTCoords())
177
- return mesh, uv
178
-
179
-
180
- class PyvistaScalarType(enum.Enum):
181
- POINT = 'point'
182
- CELL = 'cell'
183
-
184
-
185
- def to_pyvista_line(
186
- line_set: LineSet,
187
- as_tube=True,
188
- radius=None,
189
- spline=False,
190
- n_interp_points=1000,
191
- scalar_type: PyvistaScalarType = PyvistaScalarType.POINT,
192
- active_scalar: Optional[str] = None
193
- ):
194
- nve = line_set.data.n_vertex_per_element
195
- vertices = line_set.data.vertex
196
- cells = np.c_[np.full(line_set.data.n_elements, nve),
197
- line_set.data.cells]
198
- if spline is False:
199
- mesh = pv.PolyData()
200
- mesh.points = vertices
201
- mesh.lines = cells
202
- else:
203
- raise NotImplementedError
204
-
205
- match scalar_type:
206
- case PyvistaScalarType.POINT:
207
- mesh.point_data.update(line_set.data.points_attributes_to_dict)
208
- if active_scalar is not None:
209
- mesh.set_active_scalars(active_scalar, preference='point')
210
- case PyvistaScalarType.CELL:
211
- mesh.cell_data.update(line_set.data.attributes_to_dict)
212
- if active_scalar is not None:
213
- mesh.set_active_scalars(active_scalar, preference='cell')
214
- if as_tube is True:
215
- return mesh.tube(radius=radius)
216
- else:
217
- return mesh
218
-
219
-
220
- def to_pyvista_tetra(tetra_mesh: TetraMesh):
221
- """Create pyvista.UnstructuredGrid"""
222
- vertices = tetra_mesh.data.vertex
223
- tets = tetra_mesh.data.cells
224
- cells = np.c_[np.full(len(tets), 4), tets]
225
- import vtk
226
- ctypes = np.array([vtk.VTK_TETRA, ], np.int32)
227
- mesh = pv.UnstructuredGrid(cells, ctypes, vertices)
228
- mesh.cell_data.update(tetra_mesh.data.attributes_to_dict)
229
- return mesh
230
-
231
-
232
- def to_pyvista_grid(
233
- structured_grid: StructuredGrid,
234
- data_set_name: str = None,
235
- attribute_slice: dict = None,
236
- data_order: str = 'F'
237
- ) -> "pyvista.StructuredGrid":
238
- """
239
-
240
- Args:
241
- structured_grid:
242
- data_set_name:
243
- attribute_slice: dictionary to select which 3D array will be displayed as color
244
-
245
- Returns:
246
-
247
- """
248
- if attribute_slice is None:
249
- attribute_slice = dict()
250
-
251
- if data_set_name is None:
252
- data_set_name = structured_grid.ds.active_data_array_name
253
-
254
- cart_dims = structured_grid.cartesian_dimensions
255
- data_dims = structured_grid.ds.data[data_set_name].sel(**attribute_slice).ndim
256
- if cart_dims < data_dims:
257
- raise AttributeError('Data dimension and cartesian dimensions must match.'
258
- 'Possibly there are not valid dimension name in the'
259
- 'xarray.DataArray. These are X Y Z x y z')
260
-
261
- if data_dims == 2:
262
- meshgrid = structured_grid.meshgrid_2d(data_set_name)
263
- elif data_dims == 3:
264
- meshgrid = structured_grid.meshgrid_3d
265
- else:
266
- raise AttributeError('The DataArray does not have valid dimensionality. '
267
- 'Possibly there are not valid dimension name in the'
268
- 'xarray.DataArray. These are X Y Z x y z')
269
-
270
- pv = optional_requirements.require_pyvista()
271
- mesh = pv.StructuredGrid(*meshgrid)
272
- update_grid_attribute(mesh, structured_grid, data_order,
273
- attribute_slice, data_set_name)
274
-
275
- return mesh
276
-
277
-
278
- def update_grid_attribute(
279
- mesh: 'pv.StructuredGrid',
280
- structured_grid: StructuredGrid,
281
- data_order='F',
282
- attribute_slice=None,
283
- data_set_name=None
284
- ):
285
- if attribute_slice is None:
286
- attribute_slice = dict()
287
-
288
- if data_set_name is None:
289
- data_set_name = structured_grid.ds.active_data_array_name
290
- import xarray as xr
291
- dataset: xr.DataArray = structured_grid.ds.data[data_set_name]
292
-
293
- attributeData = {data_set_name: dataset.sel(**attribute_slice).values.ravel(data_order)}
294
- mesh.point_data.update(attributeData)
295
-
296
- return mesh
297
-
298
-
299
- def _n_cartesian_coord(attribute, structured_grid):
300
- coord_names = np.array(['X', 'Y', 'Z', 'x', 'y', 'z'])
301
- ndim = np.isin(coord_names, structured_grid.ds.data[attribute].dims).sum()
302
- return ndim
303
-
304
-
305
- def _generate_colors_from_colormap(num_colors, cmap_name='viridis'):
306
- """
307
- Generate a sequence of colors from a given Matplotlib colormap.
308
-
309
- Parameters:
310
- num_colors (int): Number of colors to generate.
311
- cmap_name (str): Name of the Matplotlib colormap to use.
312
-
313
- Returns:
314
- list of tuple: List of RGB color tuples.
315
- """
316
- import matplotlib.pyplot as plt
317
- colormap = plt.cm.get_cmap(cmap_name)
318
- colors = colormap(np.linspace(0, 1, num_colors))
319
- # Convert from RGBA to RGB and scale to 0-255
320
- return [(int(r * 255), int(g * 255), int(b * 255)) for r, g, b, _ in colors]
1
+ import enum
2
+
3
+ import warnings
4
+
5
+ from typing import Union, Tuple, Optional
6
+
7
+ from ... import optional_requirements
8
+ from ...core.structs.unstructured_elements import PointSet, TriSurf, LineSet, TetraMesh
9
+ from ...core.structs.structured_elements.structured_grid import StructuredGrid
10
+ import numpy as np
11
+
12
+ try:
13
+ import pyvista as pv
14
+ except ImportError:
15
+ warnings.warn('Pyvista is not installed. Some visualization functions will not work.')
16
+
17
+
18
+ def pv_plot(meshes: list,
19
+ image_2d=False,
20
+ ve=None,
21
+ cmap='viridis',
22
+ plotter_kwargs: dict = None,
23
+ add_mesh_kwargs: dict = None,
24
+ background_plotter=False):
25
+ """Function to plot meshes in vtk using pyvista
26
+
27
+ Args:
28
+ meshes (List[pv.PolyData]):
29
+ image_2d (bool): If True convert plot to matplotlib imshow. This helps for visualizing
30
+ the plot in IDEs
31
+ ve (float): vertical exaggeration
32
+ plotter_kwargs (dict): pyvista.Plotter kwargs
33
+ add_mesh_kwargs (dict): pyvista.add_mesh kwargs
34
+ background_plotter (bool): if true and pyvistaqt installed use pyvista
35
+ backgroung plotter.
36
+ """
37
+
38
+ add_mesh_kwargs = dict() if add_mesh_kwargs is None else add_mesh_kwargs
39
+ p: pv.Pll = init_plotter(image_2d, ve, plotter_kwargs)
40
+
41
+ for m in meshes:
42
+ # Check if m has texture data
43
+ texture = None
44
+ if hasattr(m, '_textures') and isinstance(m._textures, dict):
45
+ texture = m._textures.get(0, None)
46
+
47
+ p.add_mesh(
48
+ mesh=m,
49
+ cmap=cmap,
50
+ categories=True,
51
+ texture=texture,
52
+ **add_mesh_kwargs
53
+ )
54
+
55
+ p.show_bounds()
56
+
57
+ if image_2d is False:
58
+ p.show()
59
+ return p
60
+ else:
61
+ fig = pyvista_to_matplotlib(p)
62
+ return fig
63
+
64
+
65
+ def pyvista_to_matplotlib(p: "pv.Plotter"):
66
+ try:
67
+ import matplotlib.pyplot as plt
68
+ except ImportError:
69
+ raise ImportError('Matplotlib is necessary for generating a 2D image.')
70
+ img = p.show(screenshot=True)
71
+ img = p.last_image
72
+ fig = plt.imshow(img)
73
+ plt.axis('off')
74
+ plt.show(block=False)
75
+ p.close()
76
+ return fig
77
+
78
+
79
+ def init_plotter(
80
+ image_2d=False,
81
+ ve=None,
82
+ plotter_kwargs: dict = None
83
+ ) -> "pv.Plotter":
84
+ plotter_kwargs = dict() if plotter_kwargs is None else plotter_kwargs
85
+ off_screen = True if image_2d is True else None
86
+ p = pv.Plotter(**plotter_kwargs, off_screen=off_screen)
87
+ if ve is not None:
88
+ p.set_scale(zscale=ve)
89
+ return p
90
+
91
+
92
+ def to_pyvista_points(point_set: PointSet):
93
+ """Create pyvista.PolyData from PointSet
94
+
95
+ Args:
96
+ point_set (PointSet): Class for pointset based data structures.
97
+
98
+ Returns:
99
+ pv.PolyData
100
+ """
101
+ pv = optional_requirements.require_pyvista()
102
+ poly: pv.PolyData = pv.PolyData(point_set.data.vertex)
103
+ poly.point_data.update(point_set.data.attributes_to_dict)
104
+
105
+ return poly
106
+
107
+
108
+ def to_pyvista_mesh(triangular_surface: TriSurf) -> "pv.PolyData":
109
+ """Create planar surface PolyData from unstructured element such as TriSurf
110
+
111
+ Returns:
112
+ mesh texture
113
+ """
114
+ nve = triangular_surface.mesh.n_vertex_per_element
115
+ vertices = triangular_surface.mesh.vertex
116
+
117
+ # ? We need better name for these variables
118
+ num_vertex_elements = np.full(triangular_surface.mesh.n_elements, nve)
119
+ x = triangular_surface.mesh.cells
120
+
121
+ cells = np.c_[num_vertex_elements, x]
122
+
123
+ pv = optional_requirements.require_pyvista()
124
+ mesh = pv.PolyData(vertices, cells)
125
+ mesh.cell_data.update(triangular_surface.mesh.attributes_to_dict)
126
+ mesh.point_data.update(triangular_surface.mesh.points_attributes)
127
+
128
+ # If UV coordinates exist in points_attributes, set them as texture coordinates
129
+ if triangular_surface.has_texture_data_with_uv:
130
+ uv = np.column_stack((
131
+ triangular_surface.mesh.points_attributes['u'],
132
+ triangular_surface.mesh.points_attributes['v']
133
+ ))
134
+ mesh.active_texture_coordinates = uv
135
+ if triangular_surface.texture is not None:
136
+ texture_data = np.asarray(triangular_surface.texture.values, dtype=np.float32)
137
+ mesh._textures = {0: texture_data}
138
+ mesh.active_scalars_name = None
139
+
140
+ elif triangular_surface.has_texture_data_without_uv:
141
+ mesh.texture_map_to_plane(
142
+ inplace=True,
143
+ origin=triangular_surface.texture_origin,
144
+ point_u=triangular_surface.texture_point_u,
145
+ point_v=triangular_surface.texture_point_v
146
+ )
147
+
148
+ texture_data = np.asarray(triangular_surface.texture.values, dtype=np.float32)
149
+ mesh._textures = {0: texture_data}
150
+ mesh.active_scalars_name = None
151
+
152
+ return mesh
153
+
154
+
155
+ def to_pyvista_mesh_and_texture(triangular_surface: Union[TriSurf], ) -> Tuple["pv.PolyData", Optional[np.array]]:
156
+ """Create planar surface PolyData from unstructured element such as TriSurf
157
+
158
+ Returns:
159
+ mesh texture
160
+ """
161
+ mesh = to_pyvista_mesh(triangular_surface)
162
+
163
+ if triangular_surface.texture is None:
164
+ raise ValueError('unstructured_element needs texture data to be mapped.')
165
+
166
+ mesh.texture_map_to_plane(
167
+ inplace=True,
168
+ origin=triangular_surface.texture_origin,
169
+ point_u=triangular_surface.texture_point_u,
170
+ point_v=triangular_surface.texture_point_v
171
+ )
172
+ tex = pv.numpy_to_texture(triangular_surface.texture.values)
173
+ mesh._textures = {0: tex}
174
+
175
+ from vtkmodules.util.numpy_support import vtk_to_numpy
176
+ uv = vtk_to_numpy(mesh.GetPointData().GetTCoords())
177
+ return mesh, uv
178
+
179
+
180
+ class PyvistaScalarType(enum.Enum):
181
+ POINT = 'point'
182
+ CELL = 'cell'
183
+
184
+
185
+ def to_pyvista_line(
186
+ line_set: LineSet,
187
+ as_tube=True,
188
+ radius=None,
189
+ spline=False,
190
+ n_interp_points=1000,
191
+ scalar_type: PyvistaScalarType = PyvistaScalarType.POINT,
192
+ active_scalar: Optional[str] = None
193
+ ):
194
+ nve = line_set.data.n_vertex_per_element
195
+ vertices = line_set.data.vertex
196
+ cells = np.c_[np.full(line_set.data.n_elements, nve),
197
+ line_set.data.cells]
198
+ if spline is False:
199
+ mesh = pv.PolyData()
200
+ mesh.points = vertices
201
+ mesh.lines = cells
202
+ else:
203
+ raise NotImplementedError
204
+
205
+ match scalar_type:
206
+ case PyvistaScalarType.POINT:
207
+ mesh.point_data.update(line_set.data.points_attributes_to_dict)
208
+ if active_scalar is not None:
209
+ mesh.set_active_scalars(active_scalar, preference='point')
210
+ case PyvistaScalarType.CELL:
211
+ mesh.cell_data.update(line_set.data.attributes_to_dict)
212
+ if active_scalar is not None:
213
+ mesh.set_active_scalars(active_scalar, preference='cell')
214
+ if as_tube is True:
215
+ return mesh.tube(radius=radius)
216
+ else:
217
+ return mesh
218
+
219
+
220
+ def to_pyvista_tetra(tetra_mesh: TetraMesh):
221
+ """Create pyvista.UnstructuredGrid"""
222
+ vertices = tetra_mesh.data.vertex
223
+ tets = tetra_mesh.data.cells
224
+ cells = np.c_[np.full(len(tets), 4), tets]
225
+ import vtk
226
+ ctypes = np.array([vtk.VTK_TETRA, ], np.int32)
227
+ mesh = pv.UnstructuredGrid(cells, ctypes, vertices)
228
+ mesh.cell_data.update(tetra_mesh.data.attributes_to_dict)
229
+ return mesh
230
+
231
+
232
+ def to_pyvista_grid(
233
+ structured_grid: StructuredGrid,
234
+ data_set_name: str = None,
235
+ attribute_slice: dict = None,
236
+ data_order: str = 'F'
237
+ ) -> "pyvista.StructuredGrid":
238
+ """
239
+
240
+ Args:
241
+ structured_grid:
242
+ data_set_name:
243
+ attribute_slice: dictionary to select which 3D array will be displayed as color
244
+
245
+ Returns:
246
+
247
+ """
248
+ if attribute_slice is None:
249
+ attribute_slice = dict()
250
+
251
+ if data_set_name is None:
252
+ data_set_name = structured_grid.ds.active_data_array_name
253
+
254
+ cart_dims = structured_grid.cartesian_dimensions
255
+ data_dims = structured_grid.ds.data[data_set_name].sel(**attribute_slice).ndim
256
+ if cart_dims < data_dims:
257
+ raise AttributeError('Data dimension and cartesian dimensions must match.'
258
+ 'Possibly there are not valid dimension name in the'
259
+ 'xarray.DataArray. These are X Y Z x y z')
260
+
261
+ if data_dims == 2:
262
+ meshgrid = structured_grid.meshgrid_2d(data_set_name)
263
+ elif data_dims == 3:
264
+ meshgrid = structured_grid.meshgrid_3d
265
+ else:
266
+ raise AttributeError('The DataArray does not have valid dimensionality. '
267
+ 'Possibly there are not valid dimension name in the'
268
+ 'xarray.DataArray. These are X Y Z x y z')
269
+
270
+ pv = optional_requirements.require_pyvista()
271
+ mesh = pv.StructuredGrid(*meshgrid)
272
+ update_grid_attribute(mesh, structured_grid, data_order,
273
+ attribute_slice, data_set_name)
274
+
275
+ return mesh
276
+
277
+
278
+ def update_grid_attribute(
279
+ mesh: 'pv.StructuredGrid',
280
+ structured_grid: StructuredGrid,
281
+ data_order='F',
282
+ attribute_slice=None,
283
+ data_set_name=None
284
+ ):
285
+ if attribute_slice is None:
286
+ attribute_slice = dict()
287
+
288
+ if data_set_name is None:
289
+ data_set_name = structured_grid.ds.active_data_array_name
290
+ import xarray as xr
291
+ dataset: xr.DataArray = structured_grid.ds.data[data_set_name]
292
+
293
+ attributeData = {data_set_name: dataset.sel(**attribute_slice).values.ravel(data_order)}
294
+ mesh.point_data.update(attributeData)
295
+
296
+ return mesh
297
+
298
+
299
+ def _n_cartesian_coord(attribute, structured_grid):
300
+ coord_names = np.array(['X', 'Y', 'Z', 'x', 'y', 'z'])
301
+ ndim = np.isin(coord_names, structured_grid.ds.data[attribute].dims).sum()
302
+ return ndim
303
+
304
+
305
+ def _generate_colors_from_colormap(num_colors, cmap_name='viridis'):
306
+ """
307
+ Generate a sequence of colors from a given Matplotlib colormap.
308
+
309
+ Parameters:
310
+ num_colors (int): Number of colors to generate.
311
+ cmap_name (str): Name of the Matplotlib colormap to use.
312
+
313
+ Returns:
314
+ list of tuple: List of RGB color tuples.
315
+ """
316
+ import matplotlib.pyplot as plt
317
+ colormap = plt.cm.get_cmap(cmap_name)
318
+ colors = colormap(np.linspace(0, 1, num_colors))
319
+ # Convert from RGBA to RGB and scale to 0-255
320
+ return [(int(r * 255), int(g * 255), int(b * 255)) for r, g, b, _ in colors]
@@ -1,13 +1,13 @@
1
- import json
2
-
3
-
4
- def base_structs_to_binary_file(path, base_struct, order='F'):
5
- try:
6
- bytearray_le, header = base_struct.default_data_array_to_binary_legacy(order=order)
7
- except AttributeError:
8
- bytearray_le, header = base_struct.to_binary_legacy(order=order)
9
- with open(path+'.json', 'w') as outfile:
10
- json.dump(header, outfile)
11
-
12
- new_file = open(path+".le", "wb")
1
+ import json
2
+
3
+
4
+ def base_structs_to_binary_file(path, base_struct, order='F'):
5
+ try:
6
+ bytearray_le, header = base_struct.default_data_array_to_binary_legacy(order=order)
7
+ except AttributeError:
8
+ bytearray_le, header = base_struct.to_binary_legacy(order=order)
9
+ with open(path+'.json', 'w') as outfile:
10
+ json.dump(header, outfile)
11
+
12
+ new_file = open(path+".le", "wb")
13
13
  new_file.write(bytearray_le)