Migrating from mmgpy.Mesh to the .mmg accessor¶
mmgpy.Mesh is deprecated in 0.12 and will be removed in 0.13. The replacement is the PyVista 0.48 dataset accessor that ships with mmgpy:
import pyvista as pv
import mmgpy # noqa: F401 -- registers the accessor
mesh = pv.read("brain.mesh") # uses mmgpy's Medit reader plugin
remeshed = mesh.mmg.remesh(hsiz=0.1) # accessor-driven remeshing
mesh.save("out.mesh") # uses mmgpy's Medit writer plugin
Every MMG-specific operation that used to live on Mesh now lives on the accessor; everything else (vertex coordinates, cell connectivity, geometry queries, .save(), .plot(), scalar field storage) is available through PyVista's native API.
Quick reference¶
Mesh method |
Replacement |
|---|---|
Mesh(pv_dataset) |
pv_dataset directly — no wrapper needed |
mesh.kind |
dataset.mmg.kind |
mesh.remesh(**opts) |
new = dataset.mmg.remesh(**opts) |
mesh.remesh_lagrangian(displacement, **opts) |
new = dataset.mmg.move(displacement, **opts) (Laplacian by default; pass propagation_method="elasticity" for the fedoo-backed solver) |
mesh.remesh_levelset(levelset, **opts) |
new = dataset.mmg.remesh_levelset(levelset, **opts) |
mesh.remesh_optimize(**opts) |
new = dataset.mmg.remesh_optimize(**opts) |
mesh.remesh_uniform(size, **opts) |
new = dataset.mmg.remesh_uniform(size, **opts) |
mesh.set_size_sphere(...) etc. + mesh.remesh() |
dataset.mmg.remesh(local_sizing=[{"shape": "sphere", ...}]) |
mesh.load_sol(path) |
dataset.mmg.load_sol(path) |
mesh.save_sol(path) |
dataset.mmg.save_sol(path) |
mesh.validate(detailed=True) |
dataset.mmg.validate(detailed=True) |
mesh.get_element_quality(idx) |
dataset.mmg.element_quality(idx) |
mesh.get_element_qualities() |
dataset.mmg.element_qualities() |
mesh.get_adjacent_elements(idx) |
dataset.mmg.adjacent_elements(idx) |
mesh.get_vertex_neighbors(idx) |
dataset.mmg.vertex_neighbors(idx) |
mesh.get_center_of_mass() |
dataset.mmg.center_of_mass() |
mesh.get_vertices() / mesh.set_vertices(v) |
dataset.points (read/write) |
mesh.get_triangles() / mesh.get_tetrahedra() |
dataset.cells_dict[pv.CellType.TRIANGLE] / [pv.CellType.TETRA] |
mesh.get_edges() |
dataset.cells_dict[pv.CellType.LINE] (when include_edges=True) |
mesh.compute_volume() |
dataset.volume (tet meshes) |
mesh.compute_surface_area() |
dataset.area |
mesh.get_bounds() |
dataset.bounds (note: returns (xmin, xmax, ymin, ymax, zmin, zmax)) |
mesh.get_diagonal() |
np.linalg.norm(np.array(dataset.bounds[1::2]) - np.array(dataset.bounds[0::2])) |
mesh["metric"] = arr |
dataset.point_data["metric"] = arr |
mesh["temperature"] = arr |
dataset.point_data["temperature"] = arr |
mesh.set_user_field(name, arr) / mesh.get_user_field(name) |
dataset.point_data[name] |
mesh.to_pyvista() / mesh.vtk |
dataset (already PyVista) |
mesh.plot(**kwargs) |
dataset.plot(**kwargs) |
mesh.save(path) |
dataset.save(path) (mmgpy's writer plugin handles .mesh/.meshb) |
mesh.copy() |
dataset.copy() |
mesh.checkpoint() |
snapshot via snap = dataset.copy(), reassign on success (see below) |
Three concrete migrations¶
1. Read, remesh, save¶
# Before
import mmgpy
mesh = mmgpy.Mesh("brain.mesh")
mesh.remesh(hsiz=0.1)
mesh.save("brain_fine.mesh")
# After
import pyvista as pv
import mmgpy # noqa: F401 -- registers reader/writer plugins + accessor
mesh = pv.read("brain.mesh")
remeshed = mesh.mmg.remesh(hsiz=0.1)
remeshed.save("brain_fine.mesh")
2. Local sizing¶
# Before
mesh = mmgpy.Mesh(vertices, triangles)
mesh.set_size_sphere(center=[0, 0, 0], radius=0.3, size=0.05)
mesh.set_size_box(bounds=[[0.5, 0, 0], [1, 0.5, 0]], size=0.02)
mesh.remesh(hsiz=0.2)
# After
import pyvista as pv
grid = pv.UnstructuredGrid({pv.CellType.TETRA: triangles}, vertices)
remeshed = grid.mmg.remesh(
hsiz=0.2,
local_sizing=[
{"shape": "sphere", "center": (0, 0, 0), "radius": 0.3, "size": 0.05},
{"shape": "box", "bounds": [[0.5, 0, 0], [1, 0.5, 0]], "size": 0.02},
],
)
3. Checkpoint / rollback¶
# Before — Mesh.checkpoint with auto-rollback on exception
mesh = mmgpy.Mesh("brain.mesh")
with mesh.checkpoint() as snap:
mesh.remesh(hsiz=0.01)
if not mesh.validate():
raise RuntimeError # auto-rollback
snap.commit() # keep the result
# After — explicit snapshot, reassign on success
mesh = pv.read("brain.mesh")
snap = mesh.copy()
try:
candidate = mesh.mmg.remesh(hsiz=0.01)
if not candidate.mmg.validate():
raise RuntimeError
mesh = candidate
except Exception:
mesh = snap # roll back
raise
The accessor returns a fresh dataset on every call, so you never need to undo anything: just don't reassign on failure.
Subtle differences¶
mesh.get_center_of_mass()was volume- (3D) or area-weighted (2D/surface). PyVista'sdataset.centeris the unweighted arithmetic mean of point coordinates. Usedataset.mmg.center_of_mass()to get the same number you had before.mesh.get_*_neighbors(idx)andmesh.get_adjacent_elements(idx)use 1-based indexing (MMG convention). PyVista'sdataset.point_neighbors(idx)anddataset.cell_neighbors(idx)use 0-based indexing (VTK convention) and may use a different adjacency rule. If you need MMG's exact behavior, use the accessor methods (dataset.mmg.vertex_neighbors,dataset.mmg.adjacent_elements).- MMG-specific point_data fields (
metric,displacement,levelset,tensor) survive on the dataset'spoint_dataand are picked up automatically bydataset.mmg.remesh*. Set them withdataset.point_data["metric"] = my_array. Scalar fields can be 1D(n,); the accessor reshapes to(n, 1)internally.
Removal timeline¶
- 0.12 (now):
DeprecationWarningonMeshinstantiation andMesh.checkpoint(). Internal mmgpy code paths are silent. - 0.13:
MeshandMeshCheckpointremoved.MeshKindsurvives (still returned bydataset.mmg.kind).