Working with the mesh class#

The mesh class, at its core, stores the definition of a mesh. A mesh is defined by the coordinates of its nodes (NodeCoords) and set of node connections (NodeConn) that define the elements (mesh.points and mesh.cells are offered as aliases to mesh.NodeCoords and mesh.NodeConn since these are commonly used terms for the same attributes in other softwares).

On-demand properties#

There are a number of properties that can calculate various mesh features on-demand and cache them for quick access later. For example, mesh.Centroids will calculate the element centroids the first time it is referenced, and then they will be stored to avoid the need for subsequent recalculation. This offers a balance of convenience and efficiency, without the need to calculate unnecessary features or recalculate features that are needed multiple times (see mesh for the full list of properties).

Unpacking#

One of the goals in creating a MyMesh-specific mesh class was to make it easy to come and go from the MyMesh “ecosystem” and avoid lock-in, so that users can easily take advantage of the functionality offered by other well established mesh packages or custom code. To make it easy to move to and from instances of this class, objects are unpackable into NodeCoords and NodeConn. This means that the following three code blocks all achieve the same thing:

sphere = primitives.Sphere([0,0,0], .5)
NodeCoords = sphere.NodeCoords
NodeConn = sphere.NodeConn
sphere = primitives.Sphere([0,0,0], .5)
NodeCoords, NodeConn = sphere
NodeCoords, NodeConn = primitives.Sphere([0,0,0], .5)

Additionally, since many of the lower-level functions in MyMesh (such as those in mymesh.utils) take NodeCoords and NodeConn as inputs, users can use the * operator to unpack the mesh directly in the function call:

sphere = primitives.Sphere([0,0,0], .5)
NodeNeighbors = utils.getNodeNeighbors(*sphere)

Similarly, many functions in the mymesh.converter module take NodeCoords and NodeConn as inputs and return new or modified node coordinates and node connectivities, so you can avoid having to deal with separate intermediate values:

sphere = primitives.Sphere([0,0,0], .5)
VoxelNodeCoords, VoxelNodeConn  = converter.surf2voxel(sphere.NodeCoords, sphere.NodeConn, .1)
voxelized = mesh(VoxelNodeCoords, VoxelNodeConn)

is equivalent to

sphere = primitives.Sphere([0,0,0], .5)
voxelized = mesh(*converter.surf2voxel(*sphere, .1))

From meshes to meshes#

There are several mesh class methods that produce new meshes based on the original.

copy()#

copy() produces an identical copy of the original mesh. The copies are separate and do not reference each other, meaning any modification to one mesh won’t modify the other.

M = primitives.Grid([0,1,0,1,0,1], 0.1)
M2 = M.copy()

Clip()#

Clip() cuts the mesh along a plane

M = primitives.Grid([-1,1,-1,1,-1,1], 0.1)
M2 = M.Clip(normal=[1,1,-1])
M2.plot(show_edges=False, view='trimetric', bgcolor='w')
../_images/mesh_class-1.png

Threshold()#

Threshold() generates a new mesh that keeps elements from the original mesh based on scalar values and the chosen thresholding rule.

M = primitives.Grid([-1,1,-1,1,-1,1], 0.1)
M2 = M.Threshold(scalars=implicit.sphere([0,0,0], 1)(*M.points.T), threshold=0, mode='<=')
M2.plot(show_edges=False, view='trimetric', bgcolor='w')
../_images/mesh_class-2.png

Contour()#

Contour() generates a new mesh that contours the original mesh based on scalar values.

M = primitives.Grid([-1,1,-1,1,-1,1], 0.1)
M2 = M.Contour(scalars=implicit.sphere([0,0,0], 1)(*M.points.T), threshold=0, threshold_direction=-1, Type='surf')
M2.plot(show_edges=False, view='trimetric', bgcolor='w')
../_images/mesh_class-3.png