From 214d99e8da6479a0cb277b27f9a8f5493333aa71 Mon Sep 17 00:00:00 2001 From: Andreas Dutzler Date: Sun, 1 Sep 2024 11:14:16 +0200 Subject: [PATCH] Add `MeshContainer.from_unstructured_grid()` (#847) * Add `MeshContainer.from_unstructured_grid()` * Add test to read an unstructured grid --- CHANGELOG.md | 1 + src/felupe/mesh/_container.py | 52 +++++++++++++++++++++++++++++++++++ tests/test_mesh.py | 7 +++++ 3 files changed, 60 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0f73100..e244bc1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. The format - Add `LinearElasticOrthotropic`. - Add `SolidBodyCauchyStress` in addition to `SolidBodyPressure`. - Add `mesh.cell_types()` which returns an object-array with cell-type mappings for FElupe and PyVista. +- Add `MeshContainer.from_unstructured_grid(grid, dim=None, **kwargs)` to create a mesh-container from an unstructured grid (PyVista). ### Changed - Change the internal initialization of `field = Field(region, values=1, dtype=None)` values from `field.values = np.ones(shape) * values` to `field = np.full(shape, fill_value=values, dtype=dtype)`. This enforces `field = Field(region, values=1)` to return the gradient array with data-type `int` which was of type `float` before. diff --git a/src/felupe/mesh/_container.py b/src/felupe/mesh/_container.py index 4f1e21e2..631f6414 100644 --- a/src/felupe/mesh/_container.py +++ b/src/felupe/mesh/_container.py @@ -20,6 +20,7 @@ import numpy as np +from ._convert import cell_types from ._mesh import Mesh from ._tools import merge_duplicate_points as sweep from ._tools import stack @@ -202,6 +203,57 @@ def stack(self, idx=None): ] raise TypeError(" ".join(message)) + @classmethod + def from_unstructured_grid(cls, grid, dim=None, **kwargs): + r"""Create a mesh container from an unstructured grid (PyVista). + + Parameters + ---------- + grid : pyvista.UnstructuredGrid + PyVista dataset used for arbitrary combinations of all possible cell types. + dim : int or None, optional + Trim the dimension of the ``points``-array (default is None). + **kwargs : dict, optional + Additional keyword-arguments are passed to the mesh container. + + Returns + ------- + MeshContainer + A container which operates on a list of meshes with identical dimensions. + + Examples + -------- + + .. pyvista-plot:: + + >>> import felupe as fem + >>> import pyvista as pv + >>> + >>> grid = pv.UnstructuredGrid(pv.examples.hexbeamfile) + >>> container = fem.MechContainer.from_unstructured_grid(grid) + >>> + >>> container + + Number of points: 99 + Number of cells: + hexahedron: 40 + + See Also + -------- + felupe.mesh.cell_types : Return a list with tuples of cell type mappings. + felupe.Mesh.as_unstructured_grid : Export the mesh as unstructured grid. + """ + + points = grid.points + meshes = [] + + cell_types_felupe = dict(cell_types()[:, [1, 0]]) + + for cell_type, cells in grid.cells_dict.items(): + meshes.append(Mesh(points[:, :dim], cells, cell_types_felupe[cell_type])) + + return cls(meshes, **kwargs) + def as_meshio(self, combined=True, **kwargs): "Export a (combined) mesh object as :class:`meshio.Mesh`." diff --git a/tests/test_mesh.py b/tests/test_mesh.py index 608f73ec..61105393 100644 --- a/tests/test_mesh.py +++ b/tests/test_mesh.py @@ -365,6 +365,13 @@ def test_container(): for combined in [False, True]: print(container.as_meshio(combined=combined)) + container_2 = fem.MeshContainer.from_unstructured_grid( + mesh_1.as_unstructured_grid(), dim=2 + ) + + assert np.allclose(container_2[0].points, mesh_1.points) + assert np.allclose(container_2[0].cells, mesh_1.cells) + def test_read(filename="tests/mesh.bdf"): mesh = fem.mesh.read(filename=filename, dim=2)[0]