mmgpy 0.5.0__cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.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.
- mmgpy/__init__.py +296 -0
- mmgpy/__main__.py +13 -0
- mmgpy/_io.py +535 -0
- mmgpy/_logging.py +290 -0
- mmgpy/_mesh.py +2286 -0
- mmgpy/_mmgpy.cpython-311-x86_64-linux-gnu.so +0 -0
- mmgpy/_mmgpy.pyi +2140 -0
- mmgpy/_options.py +304 -0
- mmgpy/_progress.py +850 -0
- mmgpy/_pyvista.py +410 -0
- mmgpy/_result.py +143 -0
- mmgpy/_transfer.py +273 -0
- mmgpy/_validation.py +669 -0
- mmgpy/_version.py +3 -0
- mmgpy/_version.py.in +3 -0
- mmgpy/bin/mmg2d_O3 +0 -0
- mmgpy/bin/mmg3d_O3 +0 -0
- mmgpy/bin/mmgs_O3 +0 -0
- mmgpy/interactive/__init__.py +24 -0
- mmgpy/interactive/sizing_editor.py +790 -0
- mmgpy/lagrangian.py +394 -0
- mmgpy/lib/libmmg2d.so +0 -0
- mmgpy/lib/libmmg2d.so.5 +0 -0
- mmgpy/lib/libmmg2d.so.5.8.0 +0 -0
- mmgpy/lib/libmmg3d.so +0 -0
- mmgpy/lib/libmmg3d.so.5 +0 -0
- mmgpy/lib/libmmg3d.so.5.8.0 +0 -0
- mmgpy/lib/libmmgs.so +0 -0
- mmgpy/lib/libmmgs.so.5 +0 -0
- mmgpy/lib/libmmgs.so.5.8.0 +0 -0
- mmgpy/lib/libvtkCommonColor-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonComputationalGeometry-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonDataModel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonExecutionModel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonMath-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonMisc-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonSystem-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonTransforms-9.5.so.1 +0 -0
- mmgpy/lib/libvtkDICOMParser-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersCellGrid-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersExtraction-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersGeneral-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersGeometry-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersHybrid-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersHyperTree-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersModeling-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersParallel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersReduction-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersSources-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersStatistics-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersTexture-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersVerdict-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOCellGrid-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOGeometry-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOImage-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOLegacy-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOParallel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOParallelXML-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOXML-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOXMLParser-9.5.so.1 +0 -0
- mmgpy/lib/libvtkImagingCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkImagingSources-9.5.so.1 +0 -0
- mmgpy/lib/libvtkParallelCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkParallelDIY-9.5.so.1 +0 -0
- mmgpy/lib/libvtkRenderingCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkdoubleconversion-9.5.so.1 +0 -0
- mmgpy/lib/libvtkexpat-9.5.so.1 +0 -0
- mmgpy/lib/libvtkfmt-9.5.so.1 +0 -0
- mmgpy/lib/libvtkjpeg-9.5.so.1 +0 -0
- mmgpy/lib/libvtkjsoncpp-9.5.so.1 +0 -0
- mmgpy/lib/libvtkkissfft-9.5.so.1 +0 -0
- mmgpy/lib/libvtkloguru-9.5.so.1 +0 -0
- mmgpy/lib/libvtklz4-9.5.so.1 +0 -0
- mmgpy/lib/libvtklzma-9.5.so.1 +0 -0
- mmgpy/lib/libvtkmetaio-9.5.so.1 +0 -0
- mmgpy/lib/libvtkpng-9.5.so.1 +0 -0
- mmgpy/lib/libvtkpugixml-9.5.so.1 +0 -0
- mmgpy/lib/libvtksys-9.5.so.1 +0 -0
- mmgpy/lib/libvtktiff-9.5.so.1 +0 -0
- mmgpy/lib/libvtktoken-9.5.so.1 +0 -0
- mmgpy/lib/libvtkverdict-9.5.so.1 +0 -0
- mmgpy/lib/libvtkzlib-9.5.so.1 +0 -0
- mmgpy/metrics.py +596 -0
- mmgpy/progress.py +69 -0
- mmgpy/py.typed +0 -0
- mmgpy/repair/__init__.py +37 -0
- mmgpy/repair/_core.py +226 -0
- mmgpy/repair/_elements.py +241 -0
- mmgpy/repair/_vertices.py +219 -0
- mmgpy/sizing.py +370 -0
- mmgpy/ui/__init__.py +97 -0
- mmgpy/ui/__main__.py +87 -0
- mmgpy/ui/app.py +1837 -0
- mmgpy/ui/parsers.py +501 -0
- mmgpy/ui/remeshing.py +448 -0
- mmgpy/ui/samples.py +249 -0
- mmgpy/ui/utils.py +280 -0
- mmgpy/ui/viewer.py +587 -0
- mmgpy-0.5.0.dist-info/METADATA +186 -0
- mmgpy-0.5.0.dist-info/RECORD +109 -0
- mmgpy-0.5.0.dist-info/WHEEL +6 -0
- mmgpy-0.5.0.dist-info/entry_points.txt +13 -0
- mmgpy-0.5.0.dist-info/licenses/LICENSE +38 -0
- share/man/man1/mmg2d.1.gz +0 -0
- share/man/man1/mmg3d.1.gz +0 -0
- share/man/man1/mmgs.1.gz +0 -0
mmgpy/_mmgpy.pyi
ADDED
|
@@ -0,0 +1,2140 @@
|
|
|
1
|
+
"""Type stubs for the mmgpy C++ extension module.
|
|
2
|
+
|
|
3
|
+
This module provides type information for the pybind11 C++ bindings.
|
|
4
|
+
All element indices in this API are 0-based (Python convention), though
|
|
5
|
+
MMG internally uses 1-based indexing. The bindings handle this conversion.
|
|
6
|
+
|
|
7
|
+
Supported solution fields for set_field/get_field:
|
|
8
|
+
- "metric": Isotropic sizing field (Nx1 array)
|
|
9
|
+
- "displacement": Lagrangian motion field (Nx2 or Nx3 array)
|
|
10
|
+
- "levelset": Implicit surface definition (Nx1 array)
|
|
11
|
+
- "tensor": Anisotropic metric (Nx6 array, stored as xx, xy, xz, yy, yz, zz)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, overload
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from numpy.typing import NDArray
|
|
19
|
+
|
|
20
|
+
MMG_VERSION: str
|
|
21
|
+
|
|
22
|
+
class mmg3d: # noqa: N801
|
|
23
|
+
"""Static methods for file-based 3D mesh remeshing."""
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def remesh(
|
|
27
|
+
input_mesh: str | Path,
|
|
28
|
+
input_sol: str | Path | None = None,
|
|
29
|
+
output_mesh: str | Path | None = None,
|
|
30
|
+
output_sol: str | Path | None = None,
|
|
31
|
+
options: dict[str, float | int] | None = None,
|
|
32
|
+
) -> bool:
|
|
33
|
+
"""Remesh a 3D mesh file using MMG3D.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
input_mesh : str | Path
|
|
38
|
+
Path to input mesh file (.mesh format).
|
|
39
|
+
input_sol : str | Path | None
|
|
40
|
+
Path to input solution file (.sol format).
|
|
41
|
+
output_mesh : str | Path | None
|
|
42
|
+
Path for output mesh file. If None, modifies input in place.
|
|
43
|
+
output_sol : str | Path | None
|
|
44
|
+
Path for output solution file.
|
|
45
|
+
options : dict[str, float | int] | None
|
|
46
|
+
Remeshing options (hmin, hmax, hsiz, hausd, hgrad, verbose, etc.).
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
bool
|
|
51
|
+
True if remeshing succeeded.
|
|
52
|
+
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
class mmg2d: # noqa: N801
|
|
56
|
+
"""Static methods for file-based 2D mesh remeshing."""
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def remesh(
|
|
60
|
+
input_mesh: str | Path,
|
|
61
|
+
input_sol: str | Path | None = None,
|
|
62
|
+
output_mesh: str | Path | None = None,
|
|
63
|
+
output_sol: str | Path | None = None,
|
|
64
|
+
options: dict[str, float | int] | None = None,
|
|
65
|
+
) -> bool:
|
|
66
|
+
"""Remesh a 2D mesh file using MMG2D.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
input_mesh : str | Path
|
|
71
|
+
Path to input mesh file (.mesh format).
|
|
72
|
+
input_sol : str | Path | None
|
|
73
|
+
Path to input solution file (.sol format).
|
|
74
|
+
output_mesh : str | Path | None
|
|
75
|
+
Path for output mesh file. If None, modifies input in place.
|
|
76
|
+
output_sol : str | Path | None
|
|
77
|
+
Path for output solution file.
|
|
78
|
+
options : dict[str, float | int] | None
|
|
79
|
+
Remeshing options (hmin, hmax, hsiz, hausd, hgrad, verbose, etc.).
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
bool
|
|
84
|
+
True if remeshing succeeded.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
class mmgs: # noqa: N801
|
|
89
|
+
"""Static methods for file-based surface mesh remeshing."""
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def remesh(
|
|
93
|
+
input_mesh: str | Path,
|
|
94
|
+
input_sol: str | Path | None = None,
|
|
95
|
+
output_mesh: str | Path | None = None,
|
|
96
|
+
output_sol: str | Path | None = None,
|
|
97
|
+
options: dict[str, float | int] | None = None,
|
|
98
|
+
) -> bool:
|
|
99
|
+
"""Remesh a surface mesh file using MMGS.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
input_mesh : str | Path
|
|
104
|
+
Path to input mesh file (.mesh format).
|
|
105
|
+
input_sol : str | Path | None
|
|
106
|
+
Path to input solution file (.sol format).
|
|
107
|
+
output_mesh : str | Path | None
|
|
108
|
+
Path for output mesh file. If None, modifies input in place.
|
|
109
|
+
output_sol : str | Path | None
|
|
110
|
+
Path for output solution file.
|
|
111
|
+
options : dict[str, float | int] | None
|
|
112
|
+
Remeshing options (hmin, hmax, hsiz, hausd, hgrad, verbose, etc.).
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
bool
|
|
117
|
+
True if remeshing succeeded.
|
|
118
|
+
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
class MmgMesh3D:
|
|
122
|
+
"""3D tetrahedral mesh class for in-memory remeshing.
|
|
123
|
+
|
|
124
|
+
All element indices in this class are 0-based (Python convention).
|
|
125
|
+
The underlying MMG library uses 1-based indexing, but the bindings
|
|
126
|
+
handle this conversion automatically.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
@overload
|
|
130
|
+
def __init__(self) -> None:
|
|
131
|
+
"""Create an empty 3D mesh."""
|
|
132
|
+
|
|
133
|
+
@overload
|
|
134
|
+
def __init__(
|
|
135
|
+
self,
|
|
136
|
+
vertices: NDArray[np.float64],
|
|
137
|
+
elements: NDArray[np.int32],
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Create a 3D mesh from vertices and tetrahedra.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
vertices : NDArray[np.float64]
|
|
144
|
+
Vertex coordinates, shape (n_vertices, 3).
|
|
145
|
+
elements : NDArray[np.int32]
|
|
146
|
+
Tetrahedra connectivity, shape (n_tetrahedra, 4).
|
|
147
|
+
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
@overload
|
|
151
|
+
def __init__(
|
|
152
|
+
self,
|
|
153
|
+
filename: str | Path,
|
|
154
|
+
) -> None:
|
|
155
|
+
"""Load a 3D mesh from file.
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
filename : str | Path
|
|
160
|
+
Path to mesh file (.mesh, .vtk, .vtu format).
|
|
161
|
+
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
def set_vertices_and_elements(
|
|
165
|
+
self,
|
|
166
|
+
vertices: NDArray[np.float64],
|
|
167
|
+
elements: NDArray[np.int32],
|
|
168
|
+
) -> None:
|
|
169
|
+
"""Set mesh vertices and tetrahedra.
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
vertices : NDArray[np.float64]
|
|
174
|
+
Vertex coordinates, shape (n_vertices, 3).
|
|
175
|
+
elements : NDArray[np.int32]
|
|
176
|
+
Tetrahedra connectivity, shape (n_tetrahedra, 4).
|
|
177
|
+
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
def get_vertices(self) -> NDArray[np.float64]:
|
|
181
|
+
"""Get vertex coordinates.
|
|
182
|
+
|
|
183
|
+
Returns
|
|
184
|
+
-------
|
|
185
|
+
NDArray[np.float64]
|
|
186
|
+
Vertex coordinates, shape (n_vertices, 3).
|
|
187
|
+
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
def get_elements(self) -> NDArray[np.int32]:
|
|
191
|
+
"""Get tetrahedra connectivity (alias for get_tetrahedra).
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
NDArray[np.int32]
|
|
196
|
+
Tetrahedra connectivity, shape (n_tetrahedra, 4).
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
def set_mesh_size(
|
|
201
|
+
self,
|
|
202
|
+
vertices: int = 0,
|
|
203
|
+
tetrahedra: int = 0,
|
|
204
|
+
prisms: int = 0,
|
|
205
|
+
triangles: int = 0,
|
|
206
|
+
quadrilaterals: int = 0,
|
|
207
|
+
edges: int = 0,
|
|
208
|
+
) -> None:
|
|
209
|
+
"""Allocate mesh storage for the specified element counts.
|
|
210
|
+
|
|
211
|
+
Call this before using single-element setters (set_vertex, etc.).
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
vertices : int
|
|
216
|
+
Number of vertices.
|
|
217
|
+
tetrahedra : int
|
|
218
|
+
Number of tetrahedra.
|
|
219
|
+
prisms : int
|
|
220
|
+
Number of prisms.
|
|
221
|
+
triangles : int
|
|
222
|
+
Number of triangles (boundary faces).
|
|
223
|
+
quadrilaterals : int
|
|
224
|
+
Number of quadrilaterals.
|
|
225
|
+
edges : int
|
|
226
|
+
Number of edges.
|
|
227
|
+
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
def get_mesh_size(
|
|
231
|
+
self,
|
|
232
|
+
) -> tuple[int, int, int, int, int, int]:
|
|
233
|
+
"""Get current mesh element counts.
|
|
234
|
+
|
|
235
|
+
Returns
|
|
236
|
+
-------
|
|
237
|
+
tuple[int, int, int, int, int, int]
|
|
238
|
+
Tuple of (vertices, tetrahedra, prisms, triangles, quadrilaterals, edges).
|
|
239
|
+
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
def set_vertices(
|
|
243
|
+
self,
|
|
244
|
+
vertices: NDArray[np.float64],
|
|
245
|
+
refs: NDArray[np.int64] | None = None,
|
|
246
|
+
) -> None:
|
|
247
|
+
"""Set all vertex coordinates.
|
|
248
|
+
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
vertices : NDArray[np.float64]
|
|
252
|
+
Vertex coordinates, shape (n_vertices, 3).
|
|
253
|
+
refs : NDArray[np.int64] | None
|
|
254
|
+
Reference markers for each vertex.
|
|
255
|
+
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
def set_tetrahedra(
|
|
259
|
+
self,
|
|
260
|
+
tetrahedra: NDArray[np.int32],
|
|
261
|
+
refs: NDArray[np.int64] | None = None,
|
|
262
|
+
) -> None:
|
|
263
|
+
"""Set all tetrahedra.
|
|
264
|
+
|
|
265
|
+
Parameters
|
|
266
|
+
----------
|
|
267
|
+
tetrahedra : NDArray[np.int32]
|
|
268
|
+
Tetrahedra connectivity, shape (n_tetrahedra, 4).
|
|
269
|
+
refs : NDArray[np.int64] | None
|
|
270
|
+
Reference markers for each tetrahedron.
|
|
271
|
+
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
def set_triangles(
|
|
275
|
+
self,
|
|
276
|
+
triangles: NDArray[np.int32],
|
|
277
|
+
refs: NDArray[np.int64] | None = None,
|
|
278
|
+
) -> None:
|
|
279
|
+
"""Set all triangles (boundary faces).
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
triangles : NDArray[np.int32]
|
|
284
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
285
|
+
refs : NDArray[np.int64] | None
|
|
286
|
+
Reference markers for each triangle.
|
|
287
|
+
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
def set_edges(
|
|
291
|
+
self,
|
|
292
|
+
edges: NDArray[np.int32],
|
|
293
|
+
refs: NDArray[np.int64] | None = None,
|
|
294
|
+
) -> None:
|
|
295
|
+
"""Set all edges.
|
|
296
|
+
|
|
297
|
+
Parameters
|
|
298
|
+
----------
|
|
299
|
+
edges : NDArray[np.int32]
|
|
300
|
+
Edge connectivity, shape (n_edges, 2).
|
|
301
|
+
refs : NDArray[np.int64] | None
|
|
302
|
+
Reference markers for each edge.
|
|
303
|
+
|
|
304
|
+
"""
|
|
305
|
+
|
|
306
|
+
def get_vertices_with_refs(
|
|
307
|
+
self,
|
|
308
|
+
) -> tuple[NDArray[np.float64], NDArray[np.int64]]:
|
|
309
|
+
"""Get vertex coordinates with reference markers.
|
|
310
|
+
|
|
311
|
+
Returns
|
|
312
|
+
-------
|
|
313
|
+
tuple[NDArray[np.float64], NDArray[np.int64]]
|
|
314
|
+
Tuple of (vertices, refs).
|
|
315
|
+
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
def get_triangles(self) -> NDArray[np.int32]:
|
|
319
|
+
"""Get triangle connectivity.
|
|
320
|
+
|
|
321
|
+
Returns
|
|
322
|
+
-------
|
|
323
|
+
NDArray[np.int32]
|
|
324
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
325
|
+
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
def get_triangles_with_refs(
|
|
329
|
+
self,
|
|
330
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
331
|
+
"""Get triangle connectivity with reference markers.
|
|
332
|
+
|
|
333
|
+
Returns
|
|
334
|
+
-------
|
|
335
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
336
|
+
Tuple of (triangles, refs).
|
|
337
|
+
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
def get_elements_with_refs(
|
|
341
|
+
self,
|
|
342
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
343
|
+
"""Get tetrahedra connectivity with reference markers.
|
|
344
|
+
|
|
345
|
+
Returns
|
|
346
|
+
-------
|
|
347
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
348
|
+
Tuple of (tetrahedra, refs).
|
|
349
|
+
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
def get_edges(self) -> NDArray[np.int32]:
|
|
353
|
+
"""Get edge connectivity.
|
|
354
|
+
|
|
355
|
+
Returns
|
|
356
|
+
-------
|
|
357
|
+
NDArray[np.int32]
|
|
358
|
+
Edge connectivity, shape (n_edges, 2).
|
|
359
|
+
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
def get_edges_with_refs(
|
|
363
|
+
self,
|
|
364
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
365
|
+
"""Get edge connectivity with reference markers.
|
|
366
|
+
|
|
367
|
+
Returns
|
|
368
|
+
-------
|
|
369
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
370
|
+
Tuple of (edges, refs).
|
|
371
|
+
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
def set_vertex(
|
|
375
|
+
self,
|
|
376
|
+
x: float,
|
|
377
|
+
y: float,
|
|
378
|
+
z: float,
|
|
379
|
+
ref: int,
|
|
380
|
+
idx: int,
|
|
381
|
+
) -> None:
|
|
382
|
+
"""Set a single vertex.
|
|
383
|
+
|
|
384
|
+
Parameters
|
|
385
|
+
----------
|
|
386
|
+
x, y, z : float
|
|
387
|
+
Vertex coordinates.
|
|
388
|
+
ref : int
|
|
389
|
+
Reference marker.
|
|
390
|
+
idx : int
|
|
391
|
+
Vertex index (0-based).
|
|
392
|
+
|
|
393
|
+
"""
|
|
394
|
+
|
|
395
|
+
def set_tetrahedron(
|
|
396
|
+
self,
|
|
397
|
+
v0: int,
|
|
398
|
+
v1: int,
|
|
399
|
+
v2: int,
|
|
400
|
+
v3: int,
|
|
401
|
+
ref: int,
|
|
402
|
+
idx: int,
|
|
403
|
+
) -> None:
|
|
404
|
+
"""Set a single tetrahedron.
|
|
405
|
+
|
|
406
|
+
Parameters
|
|
407
|
+
----------
|
|
408
|
+
v0, v1, v2, v3 : int
|
|
409
|
+
Vertex indices (0-based).
|
|
410
|
+
ref : int
|
|
411
|
+
Reference marker.
|
|
412
|
+
idx : int
|
|
413
|
+
Tetrahedron index (0-based).
|
|
414
|
+
|
|
415
|
+
"""
|
|
416
|
+
|
|
417
|
+
def set_triangle(
|
|
418
|
+
self,
|
|
419
|
+
v0: int,
|
|
420
|
+
v1: int,
|
|
421
|
+
v2: int,
|
|
422
|
+
ref: int,
|
|
423
|
+
idx: int,
|
|
424
|
+
) -> None:
|
|
425
|
+
"""Set a single triangle.
|
|
426
|
+
|
|
427
|
+
Parameters
|
|
428
|
+
----------
|
|
429
|
+
v0, v1, v2 : int
|
|
430
|
+
Vertex indices (0-based).
|
|
431
|
+
ref : int
|
|
432
|
+
Reference marker.
|
|
433
|
+
idx : int
|
|
434
|
+
Triangle index (0-based).
|
|
435
|
+
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
def set_edge(self, v0: int, v1: int, ref: int, idx: int) -> None:
|
|
439
|
+
"""Set a single edge.
|
|
440
|
+
|
|
441
|
+
Parameters
|
|
442
|
+
----------
|
|
443
|
+
v0, v1 : int
|
|
444
|
+
Vertex indices (0-based).
|
|
445
|
+
ref : int
|
|
446
|
+
Reference marker.
|
|
447
|
+
idx : int
|
|
448
|
+
Edge index (0-based).
|
|
449
|
+
|
|
450
|
+
"""
|
|
451
|
+
|
|
452
|
+
def get_vertex(self, idx: int) -> tuple[float, float, float, int]:
|
|
453
|
+
"""Get a single vertex.
|
|
454
|
+
|
|
455
|
+
Parameters
|
|
456
|
+
----------
|
|
457
|
+
idx : int
|
|
458
|
+
Vertex index (0-based).
|
|
459
|
+
|
|
460
|
+
Returns
|
|
461
|
+
-------
|
|
462
|
+
tuple[float, float, float, int]
|
|
463
|
+
Tuple of (x, y, z, ref).
|
|
464
|
+
|
|
465
|
+
"""
|
|
466
|
+
|
|
467
|
+
def get_tetrahedron(
|
|
468
|
+
self,
|
|
469
|
+
idx: int,
|
|
470
|
+
) -> tuple[int, int, int, int, int]:
|
|
471
|
+
"""Get a single tetrahedron.
|
|
472
|
+
|
|
473
|
+
Parameters
|
|
474
|
+
----------
|
|
475
|
+
idx : int
|
|
476
|
+
Tetrahedron index (0-based).
|
|
477
|
+
|
|
478
|
+
Returns
|
|
479
|
+
-------
|
|
480
|
+
tuple[int, int, int, int, int]
|
|
481
|
+
Tuple of (v0, v1, v2, v3, ref).
|
|
482
|
+
|
|
483
|
+
"""
|
|
484
|
+
|
|
485
|
+
def get_triangle(self, idx: int) -> tuple[int, int, int, int]:
|
|
486
|
+
"""Get a single triangle.
|
|
487
|
+
|
|
488
|
+
Parameters
|
|
489
|
+
----------
|
|
490
|
+
idx : int
|
|
491
|
+
Triangle index (0-based).
|
|
492
|
+
|
|
493
|
+
Returns
|
|
494
|
+
-------
|
|
495
|
+
tuple[int, int, int, int]
|
|
496
|
+
Tuple of (v0, v1, v2, ref).
|
|
497
|
+
|
|
498
|
+
"""
|
|
499
|
+
|
|
500
|
+
def get_edge(self, idx: int) -> tuple[int, int, int]:
|
|
501
|
+
"""Get a single edge.
|
|
502
|
+
|
|
503
|
+
Parameters
|
|
504
|
+
----------
|
|
505
|
+
idx : int
|
|
506
|
+
Edge index (0-based).
|
|
507
|
+
|
|
508
|
+
Returns
|
|
509
|
+
-------
|
|
510
|
+
tuple[int, int, int]
|
|
511
|
+
Tuple of (v0, v1, ref).
|
|
512
|
+
|
|
513
|
+
"""
|
|
514
|
+
|
|
515
|
+
def set_corners(self, vertex_indices: NDArray[np.int32]) -> None:
|
|
516
|
+
"""Mark vertices as corners (preserved during remeshing).
|
|
517
|
+
|
|
518
|
+
Parameters
|
|
519
|
+
----------
|
|
520
|
+
vertex_indices : NDArray[np.int32]
|
|
521
|
+
Indices of corner vertices (0-based).
|
|
522
|
+
|
|
523
|
+
"""
|
|
524
|
+
|
|
525
|
+
def set_required_vertices(self, vertex_indices: NDArray[np.int32]) -> None:
|
|
526
|
+
"""Mark vertices as required (cannot be removed).
|
|
527
|
+
|
|
528
|
+
Parameters
|
|
529
|
+
----------
|
|
530
|
+
vertex_indices : NDArray[np.int32]
|
|
531
|
+
Indices of required vertices (0-based).
|
|
532
|
+
|
|
533
|
+
"""
|
|
534
|
+
|
|
535
|
+
def set_ridge_edges(self, edge_indices: NDArray[np.int32]) -> None:
|
|
536
|
+
"""Mark edges as ridges (sharp features preserved).
|
|
537
|
+
|
|
538
|
+
Parameters
|
|
539
|
+
----------
|
|
540
|
+
edge_indices : NDArray[np.int32]
|
|
541
|
+
Indices of ridge edges (0-based).
|
|
542
|
+
|
|
543
|
+
"""
|
|
544
|
+
|
|
545
|
+
def get_adjacent_elements(self, idx: int) -> NDArray[np.int32]:
|
|
546
|
+
"""Get indices of tetrahedra sharing faces with element idx.
|
|
547
|
+
|
|
548
|
+
Parameters
|
|
549
|
+
----------
|
|
550
|
+
idx : int
|
|
551
|
+
Element index (0-based).
|
|
552
|
+
|
|
553
|
+
Returns
|
|
554
|
+
-------
|
|
555
|
+
NDArray[np.int32]
|
|
556
|
+
Array of 4 indices (-1 indicates boundary).
|
|
557
|
+
|
|
558
|
+
"""
|
|
559
|
+
|
|
560
|
+
def get_vertex_neighbors(self, idx: int) -> NDArray[np.int32]:
|
|
561
|
+
"""Get indices of vertices connected to vertex idx by an edge.
|
|
562
|
+
|
|
563
|
+
Parameters
|
|
564
|
+
----------
|
|
565
|
+
idx : int
|
|
566
|
+
Vertex index (0-based).
|
|
567
|
+
|
|
568
|
+
Returns
|
|
569
|
+
-------
|
|
570
|
+
NDArray[np.int32]
|
|
571
|
+
Array of neighbor vertex indices.
|
|
572
|
+
|
|
573
|
+
"""
|
|
574
|
+
|
|
575
|
+
def get_element_quality(self, idx: int) -> float:
|
|
576
|
+
"""Get quality metric for a tetrahedron.
|
|
577
|
+
|
|
578
|
+
Parameters
|
|
579
|
+
----------
|
|
580
|
+
idx : int
|
|
581
|
+
Tetrahedron index (0-based).
|
|
582
|
+
|
|
583
|
+
Returns
|
|
584
|
+
-------
|
|
585
|
+
float
|
|
586
|
+
Quality metric (0-1, higher is better).
|
|
587
|
+
|
|
588
|
+
"""
|
|
589
|
+
|
|
590
|
+
def get_element_qualities(self) -> NDArray[np.float64]:
|
|
591
|
+
"""Get quality metrics for all tetrahedra.
|
|
592
|
+
|
|
593
|
+
Returns
|
|
594
|
+
-------
|
|
595
|
+
NDArray[np.float64]
|
|
596
|
+
Quality metrics for all elements.
|
|
597
|
+
|
|
598
|
+
"""
|
|
599
|
+
|
|
600
|
+
def set_prism(
|
|
601
|
+
self,
|
|
602
|
+
v0: int,
|
|
603
|
+
v1: int,
|
|
604
|
+
v2: int,
|
|
605
|
+
v3: int,
|
|
606
|
+
v4: int,
|
|
607
|
+
v5: int,
|
|
608
|
+
ref: int,
|
|
609
|
+
idx: int,
|
|
610
|
+
) -> None:
|
|
611
|
+
"""Set a single prism element.
|
|
612
|
+
|
|
613
|
+
Parameters
|
|
614
|
+
----------
|
|
615
|
+
v0, v1, v2, v3, v4, v5 : int
|
|
616
|
+
Vertex indices (0-based).
|
|
617
|
+
ref : int
|
|
618
|
+
Reference marker.
|
|
619
|
+
idx : int
|
|
620
|
+
Prism index (0-based).
|
|
621
|
+
|
|
622
|
+
"""
|
|
623
|
+
|
|
624
|
+
def set_quadrilateral(
|
|
625
|
+
self,
|
|
626
|
+
v0: int,
|
|
627
|
+
v1: int,
|
|
628
|
+
v2: int,
|
|
629
|
+
v3: int,
|
|
630
|
+
ref: int,
|
|
631
|
+
idx: int,
|
|
632
|
+
) -> None:
|
|
633
|
+
"""Set a single quadrilateral.
|
|
634
|
+
|
|
635
|
+
Parameters
|
|
636
|
+
----------
|
|
637
|
+
v0, v1, v2, v3 : int
|
|
638
|
+
Vertex indices (0-based).
|
|
639
|
+
ref : int
|
|
640
|
+
Reference marker.
|
|
641
|
+
idx : int
|
|
642
|
+
Quadrilateral index (0-based).
|
|
643
|
+
|
|
644
|
+
"""
|
|
645
|
+
|
|
646
|
+
def set_prisms(
|
|
647
|
+
self,
|
|
648
|
+
prisms: NDArray[np.int32],
|
|
649
|
+
refs: NDArray[np.int64] | None = None,
|
|
650
|
+
) -> None:
|
|
651
|
+
"""Set all prisms.
|
|
652
|
+
|
|
653
|
+
Parameters
|
|
654
|
+
----------
|
|
655
|
+
prisms : NDArray[np.int32]
|
|
656
|
+
Prism connectivity, shape (n_prisms, 6).
|
|
657
|
+
refs : NDArray[np.int64] | None
|
|
658
|
+
Reference markers for each prism.
|
|
659
|
+
|
|
660
|
+
"""
|
|
661
|
+
|
|
662
|
+
def set_quadrilaterals(
|
|
663
|
+
self,
|
|
664
|
+
quads: NDArray[np.int32],
|
|
665
|
+
refs: NDArray[np.int64] | None = None,
|
|
666
|
+
) -> None:
|
|
667
|
+
"""Set all quadrilaterals.
|
|
668
|
+
|
|
669
|
+
Parameters
|
|
670
|
+
----------
|
|
671
|
+
quads : NDArray[np.int32]
|
|
672
|
+
Quadrilateral connectivity, shape (n_quads, 4).
|
|
673
|
+
refs : NDArray[np.int64] | None
|
|
674
|
+
Reference markers for each quadrilateral.
|
|
675
|
+
|
|
676
|
+
"""
|
|
677
|
+
|
|
678
|
+
def get_prism(self, idx: int) -> tuple[int, int, int, int, int, int, int]:
|
|
679
|
+
"""Get a single prism.
|
|
680
|
+
|
|
681
|
+
Parameters
|
|
682
|
+
----------
|
|
683
|
+
idx : int
|
|
684
|
+
Prism index (0-based).
|
|
685
|
+
|
|
686
|
+
Returns
|
|
687
|
+
-------
|
|
688
|
+
tuple[int, int, int, int, int, int, int]
|
|
689
|
+
Tuple of (v0, v1, v2, v3, v4, v5, ref).
|
|
690
|
+
|
|
691
|
+
"""
|
|
692
|
+
|
|
693
|
+
def get_quadrilateral(self, idx: int) -> tuple[int, int, int, int, int]:
|
|
694
|
+
"""Get a single quadrilateral.
|
|
695
|
+
|
|
696
|
+
Parameters
|
|
697
|
+
----------
|
|
698
|
+
idx : int
|
|
699
|
+
Quadrilateral index (0-based).
|
|
700
|
+
|
|
701
|
+
Returns
|
|
702
|
+
-------
|
|
703
|
+
tuple[int, int, int, int, int]
|
|
704
|
+
Tuple of (v0, v1, v2, v3, ref).
|
|
705
|
+
|
|
706
|
+
"""
|
|
707
|
+
|
|
708
|
+
def get_prisms(self) -> NDArray[np.int32]:
|
|
709
|
+
"""Get all prism connectivity.
|
|
710
|
+
|
|
711
|
+
Returns
|
|
712
|
+
-------
|
|
713
|
+
NDArray[np.int32]
|
|
714
|
+
Prism connectivity, shape (n_prisms, 6).
|
|
715
|
+
|
|
716
|
+
"""
|
|
717
|
+
|
|
718
|
+
def get_prisms_with_refs(
|
|
719
|
+
self,
|
|
720
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
721
|
+
"""Get prism connectivity with reference markers.
|
|
722
|
+
|
|
723
|
+
Returns
|
|
724
|
+
-------
|
|
725
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
726
|
+
Tuple of (prisms, refs).
|
|
727
|
+
|
|
728
|
+
"""
|
|
729
|
+
|
|
730
|
+
def get_quadrilaterals(self) -> NDArray[np.int32]:
|
|
731
|
+
"""Get all quadrilateral connectivity.
|
|
732
|
+
|
|
733
|
+
Returns
|
|
734
|
+
-------
|
|
735
|
+
NDArray[np.int32]
|
|
736
|
+
Quadrilateral connectivity, shape (n_quads, 4).
|
|
737
|
+
|
|
738
|
+
"""
|
|
739
|
+
|
|
740
|
+
def get_quadrilaterals_with_refs(
|
|
741
|
+
self,
|
|
742
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
743
|
+
"""Get quadrilateral connectivity with reference markers.
|
|
744
|
+
|
|
745
|
+
Returns
|
|
746
|
+
-------
|
|
747
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
748
|
+
Tuple of (quadrilaterals, refs).
|
|
749
|
+
|
|
750
|
+
"""
|
|
751
|
+
|
|
752
|
+
def get_tetrahedra(self) -> NDArray[np.int32]:
|
|
753
|
+
"""Get all tetrahedra connectivity.
|
|
754
|
+
|
|
755
|
+
Returns
|
|
756
|
+
-------
|
|
757
|
+
NDArray[np.int32]
|
|
758
|
+
Tetrahedra connectivity, shape (n_tetrahedra, 4).
|
|
759
|
+
|
|
760
|
+
"""
|
|
761
|
+
|
|
762
|
+
def get_tetrahedra_with_refs(
|
|
763
|
+
self,
|
|
764
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
765
|
+
"""Get tetrahedra connectivity with reference markers.
|
|
766
|
+
|
|
767
|
+
Returns
|
|
768
|
+
-------
|
|
769
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
770
|
+
Tuple of (tetrahedra, refs).
|
|
771
|
+
|
|
772
|
+
"""
|
|
773
|
+
|
|
774
|
+
def set_field(self, key: str, value: NDArray[np.float64]) -> None:
|
|
775
|
+
"""Set a solution field on vertices.
|
|
776
|
+
|
|
777
|
+
Parameters
|
|
778
|
+
----------
|
|
779
|
+
key : str
|
|
780
|
+
Field name: "metric", "displacement", "levelset", or "tensor".
|
|
781
|
+
value : NDArray[np.float64]
|
|
782
|
+
Field values (one row per vertex). Shape depends on field type:
|
|
783
|
+
- "metric": (n_vertices, 1) - isotropic sizing
|
|
784
|
+
- "displacement": (n_vertices, 3) - motion vectors
|
|
785
|
+
- "levelset": (n_vertices, 1) - signed distance
|
|
786
|
+
- "tensor": (n_vertices, 6) - anisotropic metric
|
|
787
|
+
|
|
788
|
+
"""
|
|
789
|
+
|
|
790
|
+
def get_field(self, key: str) -> NDArray[np.float64]:
|
|
791
|
+
"""Get a solution field from vertices.
|
|
792
|
+
|
|
793
|
+
Parameters
|
|
794
|
+
----------
|
|
795
|
+
key : str
|
|
796
|
+
Field name: "metric", "displacement", "levelset", or "tensor".
|
|
797
|
+
|
|
798
|
+
Returns
|
|
799
|
+
-------
|
|
800
|
+
NDArray[np.float64]
|
|
801
|
+
Field values (one row per vertex).
|
|
802
|
+
|
|
803
|
+
"""
|
|
804
|
+
|
|
805
|
+
def __setitem__(self, key: str, value: NDArray[np.float64]) -> None:
|
|
806
|
+
"""Set a solution field using dictionary syntax.
|
|
807
|
+
|
|
808
|
+
Equivalent to set_field(key, value).
|
|
809
|
+
"""
|
|
810
|
+
|
|
811
|
+
def __getitem__(self, key: str) -> NDArray[np.float64]:
|
|
812
|
+
"""Get a solution field using dictionary syntax.
|
|
813
|
+
|
|
814
|
+
Equivalent to get_field(key).
|
|
815
|
+
"""
|
|
816
|
+
|
|
817
|
+
def save(self, filename: str | Path) -> None:
|
|
818
|
+
"""Save mesh to file.
|
|
819
|
+
|
|
820
|
+
Parameters
|
|
821
|
+
----------
|
|
822
|
+
filename : str | Path
|
|
823
|
+
Output file path. Format determined by extension
|
|
824
|
+
(.mesh, .vtk, .vtu).
|
|
825
|
+
|
|
826
|
+
"""
|
|
827
|
+
|
|
828
|
+
def remesh(
|
|
829
|
+
self,
|
|
830
|
+
*,
|
|
831
|
+
hmin: float | None = None,
|
|
832
|
+
hmax: float | None = None,
|
|
833
|
+
hsiz: float | None = None,
|
|
834
|
+
hausd: float | None = None,
|
|
835
|
+
hgrad: float | None = None,
|
|
836
|
+
verbose: int | bool | None = None,
|
|
837
|
+
optim: int | None = None,
|
|
838
|
+
noinsert: int | None = None,
|
|
839
|
+
noswap: int | None = None,
|
|
840
|
+
nomove: int | None = None,
|
|
841
|
+
nosurf: int | None = None,
|
|
842
|
+
**kwargs: float | None,
|
|
843
|
+
) -> dict[str, Any]:
|
|
844
|
+
"""Remesh the mesh in-place.
|
|
845
|
+
|
|
846
|
+
Parameters
|
|
847
|
+
----------
|
|
848
|
+
hmin : float | None
|
|
849
|
+
Minimum edge size.
|
|
850
|
+
hmax : float | None
|
|
851
|
+
Maximum edge size.
|
|
852
|
+
hsiz : float | None
|
|
853
|
+
Uniform target edge size.
|
|
854
|
+
hausd : float | None
|
|
855
|
+
Hausdorff distance for geometry approximation.
|
|
856
|
+
hgrad : float | None
|
|
857
|
+
Gradation parameter (controls size transition).
|
|
858
|
+
verbose : int | bool | None
|
|
859
|
+
Verbosity level. True/False converted to 1/-1.
|
|
860
|
+
optim : int | None
|
|
861
|
+
Optimization mode (1 = optimize without topology changes).
|
|
862
|
+
noinsert : int | None
|
|
863
|
+
Disable vertex insertion (1 = disabled).
|
|
864
|
+
noswap : int | None
|
|
865
|
+
Disable edge/face swapping (1 = disabled).
|
|
866
|
+
nomove : int | None
|
|
867
|
+
Disable vertex relocation (1 = disabled).
|
|
868
|
+
nosurf : int | None
|
|
869
|
+
Disable surface modifications (1 = disabled).
|
|
870
|
+
**kwargs : float | int | None
|
|
871
|
+
Additional MMG options.
|
|
872
|
+
|
|
873
|
+
Returns
|
|
874
|
+
-------
|
|
875
|
+
dict[str, Any]
|
|
876
|
+
Statistics dictionary with before/after metrics.
|
|
877
|
+
|
|
878
|
+
"""
|
|
879
|
+
|
|
880
|
+
def remesh_lagrangian(
|
|
881
|
+
self,
|
|
882
|
+
displacement: NDArray[np.float64],
|
|
883
|
+
*,
|
|
884
|
+
hmin: float | None = None,
|
|
885
|
+
hmax: float | None = None,
|
|
886
|
+
hsiz: float | None = None,
|
|
887
|
+
hausd: float | None = None,
|
|
888
|
+
hgrad: float | None = None,
|
|
889
|
+
verbose: int | bool | None = None,
|
|
890
|
+
lag: int | None = None,
|
|
891
|
+
**kwargs: float | None,
|
|
892
|
+
) -> dict[str, Any]:
|
|
893
|
+
"""Remesh following Lagrangian motion.
|
|
894
|
+
|
|
895
|
+
Moves the mesh according to a displacement field while
|
|
896
|
+
maintaining mesh quality.
|
|
897
|
+
|
|
898
|
+
Parameters
|
|
899
|
+
----------
|
|
900
|
+
displacement : NDArray[np.float64]
|
|
901
|
+
Displacement vectors, shape (n_vertices, 3).
|
|
902
|
+
hmin : float | None
|
|
903
|
+
Minimum edge size.
|
|
904
|
+
hmax : float | None
|
|
905
|
+
Maximum edge size.
|
|
906
|
+
hsiz : float | None
|
|
907
|
+
Uniform target edge size.
|
|
908
|
+
hausd : float | None
|
|
909
|
+
Hausdorff distance for geometry approximation.
|
|
910
|
+
hgrad : float | None
|
|
911
|
+
Gradation parameter.
|
|
912
|
+
verbose : int | bool | None
|
|
913
|
+
Verbosity level.
|
|
914
|
+
lag : int | None
|
|
915
|
+
Lagrangian mode: 0=velocity, 1=displacement (default), 2=final position.
|
|
916
|
+
**kwargs : float | int | None
|
|
917
|
+
Additional MMG options.
|
|
918
|
+
|
|
919
|
+
Returns
|
|
920
|
+
-------
|
|
921
|
+
dict[str, Any]
|
|
922
|
+
Statistics dictionary with before/after metrics.
|
|
923
|
+
|
|
924
|
+
"""
|
|
925
|
+
|
|
926
|
+
def remesh_levelset(
|
|
927
|
+
self,
|
|
928
|
+
levelset: NDArray[np.float64],
|
|
929
|
+
*,
|
|
930
|
+
ls: float | None = None,
|
|
931
|
+
hmin: float | None = None,
|
|
932
|
+
hmax: float | None = None,
|
|
933
|
+
hsiz: float | None = None,
|
|
934
|
+
hausd: float | None = None,
|
|
935
|
+
hgrad: float | None = None,
|
|
936
|
+
verbose: int | bool | None = None,
|
|
937
|
+
iso: int | None = None,
|
|
938
|
+
**kwargs: float | None,
|
|
939
|
+
) -> dict[str, Any]:
|
|
940
|
+
"""Remesh to conform to a level-set isosurface.
|
|
941
|
+
|
|
942
|
+
Discretizes the zero level-set (or specified isovalue) and
|
|
943
|
+
creates a mesh that conforms to this surface.
|
|
944
|
+
|
|
945
|
+
Parameters
|
|
946
|
+
----------
|
|
947
|
+
levelset : NDArray[np.float64]
|
|
948
|
+
Level-set values, shape (n_vertices, 1).
|
|
949
|
+
ls : float | None
|
|
950
|
+
Isovalue to discretize (default 0.0).
|
|
951
|
+
hmin : float | None
|
|
952
|
+
Minimum edge size.
|
|
953
|
+
hmax : float | None
|
|
954
|
+
Maximum edge size.
|
|
955
|
+
hsiz : float | None
|
|
956
|
+
Uniform target edge size.
|
|
957
|
+
hausd : float | None
|
|
958
|
+
Hausdorff distance for geometry approximation.
|
|
959
|
+
hgrad : float | None
|
|
960
|
+
Gradation parameter.
|
|
961
|
+
verbose : int | bool | None
|
|
962
|
+
Verbosity level.
|
|
963
|
+
iso : int | None
|
|
964
|
+
Enable level-set mode (default 1).
|
|
965
|
+
**kwargs : float | int | None
|
|
966
|
+
Additional MMG options.
|
|
967
|
+
|
|
968
|
+
Returns
|
|
969
|
+
-------
|
|
970
|
+
dict[str, Any]
|
|
971
|
+
Statistics dictionary with before/after metrics.
|
|
972
|
+
|
|
973
|
+
"""
|
|
974
|
+
|
|
975
|
+
class MmgMesh2D:
|
|
976
|
+
"""2D triangular mesh class for in-memory remeshing.
|
|
977
|
+
|
|
978
|
+
All element indices in this class are 0-based (Python convention).
|
|
979
|
+
The underlying MMG library uses 1-based indexing, but the bindings
|
|
980
|
+
handle this conversion automatically.
|
|
981
|
+
"""
|
|
982
|
+
|
|
983
|
+
@overload
|
|
984
|
+
def __init__(self) -> None:
|
|
985
|
+
"""Create an empty 2D mesh."""
|
|
986
|
+
|
|
987
|
+
@overload
|
|
988
|
+
def __init__(
|
|
989
|
+
self,
|
|
990
|
+
vertices: NDArray[np.float64],
|
|
991
|
+
triangles: NDArray[np.int32],
|
|
992
|
+
) -> None:
|
|
993
|
+
"""Create a 2D mesh from vertices and triangles.
|
|
994
|
+
|
|
995
|
+
Parameters
|
|
996
|
+
----------
|
|
997
|
+
vertices : NDArray[np.float64]
|
|
998
|
+
Vertex coordinates, shape (n_vertices, 2).
|
|
999
|
+
triangles : NDArray[np.int32]
|
|
1000
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
1001
|
+
|
|
1002
|
+
"""
|
|
1003
|
+
|
|
1004
|
+
@overload
|
|
1005
|
+
def __init__(
|
|
1006
|
+
self,
|
|
1007
|
+
filename: str | Path,
|
|
1008
|
+
) -> None:
|
|
1009
|
+
"""Load a 2D mesh from file.
|
|
1010
|
+
|
|
1011
|
+
Parameters
|
|
1012
|
+
----------
|
|
1013
|
+
filename : str | Path
|
|
1014
|
+
Path to mesh file (.mesh, .vtk, .vtu format).
|
|
1015
|
+
|
|
1016
|
+
"""
|
|
1017
|
+
|
|
1018
|
+
def set_mesh_size(
|
|
1019
|
+
self,
|
|
1020
|
+
vertices: int = 0,
|
|
1021
|
+
triangles: int = 0,
|
|
1022
|
+
quadrilaterals: int = 0,
|
|
1023
|
+
edges: int = 0,
|
|
1024
|
+
) -> None:
|
|
1025
|
+
"""Allocate mesh storage for the specified element counts.
|
|
1026
|
+
|
|
1027
|
+
Parameters
|
|
1028
|
+
----------
|
|
1029
|
+
vertices : int
|
|
1030
|
+
Number of vertices.
|
|
1031
|
+
triangles : int
|
|
1032
|
+
Number of triangles.
|
|
1033
|
+
quadrilaterals : int
|
|
1034
|
+
Number of quadrilaterals.
|
|
1035
|
+
edges : int
|
|
1036
|
+
Number of edges (boundary edges).
|
|
1037
|
+
|
|
1038
|
+
"""
|
|
1039
|
+
|
|
1040
|
+
def get_mesh_size(self) -> tuple[int, int, int, int]:
|
|
1041
|
+
"""Get current mesh element counts.
|
|
1042
|
+
|
|
1043
|
+
Returns
|
|
1044
|
+
-------
|
|
1045
|
+
tuple[int, int, int, int]
|
|
1046
|
+
Tuple of (vertices, triangles, quadrilaterals, edges).
|
|
1047
|
+
|
|
1048
|
+
"""
|
|
1049
|
+
|
|
1050
|
+
def set_vertices(
|
|
1051
|
+
self,
|
|
1052
|
+
vertices: NDArray[np.float64],
|
|
1053
|
+
refs: NDArray[np.int64] | None = None,
|
|
1054
|
+
) -> None:
|
|
1055
|
+
"""Set all vertex coordinates.
|
|
1056
|
+
|
|
1057
|
+
Parameters
|
|
1058
|
+
----------
|
|
1059
|
+
vertices : NDArray[np.float64]
|
|
1060
|
+
Vertex coordinates, shape (n_vertices, 2).
|
|
1061
|
+
refs : NDArray[np.int64] | None
|
|
1062
|
+
Reference markers for each vertex.
|
|
1063
|
+
|
|
1064
|
+
"""
|
|
1065
|
+
|
|
1066
|
+
def set_triangles(
|
|
1067
|
+
self,
|
|
1068
|
+
triangles: NDArray[np.int32],
|
|
1069
|
+
refs: NDArray[np.int64] | None = None,
|
|
1070
|
+
) -> None:
|
|
1071
|
+
"""Set all triangles.
|
|
1072
|
+
|
|
1073
|
+
Parameters
|
|
1074
|
+
----------
|
|
1075
|
+
triangles : NDArray[np.int32]
|
|
1076
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
1077
|
+
refs : NDArray[np.int64] | None
|
|
1078
|
+
Reference markers for each triangle.
|
|
1079
|
+
|
|
1080
|
+
"""
|
|
1081
|
+
|
|
1082
|
+
def set_quadrilaterals(
|
|
1083
|
+
self,
|
|
1084
|
+
quads: NDArray[np.int32],
|
|
1085
|
+
refs: NDArray[np.int64] | None = None,
|
|
1086
|
+
) -> None:
|
|
1087
|
+
"""Set all quadrilaterals.
|
|
1088
|
+
|
|
1089
|
+
Parameters
|
|
1090
|
+
----------
|
|
1091
|
+
quads : NDArray[np.int32]
|
|
1092
|
+
Quadrilateral connectivity, shape (n_quads, 4).
|
|
1093
|
+
refs : NDArray[np.int64] | None
|
|
1094
|
+
Reference markers for each quadrilateral.
|
|
1095
|
+
|
|
1096
|
+
"""
|
|
1097
|
+
|
|
1098
|
+
def set_edges(
|
|
1099
|
+
self,
|
|
1100
|
+
edges: NDArray[np.int32],
|
|
1101
|
+
refs: NDArray[np.int64] | None = None,
|
|
1102
|
+
) -> None:
|
|
1103
|
+
"""Set all edges.
|
|
1104
|
+
|
|
1105
|
+
Parameters
|
|
1106
|
+
----------
|
|
1107
|
+
edges : NDArray[np.int32]
|
|
1108
|
+
Edge connectivity, shape (n_edges, 2).
|
|
1109
|
+
refs : NDArray[np.int64] | None
|
|
1110
|
+
Reference markers for each edge.
|
|
1111
|
+
|
|
1112
|
+
"""
|
|
1113
|
+
|
|
1114
|
+
def get_vertices(self) -> NDArray[np.float64]:
|
|
1115
|
+
"""Get vertex coordinates.
|
|
1116
|
+
|
|
1117
|
+
Returns
|
|
1118
|
+
-------
|
|
1119
|
+
NDArray[np.float64]
|
|
1120
|
+
Vertex coordinates, shape (n_vertices, 2).
|
|
1121
|
+
|
|
1122
|
+
"""
|
|
1123
|
+
|
|
1124
|
+
def get_vertices_with_refs(
|
|
1125
|
+
self,
|
|
1126
|
+
) -> tuple[NDArray[np.float64], NDArray[np.int64]]:
|
|
1127
|
+
"""Get vertex coordinates with reference markers.
|
|
1128
|
+
|
|
1129
|
+
Returns
|
|
1130
|
+
-------
|
|
1131
|
+
tuple[NDArray[np.float64], NDArray[np.int64]]
|
|
1132
|
+
Tuple of (vertices, refs).
|
|
1133
|
+
|
|
1134
|
+
"""
|
|
1135
|
+
|
|
1136
|
+
def get_triangles(self) -> NDArray[np.int32]:
|
|
1137
|
+
"""Get triangle connectivity.
|
|
1138
|
+
|
|
1139
|
+
Returns
|
|
1140
|
+
-------
|
|
1141
|
+
NDArray[np.int32]
|
|
1142
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
1143
|
+
|
|
1144
|
+
"""
|
|
1145
|
+
|
|
1146
|
+
def get_triangles_with_refs(
|
|
1147
|
+
self,
|
|
1148
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
1149
|
+
"""Get triangle connectivity with reference markers.
|
|
1150
|
+
|
|
1151
|
+
Returns
|
|
1152
|
+
-------
|
|
1153
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
1154
|
+
Tuple of (triangles, refs).
|
|
1155
|
+
|
|
1156
|
+
"""
|
|
1157
|
+
|
|
1158
|
+
def get_quadrilaterals(self) -> NDArray[np.int32]:
|
|
1159
|
+
"""Get quadrilateral connectivity.
|
|
1160
|
+
|
|
1161
|
+
Returns
|
|
1162
|
+
-------
|
|
1163
|
+
NDArray[np.int32]
|
|
1164
|
+
Quadrilateral connectivity, shape (n_quads, 4).
|
|
1165
|
+
|
|
1166
|
+
"""
|
|
1167
|
+
|
|
1168
|
+
def get_quadrilaterals_with_refs(
|
|
1169
|
+
self,
|
|
1170
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
1171
|
+
"""Get quadrilateral connectivity with reference markers.
|
|
1172
|
+
|
|
1173
|
+
Returns
|
|
1174
|
+
-------
|
|
1175
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
1176
|
+
Tuple of (quadrilaterals, refs).
|
|
1177
|
+
|
|
1178
|
+
"""
|
|
1179
|
+
|
|
1180
|
+
def get_edges(self) -> NDArray[np.int32]:
|
|
1181
|
+
"""Get edge connectivity.
|
|
1182
|
+
|
|
1183
|
+
Returns
|
|
1184
|
+
-------
|
|
1185
|
+
NDArray[np.int32]
|
|
1186
|
+
Edge connectivity, shape (n_edges, 2).
|
|
1187
|
+
|
|
1188
|
+
"""
|
|
1189
|
+
|
|
1190
|
+
def get_edges_with_refs(
|
|
1191
|
+
self,
|
|
1192
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
1193
|
+
"""Get edge connectivity with reference markers.
|
|
1194
|
+
|
|
1195
|
+
Returns
|
|
1196
|
+
-------
|
|
1197
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
1198
|
+
Tuple of (edges, refs).
|
|
1199
|
+
|
|
1200
|
+
"""
|
|
1201
|
+
|
|
1202
|
+
def set_vertex(self, x: float, y: float, ref: int, idx: int) -> None:
|
|
1203
|
+
"""Set a single vertex.
|
|
1204
|
+
|
|
1205
|
+
Parameters
|
|
1206
|
+
----------
|
|
1207
|
+
x, y : float
|
|
1208
|
+
Vertex coordinates.
|
|
1209
|
+
ref : int
|
|
1210
|
+
Reference marker.
|
|
1211
|
+
idx : int
|
|
1212
|
+
Vertex index (0-based).
|
|
1213
|
+
|
|
1214
|
+
"""
|
|
1215
|
+
|
|
1216
|
+
def set_triangle(
|
|
1217
|
+
self,
|
|
1218
|
+
v0: int,
|
|
1219
|
+
v1: int,
|
|
1220
|
+
v2: int,
|
|
1221
|
+
ref: int,
|
|
1222
|
+
idx: int,
|
|
1223
|
+
) -> None:
|
|
1224
|
+
"""Set a single triangle.
|
|
1225
|
+
|
|
1226
|
+
Parameters
|
|
1227
|
+
----------
|
|
1228
|
+
v0, v1, v2 : int
|
|
1229
|
+
Vertex indices (0-based).
|
|
1230
|
+
ref : int
|
|
1231
|
+
Reference marker.
|
|
1232
|
+
idx : int
|
|
1233
|
+
Triangle index (0-based).
|
|
1234
|
+
|
|
1235
|
+
"""
|
|
1236
|
+
|
|
1237
|
+
def set_quadrilateral(
|
|
1238
|
+
self,
|
|
1239
|
+
v0: int,
|
|
1240
|
+
v1: int,
|
|
1241
|
+
v2: int,
|
|
1242
|
+
v3: int,
|
|
1243
|
+
ref: int,
|
|
1244
|
+
idx: int,
|
|
1245
|
+
) -> None:
|
|
1246
|
+
"""Set a single quadrilateral.
|
|
1247
|
+
|
|
1248
|
+
Parameters
|
|
1249
|
+
----------
|
|
1250
|
+
v0, v1, v2, v3 : int
|
|
1251
|
+
Vertex indices (0-based).
|
|
1252
|
+
ref : int
|
|
1253
|
+
Reference marker.
|
|
1254
|
+
idx : int
|
|
1255
|
+
Quadrilateral index (0-based).
|
|
1256
|
+
|
|
1257
|
+
"""
|
|
1258
|
+
|
|
1259
|
+
def set_edge(self, v0: int, v1: int, ref: int, idx: int) -> None:
|
|
1260
|
+
"""Set a single edge.
|
|
1261
|
+
|
|
1262
|
+
Parameters
|
|
1263
|
+
----------
|
|
1264
|
+
v0, v1 : int
|
|
1265
|
+
Vertex indices (0-based).
|
|
1266
|
+
ref : int
|
|
1267
|
+
Reference marker.
|
|
1268
|
+
idx : int
|
|
1269
|
+
Edge index (0-based).
|
|
1270
|
+
|
|
1271
|
+
"""
|
|
1272
|
+
|
|
1273
|
+
def get_vertex(self, idx: int) -> tuple[float, float, int]:
|
|
1274
|
+
"""Get a single vertex.
|
|
1275
|
+
|
|
1276
|
+
Parameters
|
|
1277
|
+
----------
|
|
1278
|
+
idx : int
|
|
1279
|
+
Vertex index (0-based).
|
|
1280
|
+
|
|
1281
|
+
Returns
|
|
1282
|
+
-------
|
|
1283
|
+
tuple[float, float, int]
|
|
1284
|
+
Tuple of (x, y, ref).
|
|
1285
|
+
|
|
1286
|
+
"""
|
|
1287
|
+
|
|
1288
|
+
def get_triangle(self, idx: int) -> tuple[int, int, int, int]:
|
|
1289
|
+
"""Get a single triangle.
|
|
1290
|
+
|
|
1291
|
+
Parameters
|
|
1292
|
+
----------
|
|
1293
|
+
idx : int
|
|
1294
|
+
Triangle index (0-based).
|
|
1295
|
+
|
|
1296
|
+
Returns
|
|
1297
|
+
-------
|
|
1298
|
+
tuple[int, int, int, int]
|
|
1299
|
+
Tuple of (v0, v1, v2, ref).
|
|
1300
|
+
|
|
1301
|
+
"""
|
|
1302
|
+
|
|
1303
|
+
def get_quadrilateral(self, idx: int) -> tuple[int, int, int, int, int]:
|
|
1304
|
+
"""Get a single quadrilateral.
|
|
1305
|
+
|
|
1306
|
+
Parameters
|
|
1307
|
+
----------
|
|
1308
|
+
idx : int
|
|
1309
|
+
Quadrilateral index (0-based).
|
|
1310
|
+
|
|
1311
|
+
Returns
|
|
1312
|
+
-------
|
|
1313
|
+
tuple[int, int, int, int, int]
|
|
1314
|
+
Tuple of (v0, v1, v2, v3, ref).
|
|
1315
|
+
|
|
1316
|
+
"""
|
|
1317
|
+
|
|
1318
|
+
def get_edge(self, idx: int) -> tuple[int, int, int]:
|
|
1319
|
+
"""Get a single edge.
|
|
1320
|
+
|
|
1321
|
+
Parameters
|
|
1322
|
+
----------
|
|
1323
|
+
idx : int
|
|
1324
|
+
Edge index (0-based).
|
|
1325
|
+
|
|
1326
|
+
Returns
|
|
1327
|
+
-------
|
|
1328
|
+
tuple[int, int, int]
|
|
1329
|
+
Tuple of (v0, v1, ref).
|
|
1330
|
+
|
|
1331
|
+
"""
|
|
1332
|
+
|
|
1333
|
+
def set_corners(self, vertex_indices: NDArray[np.int32]) -> None:
|
|
1334
|
+
"""Mark vertices as corners (preserved during remeshing).
|
|
1335
|
+
|
|
1336
|
+
Parameters
|
|
1337
|
+
----------
|
|
1338
|
+
vertex_indices : NDArray[np.int32]
|
|
1339
|
+
Indices of corner vertices (0-based).
|
|
1340
|
+
|
|
1341
|
+
"""
|
|
1342
|
+
|
|
1343
|
+
def set_required_vertices(self, vertex_indices: NDArray[np.int32]) -> None:
|
|
1344
|
+
"""Mark vertices as required (cannot be removed).
|
|
1345
|
+
|
|
1346
|
+
Parameters
|
|
1347
|
+
----------
|
|
1348
|
+
vertex_indices : NDArray[np.int32]
|
|
1349
|
+
Indices of required vertices (0-based).
|
|
1350
|
+
|
|
1351
|
+
"""
|
|
1352
|
+
|
|
1353
|
+
def set_required_edges(self, edge_indices: NDArray[np.int32]) -> None:
|
|
1354
|
+
"""Mark edges as required (cannot be modified).
|
|
1355
|
+
|
|
1356
|
+
Parameters
|
|
1357
|
+
----------
|
|
1358
|
+
edge_indices : NDArray[np.int32]
|
|
1359
|
+
Indices of required edges (0-based).
|
|
1360
|
+
|
|
1361
|
+
"""
|
|
1362
|
+
|
|
1363
|
+
def get_adjacent_elements(self, idx: int) -> NDArray[np.int32]:
|
|
1364
|
+
"""Get indices of triangles sharing edges with element idx.
|
|
1365
|
+
|
|
1366
|
+
Parameters
|
|
1367
|
+
----------
|
|
1368
|
+
idx : int
|
|
1369
|
+
Element index (0-based).
|
|
1370
|
+
|
|
1371
|
+
Returns
|
|
1372
|
+
-------
|
|
1373
|
+
NDArray[np.int32]
|
|
1374
|
+
Array of 3 indices (-1 indicates boundary).
|
|
1375
|
+
|
|
1376
|
+
"""
|
|
1377
|
+
|
|
1378
|
+
def get_vertex_neighbors(self, idx: int) -> NDArray[np.int32]:
|
|
1379
|
+
"""Get indices of vertices connected to vertex idx by an edge.
|
|
1380
|
+
|
|
1381
|
+
Parameters
|
|
1382
|
+
----------
|
|
1383
|
+
idx : int
|
|
1384
|
+
Vertex index (0-based).
|
|
1385
|
+
|
|
1386
|
+
Returns
|
|
1387
|
+
-------
|
|
1388
|
+
NDArray[np.int32]
|
|
1389
|
+
Array of neighbor vertex indices.
|
|
1390
|
+
|
|
1391
|
+
"""
|
|
1392
|
+
|
|
1393
|
+
def get_element_quality(self, idx: int) -> float:
|
|
1394
|
+
"""Get quality metric for a triangle.
|
|
1395
|
+
|
|
1396
|
+
Parameters
|
|
1397
|
+
----------
|
|
1398
|
+
idx : int
|
|
1399
|
+
Triangle index (0-based).
|
|
1400
|
+
|
|
1401
|
+
Returns
|
|
1402
|
+
-------
|
|
1403
|
+
float
|
|
1404
|
+
Quality metric (0-1, higher is better).
|
|
1405
|
+
|
|
1406
|
+
"""
|
|
1407
|
+
|
|
1408
|
+
def get_element_qualities(self) -> NDArray[np.float64]:
|
|
1409
|
+
"""Get quality metrics for all triangles.
|
|
1410
|
+
|
|
1411
|
+
Returns
|
|
1412
|
+
-------
|
|
1413
|
+
NDArray[np.float64]
|
|
1414
|
+
Quality metrics for all elements.
|
|
1415
|
+
|
|
1416
|
+
"""
|
|
1417
|
+
|
|
1418
|
+
def set_field(self, key: str, value: NDArray[np.float64]) -> None:
|
|
1419
|
+
"""Set a solution field on vertices.
|
|
1420
|
+
|
|
1421
|
+
Parameters
|
|
1422
|
+
----------
|
|
1423
|
+
key : str
|
|
1424
|
+
Field name: "metric", "displacement", "levelset", or "tensor".
|
|
1425
|
+
value : NDArray[np.float64]
|
|
1426
|
+
Field values (one row per vertex).
|
|
1427
|
+
|
|
1428
|
+
"""
|
|
1429
|
+
|
|
1430
|
+
def get_field(self, key: str) -> NDArray[np.float64]:
|
|
1431
|
+
"""Get a solution field from vertices.
|
|
1432
|
+
|
|
1433
|
+
Parameters
|
|
1434
|
+
----------
|
|
1435
|
+
key : str
|
|
1436
|
+
Field name.
|
|
1437
|
+
|
|
1438
|
+
Returns
|
|
1439
|
+
-------
|
|
1440
|
+
NDArray[np.float64]
|
|
1441
|
+
Field values (one row per vertex).
|
|
1442
|
+
|
|
1443
|
+
"""
|
|
1444
|
+
|
|
1445
|
+
def __setitem__(self, key: str, value: NDArray[np.float64]) -> None:
|
|
1446
|
+
"""Set a solution field using dictionary syntax."""
|
|
1447
|
+
|
|
1448
|
+
def __getitem__(self, key: str) -> NDArray[np.float64]:
|
|
1449
|
+
"""Get a solution field using dictionary syntax."""
|
|
1450
|
+
|
|
1451
|
+
def save(self, filename: str | Path) -> None:
|
|
1452
|
+
"""Save mesh to file.
|
|
1453
|
+
|
|
1454
|
+
Parameters
|
|
1455
|
+
----------
|
|
1456
|
+
filename : str | Path
|
|
1457
|
+
Output file path. Format determined by extension.
|
|
1458
|
+
|
|
1459
|
+
"""
|
|
1460
|
+
|
|
1461
|
+
def remesh(
|
|
1462
|
+
self,
|
|
1463
|
+
*,
|
|
1464
|
+
hmin: float | None = None,
|
|
1465
|
+
hmax: float | None = None,
|
|
1466
|
+
hsiz: float | None = None,
|
|
1467
|
+
hausd: float | None = None,
|
|
1468
|
+
hgrad: float | None = None,
|
|
1469
|
+
verbose: int | bool | None = None,
|
|
1470
|
+
optim: int | None = None,
|
|
1471
|
+
noinsert: int | None = None,
|
|
1472
|
+
noswap: int | None = None,
|
|
1473
|
+
nomove: int | None = None,
|
|
1474
|
+
**kwargs: float | None,
|
|
1475
|
+
) -> dict[str, Any]:
|
|
1476
|
+
"""Remesh the mesh in-place.
|
|
1477
|
+
|
|
1478
|
+
Parameters
|
|
1479
|
+
----------
|
|
1480
|
+
hmin : float | None
|
|
1481
|
+
Minimum edge size.
|
|
1482
|
+
hmax : float | None
|
|
1483
|
+
Maximum edge size.
|
|
1484
|
+
hsiz : float | None
|
|
1485
|
+
Uniform target edge size.
|
|
1486
|
+
hausd : float | None
|
|
1487
|
+
Hausdorff distance for geometry approximation.
|
|
1488
|
+
hgrad : float | None
|
|
1489
|
+
Gradation parameter.
|
|
1490
|
+
verbose : int | bool | None
|
|
1491
|
+
Verbosity level. True/False converted to 1/-1.
|
|
1492
|
+
optim : int | None
|
|
1493
|
+
Optimization mode.
|
|
1494
|
+
noinsert : int | None
|
|
1495
|
+
Disable vertex insertion.
|
|
1496
|
+
noswap : int | None
|
|
1497
|
+
Disable edge swapping.
|
|
1498
|
+
nomove : int | None
|
|
1499
|
+
Disable vertex relocation.
|
|
1500
|
+
**kwargs : float | int | None
|
|
1501
|
+
Additional MMG options.
|
|
1502
|
+
|
|
1503
|
+
Returns
|
|
1504
|
+
-------
|
|
1505
|
+
dict[str, Any]
|
|
1506
|
+
Statistics dictionary with before/after metrics.
|
|
1507
|
+
|
|
1508
|
+
"""
|
|
1509
|
+
|
|
1510
|
+
def remesh_lagrangian(
|
|
1511
|
+
self,
|
|
1512
|
+
displacement: NDArray[np.float64],
|
|
1513
|
+
*,
|
|
1514
|
+
hmin: float | None = None,
|
|
1515
|
+
hmax: float | None = None,
|
|
1516
|
+
hsiz: float | None = None,
|
|
1517
|
+
hausd: float | None = None,
|
|
1518
|
+
hgrad: float | None = None,
|
|
1519
|
+
verbose: int | bool | None = None,
|
|
1520
|
+
lag: int | None = None,
|
|
1521
|
+
**kwargs: float | None,
|
|
1522
|
+
) -> dict[str, Any]:
|
|
1523
|
+
"""Remesh following Lagrangian motion.
|
|
1524
|
+
|
|
1525
|
+
Parameters
|
|
1526
|
+
----------
|
|
1527
|
+
displacement : NDArray[np.float64]
|
|
1528
|
+
Displacement vectors, shape (n_vertices, 2).
|
|
1529
|
+
hmin : float | None
|
|
1530
|
+
Minimum edge size.
|
|
1531
|
+
hmax : float | None
|
|
1532
|
+
Maximum edge size.
|
|
1533
|
+
hsiz : float | None
|
|
1534
|
+
Uniform target edge size.
|
|
1535
|
+
hausd : float | None
|
|
1536
|
+
Hausdorff distance for geometry approximation.
|
|
1537
|
+
hgrad : float | None
|
|
1538
|
+
Gradation parameter.
|
|
1539
|
+
verbose : int | bool | None
|
|
1540
|
+
Verbosity level.
|
|
1541
|
+
lag : int | None
|
|
1542
|
+
Lagrangian mode: 0=velocity, 1=displacement (default), 2=final position.
|
|
1543
|
+
**kwargs : float | int | None
|
|
1544
|
+
Additional MMG options.
|
|
1545
|
+
|
|
1546
|
+
Returns
|
|
1547
|
+
-------
|
|
1548
|
+
dict[str, Any]
|
|
1549
|
+
Statistics dictionary with before/after metrics.
|
|
1550
|
+
|
|
1551
|
+
"""
|
|
1552
|
+
|
|
1553
|
+
def remesh_levelset(
|
|
1554
|
+
self,
|
|
1555
|
+
levelset: NDArray[np.float64],
|
|
1556
|
+
*,
|
|
1557
|
+
ls: float | None = None,
|
|
1558
|
+
hmin: float | None = None,
|
|
1559
|
+
hmax: float | None = None,
|
|
1560
|
+
hsiz: float | None = None,
|
|
1561
|
+
hausd: float | None = None,
|
|
1562
|
+
hgrad: float | None = None,
|
|
1563
|
+
verbose: int | bool | None = None,
|
|
1564
|
+
iso: int | None = None,
|
|
1565
|
+
**kwargs: float | None,
|
|
1566
|
+
) -> dict[str, Any]:
|
|
1567
|
+
"""Remesh to conform to a level-set isoline.
|
|
1568
|
+
|
|
1569
|
+
Parameters
|
|
1570
|
+
----------
|
|
1571
|
+
levelset : NDArray[np.float64]
|
|
1572
|
+
Level-set values, shape (n_vertices, 1).
|
|
1573
|
+
ls : float | None
|
|
1574
|
+
Isovalue to discretize (default 0.0).
|
|
1575
|
+
hmin : float | None
|
|
1576
|
+
Minimum edge size.
|
|
1577
|
+
hmax : float | None
|
|
1578
|
+
Maximum edge size.
|
|
1579
|
+
hsiz : float | None
|
|
1580
|
+
Uniform target edge size.
|
|
1581
|
+
hausd : float | None
|
|
1582
|
+
Hausdorff distance for geometry approximation.
|
|
1583
|
+
hgrad : float | None
|
|
1584
|
+
Gradation parameter.
|
|
1585
|
+
verbose : int | bool | None
|
|
1586
|
+
Verbosity level.
|
|
1587
|
+
iso : int | None
|
|
1588
|
+
Enable level-set mode (default 1).
|
|
1589
|
+
**kwargs : float | int | None
|
|
1590
|
+
Additional MMG options.
|
|
1591
|
+
|
|
1592
|
+
Returns
|
|
1593
|
+
-------
|
|
1594
|
+
dict[str, Any]
|
|
1595
|
+
Statistics dictionary with before/after metrics.
|
|
1596
|
+
|
|
1597
|
+
"""
|
|
1598
|
+
|
|
1599
|
+
class MmgMeshS:
|
|
1600
|
+
"""Surface mesh class for in-memory remeshing.
|
|
1601
|
+
|
|
1602
|
+
All element indices in this class are 0-based (Python convention).
|
|
1603
|
+
The underlying MMG library uses 1-based indexing, but the bindings
|
|
1604
|
+
handle this conversion automatically.
|
|
1605
|
+
|
|
1606
|
+
Note: MmgMeshS does not support Lagrangian remeshing (remesh_lagrangian).
|
|
1607
|
+
"""
|
|
1608
|
+
|
|
1609
|
+
@overload
|
|
1610
|
+
def __init__(self) -> None:
|
|
1611
|
+
"""Create an empty surface mesh."""
|
|
1612
|
+
|
|
1613
|
+
@overload
|
|
1614
|
+
def __init__(
|
|
1615
|
+
self,
|
|
1616
|
+
vertices: NDArray[np.float64],
|
|
1617
|
+
triangles: NDArray[np.int32],
|
|
1618
|
+
) -> None:
|
|
1619
|
+
"""Create a surface mesh from vertices and triangles.
|
|
1620
|
+
|
|
1621
|
+
Parameters
|
|
1622
|
+
----------
|
|
1623
|
+
vertices : NDArray[np.float64]
|
|
1624
|
+
Vertex coordinates, shape (n_vertices, 3).
|
|
1625
|
+
triangles : NDArray[np.int32]
|
|
1626
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
1627
|
+
|
|
1628
|
+
"""
|
|
1629
|
+
|
|
1630
|
+
@overload
|
|
1631
|
+
def __init__(
|
|
1632
|
+
self,
|
|
1633
|
+
filename: str | Path,
|
|
1634
|
+
) -> None:
|
|
1635
|
+
"""Load a surface mesh from file.
|
|
1636
|
+
|
|
1637
|
+
Parameters
|
|
1638
|
+
----------
|
|
1639
|
+
filename : str | Path
|
|
1640
|
+
Path to mesh file (.mesh, .vtk, .vtu format).
|
|
1641
|
+
|
|
1642
|
+
"""
|
|
1643
|
+
|
|
1644
|
+
def set_mesh_size(
|
|
1645
|
+
self,
|
|
1646
|
+
vertices: int = 0,
|
|
1647
|
+
triangles: int = 0,
|
|
1648
|
+
edges: int = 0,
|
|
1649
|
+
) -> None:
|
|
1650
|
+
"""Allocate mesh storage for the specified element counts.
|
|
1651
|
+
|
|
1652
|
+
Parameters
|
|
1653
|
+
----------
|
|
1654
|
+
vertices : int
|
|
1655
|
+
Number of vertices.
|
|
1656
|
+
triangles : int
|
|
1657
|
+
Number of triangles.
|
|
1658
|
+
edges : int
|
|
1659
|
+
Number of edges.
|
|
1660
|
+
|
|
1661
|
+
"""
|
|
1662
|
+
|
|
1663
|
+
def get_mesh_size(self) -> tuple[int, int, int]:
|
|
1664
|
+
"""Get current mesh element counts.
|
|
1665
|
+
|
|
1666
|
+
Returns
|
|
1667
|
+
-------
|
|
1668
|
+
tuple[int, int, int]
|
|
1669
|
+
Tuple of (vertices, triangles, edges).
|
|
1670
|
+
|
|
1671
|
+
"""
|
|
1672
|
+
|
|
1673
|
+
def set_vertices(
|
|
1674
|
+
self,
|
|
1675
|
+
vertices: NDArray[np.float64],
|
|
1676
|
+
refs: NDArray[np.int64] | None = None,
|
|
1677
|
+
) -> None:
|
|
1678
|
+
"""Set all vertex coordinates.
|
|
1679
|
+
|
|
1680
|
+
Parameters
|
|
1681
|
+
----------
|
|
1682
|
+
vertices : NDArray[np.float64]
|
|
1683
|
+
Vertex coordinates, shape (n_vertices, 3).
|
|
1684
|
+
refs : NDArray[np.int64] | None
|
|
1685
|
+
Reference markers for each vertex.
|
|
1686
|
+
|
|
1687
|
+
"""
|
|
1688
|
+
|
|
1689
|
+
def set_triangles(
|
|
1690
|
+
self,
|
|
1691
|
+
triangles: NDArray[np.int32],
|
|
1692
|
+
refs: NDArray[np.int64] | None = None,
|
|
1693
|
+
) -> None:
|
|
1694
|
+
"""Set all triangles.
|
|
1695
|
+
|
|
1696
|
+
Parameters
|
|
1697
|
+
----------
|
|
1698
|
+
triangles : NDArray[np.int32]
|
|
1699
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
1700
|
+
refs : NDArray[np.int64] | None
|
|
1701
|
+
Reference markers for each triangle.
|
|
1702
|
+
|
|
1703
|
+
"""
|
|
1704
|
+
|
|
1705
|
+
def set_edges(
|
|
1706
|
+
self,
|
|
1707
|
+
edges: NDArray[np.int32],
|
|
1708
|
+
refs: NDArray[np.int64] | None = None,
|
|
1709
|
+
) -> None:
|
|
1710
|
+
"""Set all edges.
|
|
1711
|
+
|
|
1712
|
+
Parameters
|
|
1713
|
+
----------
|
|
1714
|
+
edges : NDArray[np.int32]
|
|
1715
|
+
Edge connectivity, shape (n_edges, 2).
|
|
1716
|
+
refs : NDArray[np.int64] | None
|
|
1717
|
+
Reference markers for each edge.
|
|
1718
|
+
|
|
1719
|
+
"""
|
|
1720
|
+
|
|
1721
|
+
def get_vertices(self) -> NDArray[np.float64]:
|
|
1722
|
+
"""Get vertex coordinates.
|
|
1723
|
+
|
|
1724
|
+
Returns
|
|
1725
|
+
-------
|
|
1726
|
+
NDArray[np.float64]
|
|
1727
|
+
Vertex coordinates, shape (n_vertices, 3).
|
|
1728
|
+
|
|
1729
|
+
"""
|
|
1730
|
+
|
|
1731
|
+
def get_vertices_with_refs(
|
|
1732
|
+
self,
|
|
1733
|
+
) -> tuple[NDArray[np.float64], NDArray[np.int64]]:
|
|
1734
|
+
"""Get vertex coordinates with reference markers.
|
|
1735
|
+
|
|
1736
|
+
Returns
|
|
1737
|
+
-------
|
|
1738
|
+
tuple[NDArray[np.float64], NDArray[np.int64]]
|
|
1739
|
+
Tuple of (vertices, refs).
|
|
1740
|
+
|
|
1741
|
+
"""
|
|
1742
|
+
|
|
1743
|
+
def get_triangles(self) -> NDArray[np.int32]:
|
|
1744
|
+
"""Get triangle connectivity.
|
|
1745
|
+
|
|
1746
|
+
Returns
|
|
1747
|
+
-------
|
|
1748
|
+
NDArray[np.int32]
|
|
1749
|
+
Triangle connectivity, shape (n_triangles, 3).
|
|
1750
|
+
|
|
1751
|
+
"""
|
|
1752
|
+
|
|
1753
|
+
def get_triangles_with_refs(
|
|
1754
|
+
self,
|
|
1755
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
1756
|
+
"""Get triangle connectivity with reference markers.
|
|
1757
|
+
|
|
1758
|
+
Returns
|
|
1759
|
+
-------
|
|
1760
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
1761
|
+
Tuple of (triangles, refs).
|
|
1762
|
+
|
|
1763
|
+
"""
|
|
1764
|
+
|
|
1765
|
+
def get_edges(self) -> NDArray[np.int32]:
|
|
1766
|
+
"""Get edge connectivity.
|
|
1767
|
+
|
|
1768
|
+
Returns
|
|
1769
|
+
-------
|
|
1770
|
+
NDArray[np.int32]
|
|
1771
|
+
Edge connectivity, shape (n_edges, 2).
|
|
1772
|
+
|
|
1773
|
+
"""
|
|
1774
|
+
|
|
1775
|
+
def get_edges_with_refs(
|
|
1776
|
+
self,
|
|
1777
|
+
) -> tuple[NDArray[np.int32], NDArray[np.int64]]:
|
|
1778
|
+
"""Get edge connectivity with reference markers.
|
|
1779
|
+
|
|
1780
|
+
Returns
|
|
1781
|
+
-------
|
|
1782
|
+
tuple[NDArray[np.int32], NDArray[np.int64]]
|
|
1783
|
+
Tuple of (edges, refs).
|
|
1784
|
+
|
|
1785
|
+
"""
|
|
1786
|
+
|
|
1787
|
+
def set_vertex(
|
|
1788
|
+
self,
|
|
1789
|
+
x: float,
|
|
1790
|
+
y: float,
|
|
1791
|
+
z: float,
|
|
1792
|
+
ref: int,
|
|
1793
|
+
idx: int,
|
|
1794
|
+
) -> None:
|
|
1795
|
+
"""Set a single vertex.
|
|
1796
|
+
|
|
1797
|
+
Parameters
|
|
1798
|
+
----------
|
|
1799
|
+
x, y, z : float
|
|
1800
|
+
Vertex coordinates.
|
|
1801
|
+
ref : int
|
|
1802
|
+
Reference marker.
|
|
1803
|
+
idx : int
|
|
1804
|
+
Vertex index (0-based).
|
|
1805
|
+
|
|
1806
|
+
"""
|
|
1807
|
+
|
|
1808
|
+
def set_triangle(
|
|
1809
|
+
self,
|
|
1810
|
+
v0: int,
|
|
1811
|
+
v1: int,
|
|
1812
|
+
v2: int,
|
|
1813
|
+
ref: int,
|
|
1814
|
+
idx: int,
|
|
1815
|
+
) -> None:
|
|
1816
|
+
"""Set a single triangle.
|
|
1817
|
+
|
|
1818
|
+
Parameters
|
|
1819
|
+
----------
|
|
1820
|
+
v0, v1, v2 : int
|
|
1821
|
+
Vertex indices (0-based).
|
|
1822
|
+
ref : int
|
|
1823
|
+
Reference marker.
|
|
1824
|
+
idx : int
|
|
1825
|
+
Triangle index (0-based).
|
|
1826
|
+
|
|
1827
|
+
"""
|
|
1828
|
+
|
|
1829
|
+
def set_edge(self, v0: int, v1: int, ref: int, idx: int) -> None:
|
|
1830
|
+
"""Set a single edge.
|
|
1831
|
+
|
|
1832
|
+
Parameters
|
|
1833
|
+
----------
|
|
1834
|
+
v0, v1 : int
|
|
1835
|
+
Vertex indices (0-based).
|
|
1836
|
+
ref : int
|
|
1837
|
+
Reference marker.
|
|
1838
|
+
idx : int
|
|
1839
|
+
Edge index (0-based).
|
|
1840
|
+
|
|
1841
|
+
"""
|
|
1842
|
+
|
|
1843
|
+
def get_vertex(self, idx: int) -> tuple[float, float, float, int]:
|
|
1844
|
+
"""Get a single vertex.
|
|
1845
|
+
|
|
1846
|
+
Parameters
|
|
1847
|
+
----------
|
|
1848
|
+
idx : int
|
|
1849
|
+
Vertex index (0-based).
|
|
1850
|
+
|
|
1851
|
+
Returns
|
|
1852
|
+
-------
|
|
1853
|
+
tuple[float, float, float, int]
|
|
1854
|
+
Tuple of (x, y, z, ref).
|
|
1855
|
+
|
|
1856
|
+
"""
|
|
1857
|
+
|
|
1858
|
+
def get_triangle(self, idx: int) -> tuple[int, int, int, int]:
|
|
1859
|
+
"""Get a single triangle.
|
|
1860
|
+
|
|
1861
|
+
Parameters
|
|
1862
|
+
----------
|
|
1863
|
+
idx : int
|
|
1864
|
+
Triangle index (0-based).
|
|
1865
|
+
|
|
1866
|
+
Returns
|
|
1867
|
+
-------
|
|
1868
|
+
tuple[int, int, int, int]
|
|
1869
|
+
Tuple of (v0, v1, v2, ref).
|
|
1870
|
+
|
|
1871
|
+
"""
|
|
1872
|
+
|
|
1873
|
+
def get_edge(self, idx: int) -> tuple[int, int, int]:
|
|
1874
|
+
"""Get a single edge.
|
|
1875
|
+
|
|
1876
|
+
Parameters
|
|
1877
|
+
----------
|
|
1878
|
+
idx : int
|
|
1879
|
+
Edge index (0-based).
|
|
1880
|
+
|
|
1881
|
+
Returns
|
|
1882
|
+
-------
|
|
1883
|
+
tuple[int, int, int]
|
|
1884
|
+
Tuple of (v0, v1, ref).
|
|
1885
|
+
|
|
1886
|
+
"""
|
|
1887
|
+
|
|
1888
|
+
def set_corners(self, vertex_indices: NDArray[np.int32]) -> None:
|
|
1889
|
+
"""Mark vertices as corners (preserved during remeshing).
|
|
1890
|
+
|
|
1891
|
+
Parameters
|
|
1892
|
+
----------
|
|
1893
|
+
vertex_indices : NDArray[np.int32]
|
|
1894
|
+
Indices of corner vertices (0-based).
|
|
1895
|
+
|
|
1896
|
+
"""
|
|
1897
|
+
|
|
1898
|
+
def set_required_vertices(self, vertex_indices: NDArray[np.int32]) -> None:
|
|
1899
|
+
"""Mark vertices as required (cannot be removed).
|
|
1900
|
+
|
|
1901
|
+
Parameters
|
|
1902
|
+
----------
|
|
1903
|
+
vertex_indices : NDArray[np.int32]
|
|
1904
|
+
Indices of required vertices (0-based).
|
|
1905
|
+
|
|
1906
|
+
"""
|
|
1907
|
+
|
|
1908
|
+
def set_ridge_edges(self, edge_indices: NDArray[np.int32]) -> None:
|
|
1909
|
+
"""Mark edges as ridges (sharp features preserved).
|
|
1910
|
+
|
|
1911
|
+
Parameters
|
|
1912
|
+
----------
|
|
1913
|
+
edge_indices : NDArray[np.int32]
|
|
1914
|
+
Indices of ridge edges (0-based).
|
|
1915
|
+
|
|
1916
|
+
"""
|
|
1917
|
+
|
|
1918
|
+
def get_adjacent_elements(self, idx: int) -> NDArray[np.int32]:
|
|
1919
|
+
"""Get indices of triangles sharing edges with element idx.
|
|
1920
|
+
|
|
1921
|
+
Parameters
|
|
1922
|
+
----------
|
|
1923
|
+
idx : int
|
|
1924
|
+
Element index (0-based).
|
|
1925
|
+
|
|
1926
|
+
Returns
|
|
1927
|
+
-------
|
|
1928
|
+
NDArray[np.int32]
|
|
1929
|
+
Array of 3 indices (-1 indicates boundary).
|
|
1930
|
+
|
|
1931
|
+
"""
|
|
1932
|
+
|
|
1933
|
+
def get_vertex_neighbors(self, idx: int) -> NDArray[np.int32]:
|
|
1934
|
+
"""Get indices of vertices connected to vertex idx by an edge.
|
|
1935
|
+
|
|
1936
|
+
Parameters
|
|
1937
|
+
----------
|
|
1938
|
+
idx : int
|
|
1939
|
+
Vertex index (0-based).
|
|
1940
|
+
|
|
1941
|
+
Returns
|
|
1942
|
+
-------
|
|
1943
|
+
NDArray[np.int32]
|
|
1944
|
+
Array of neighbor vertex indices.
|
|
1945
|
+
|
|
1946
|
+
"""
|
|
1947
|
+
|
|
1948
|
+
def get_element_quality(self, idx: int) -> float:
|
|
1949
|
+
"""Get quality metric for a triangle.
|
|
1950
|
+
|
|
1951
|
+
Parameters
|
|
1952
|
+
----------
|
|
1953
|
+
idx : int
|
|
1954
|
+
Triangle index (0-based).
|
|
1955
|
+
|
|
1956
|
+
Returns
|
|
1957
|
+
-------
|
|
1958
|
+
float
|
|
1959
|
+
Quality metric (0-1, higher is better).
|
|
1960
|
+
|
|
1961
|
+
"""
|
|
1962
|
+
|
|
1963
|
+
def get_element_qualities(self) -> NDArray[np.float64]:
|
|
1964
|
+
"""Get quality metrics for all triangles.
|
|
1965
|
+
|
|
1966
|
+
Returns
|
|
1967
|
+
-------
|
|
1968
|
+
NDArray[np.float64]
|
|
1969
|
+
Quality metrics for all elements.
|
|
1970
|
+
|
|
1971
|
+
"""
|
|
1972
|
+
|
|
1973
|
+
def set_field(self, key: str, value: NDArray[np.float64]) -> None:
|
|
1974
|
+
"""Set a solution field on vertices.
|
|
1975
|
+
|
|
1976
|
+
Parameters
|
|
1977
|
+
----------
|
|
1978
|
+
key : str
|
|
1979
|
+
Field name: "metric", "levelset", or "tensor".
|
|
1980
|
+
value : NDArray[np.float64]
|
|
1981
|
+
Field values (one row per vertex).
|
|
1982
|
+
|
|
1983
|
+
"""
|
|
1984
|
+
|
|
1985
|
+
def get_field(self, key: str) -> NDArray[np.float64]:
|
|
1986
|
+
"""Get a solution field from vertices.
|
|
1987
|
+
|
|
1988
|
+
Parameters
|
|
1989
|
+
----------
|
|
1990
|
+
key : str
|
|
1991
|
+
Field name.
|
|
1992
|
+
|
|
1993
|
+
Returns
|
|
1994
|
+
-------
|
|
1995
|
+
NDArray[np.float64]
|
|
1996
|
+
Field values (one row per vertex).
|
|
1997
|
+
|
|
1998
|
+
"""
|
|
1999
|
+
|
|
2000
|
+
def __setitem__(self, key: str, value: NDArray[np.float64]) -> None:
|
|
2001
|
+
"""Set a solution field using dictionary syntax."""
|
|
2002
|
+
|
|
2003
|
+
def __getitem__(self, key: str) -> NDArray[np.float64]:
|
|
2004
|
+
"""Get a solution field using dictionary syntax."""
|
|
2005
|
+
|
|
2006
|
+
def save(self, filename: str | Path) -> None:
|
|
2007
|
+
"""Save mesh to file.
|
|
2008
|
+
|
|
2009
|
+
Parameters
|
|
2010
|
+
----------
|
|
2011
|
+
filename : str | Path
|
|
2012
|
+
Output file path. Format determined by extension.
|
|
2013
|
+
|
|
2014
|
+
"""
|
|
2015
|
+
|
|
2016
|
+
def remesh(
|
|
2017
|
+
self,
|
|
2018
|
+
*,
|
|
2019
|
+
hmin: float | None = None,
|
|
2020
|
+
hmax: float | None = None,
|
|
2021
|
+
hsiz: float | None = None,
|
|
2022
|
+
hausd: float | None = None,
|
|
2023
|
+
hgrad: float | None = None,
|
|
2024
|
+
verbose: int | bool | None = None,
|
|
2025
|
+
optim: int | None = None,
|
|
2026
|
+
noinsert: int | None = None,
|
|
2027
|
+
noswap: int | None = None,
|
|
2028
|
+
nomove: int | None = None,
|
|
2029
|
+
**kwargs: float | None,
|
|
2030
|
+
) -> dict[str, Any]:
|
|
2031
|
+
"""Remesh the mesh in-place.
|
|
2032
|
+
|
|
2033
|
+
Parameters
|
|
2034
|
+
----------
|
|
2035
|
+
hmin : float | None
|
|
2036
|
+
Minimum edge size.
|
|
2037
|
+
hmax : float | None
|
|
2038
|
+
Maximum edge size.
|
|
2039
|
+
hsiz : float | None
|
|
2040
|
+
Uniform target edge size.
|
|
2041
|
+
hausd : float | None
|
|
2042
|
+
Hausdorff distance for geometry approximation.
|
|
2043
|
+
hgrad : float | None
|
|
2044
|
+
Gradation parameter.
|
|
2045
|
+
verbose : int | bool | None
|
|
2046
|
+
Verbosity level. True/False converted to 1/-1.
|
|
2047
|
+
optim : int | None
|
|
2048
|
+
Optimization mode.
|
|
2049
|
+
noinsert : int | None
|
|
2050
|
+
Disable vertex insertion.
|
|
2051
|
+
noswap : int | None
|
|
2052
|
+
Disable edge swapping.
|
|
2053
|
+
nomove : int | None
|
|
2054
|
+
Disable vertex relocation.
|
|
2055
|
+
**kwargs : float | int | None
|
|
2056
|
+
Additional MMG options.
|
|
2057
|
+
|
|
2058
|
+
Returns
|
|
2059
|
+
-------
|
|
2060
|
+
dict[str, Any]
|
|
2061
|
+
Statistics dictionary with before/after metrics.
|
|
2062
|
+
|
|
2063
|
+
"""
|
|
2064
|
+
|
|
2065
|
+
def remesh_lagrangian(
|
|
2066
|
+
self,
|
|
2067
|
+
displacement: NDArray[np.float64],
|
|
2068
|
+
**kwargs: float | None,
|
|
2069
|
+
) -> None:
|
|
2070
|
+
"""Not supported - raises RuntimeError.
|
|
2071
|
+
|
|
2072
|
+
Lagrangian motion is not supported for surface meshes (MmgMeshS).
|
|
2073
|
+
|
|
2074
|
+
Reason: Lagrangian motion requires solving elasticity PDEs to propagate
|
|
2075
|
+
boundary displacements to interior vertices. Surface meshes have no
|
|
2076
|
+
volumetric interior - the ELAS library only supports 2D/3D elasticity,
|
|
2077
|
+
not shell/membrane elasticity needed for surfaces.
|
|
2078
|
+
|
|
2079
|
+
Alternative: Use mmgpy.move_mesh() to move vertices and remesh:
|
|
2080
|
+
mmgpy.move_mesh(mesh, displacement, hausd=0.01)
|
|
2081
|
+
|
|
2082
|
+
Parameters
|
|
2083
|
+
----------
|
|
2084
|
+
displacement : NDArray[np.float64]
|
|
2085
|
+
Not used - raises RuntimeError immediately.
|
|
2086
|
+
**kwargs : float | None
|
|
2087
|
+
Not used - raises RuntimeError immediately.
|
|
2088
|
+
|
|
2089
|
+
Raises
|
|
2090
|
+
------
|
|
2091
|
+
RuntimeError
|
|
2092
|
+
Always raised - Lagrangian motion is not supported for surface meshes.
|
|
2093
|
+
|
|
2094
|
+
"""
|
|
2095
|
+
|
|
2096
|
+
def remesh_levelset(
|
|
2097
|
+
self,
|
|
2098
|
+
levelset: NDArray[np.float64],
|
|
2099
|
+
*,
|
|
2100
|
+
ls: float | None = None,
|
|
2101
|
+
hmin: float | None = None,
|
|
2102
|
+
hmax: float | None = None,
|
|
2103
|
+
hsiz: float | None = None,
|
|
2104
|
+
hausd: float | None = None,
|
|
2105
|
+
hgrad: float | None = None,
|
|
2106
|
+
verbose: int | bool | None = None,
|
|
2107
|
+
iso: int | None = None,
|
|
2108
|
+
**kwargs: float | None,
|
|
2109
|
+
) -> dict[str, Any]:
|
|
2110
|
+
"""Remesh to conform to a level-set isoline.
|
|
2111
|
+
|
|
2112
|
+
Parameters
|
|
2113
|
+
----------
|
|
2114
|
+
levelset : NDArray[np.float64]
|
|
2115
|
+
Level-set values, shape (n_vertices, 1).
|
|
2116
|
+
ls : float | None
|
|
2117
|
+
Isovalue to discretize (default 0.0).
|
|
2118
|
+
hmin : float | None
|
|
2119
|
+
Minimum edge size.
|
|
2120
|
+
hmax : float | None
|
|
2121
|
+
Maximum edge size.
|
|
2122
|
+
hsiz : float | None
|
|
2123
|
+
Uniform target edge size.
|
|
2124
|
+
hausd : float | None
|
|
2125
|
+
Hausdorff distance for geometry approximation.
|
|
2126
|
+
hgrad : float | None
|
|
2127
|
+
Gradation parameter.
|
|
2128
|
+
verbose : int | bool | None
|
|
2129
|
+
Verbosity level.
|
|
2130
|
+
iso : int | None
|
|
2131
|
+
Enable level-set mode (default 1).
|
|
2132
|
+
**kwargs : float | int | None
|
|
2133
|
+
Additional MMG options.
|
|
2134
|
+
|
|
2135
|
+
Returns
|
|
2136
|
+
-------
|
|
2137
|
+
dict[str, Any]
|
|
2138
|
+
Statistics dictionary with before/after metrics.
|
|
2139
|
+
|
|
2140
|
+
"""
|