Getting Started

In this section, we use a simple segmentation to create a finite element mesh, a smoothed finite element mesh, and an isosurface.

Segmentation Input

We start with a segmentation of a regular octahedron composed of three materials. The segmentation encodes

  • 0 for void (or background), shown in gray,
  • 1 for the inner domain, shown in green,
  • 2 for the intermediate layer, shown in yellow, and
  • 3 for the outer layer, shown in magenta.

The (7 x 7 x 7) segmentation, at the midline cut plane, appears as follows:

0
0
0
3
0
0
0
0
0
3
2
3
0
0
0
3
2
1
2
3
0
3
2
1
1
1
2
3
0
3
2
1
2
3
0
0
0
3
2
3
0
0
0
0
0
3
0
0
0

Consider each slice, 1 to 7, in succession:

     
     
     
 
     
     
     

Remark: The (7 x 7 x 7) segmentation can be thought of as a conceptual start point for a process called Loop subdivision, used to produce spherical shapes at higher resolutions. See Octa Loop for additional information. A sphere in resolutions of (24 x 24 x 24) and (48 x 48 x 48), used in the Sphere with Shells section, is shown below: spheres_cont_cut

Segmentation File Types

Two types of segmentation files types are supported: .spn and .npy.

The .spn file can be thought of as the most elementary segmentation file type because it is saved as an ASCII text file and is therefore readily human-readable. Below is an abbreviated and commented .spn segmentation of the (7 x 7 x 7) octahedron discussed above.

0 # slice 1, row 1
0
0
0
0
0
0
0 # slice 1, row 2
0
0
0
0
0
0
0 # slice 1, row 3
0
0
0
0
0
0
0 # slice 1, row 4
0
0
3
0
0
0
0 # slice 1, row 5
0
0
0
0
0
0
0 # slice 1, row 6
0
0
0
0
0
0
0 # slice 1, row 7
0
0
0
0
0
0
# ... and so on for the remaining six slices

A disadvantage of .spn is that it can become difficult to keep track of data slice-by-slice. Because it is not a compressed binary file, the .spn has a larger file size than the equivalent .npy.

The .npy segmentation file format is an alternative to the .spn format. The .npy format can be advantageous because is can be generated easily from Python. This approach can be useful because Python can be used to algorithmically create a segmentation and serialized the segmentation to a compressed binary file in .npy format.

We illustrate creating the octahedron segmentation in Python:

"""This module creates a 7x7x7 octahedron segmentation."""

import numpy as np

segmentation = np.array(
    [
        [  # slice 1
            [0, 0, 0, 0, 0, 0, 0],  # row 1
            [0, 0, 0, 0, 0, 0, 0],  # row 2
            [0, 0, 0, 0, 0, 0, 0],  # row 3
            [0, 0, 0, 3, 0, 0, 0],  # row 4
            [0, 0, 0, 0, 0, 0, 0],  # row 5
            [0, 0, 0, 0, 0, 0, 0],  # row 6
            [0, 0, 0, 0, 0, 0, 0],  # row 7
        ],
        [  # slice 2
            [0, 0, 0, 0, 0, 0, 0],  # row 1
            [0, 0, 0, 0, 0, 0, 0],  # row 2
            [0, 0, 0, 3, 0, 0, 0],  # row 3
            [0, 0, 3, 2, 3, 0, 0],  # row 4
            [0, 0, 0, 3, 0, 0, 0],  # row 5
            [0, 0, 0, 0, 0, 0, 0],  # row 6
            [0, 0, 0, 0, 0, 0, 0],  # row 7
        ],
        [  # slice 3
            [0, 0, 0, 0, 0, 0, 0],  # row 1
            [0, 0, 0, 3, 0, 0, 0],  # row 2
            [0, 0, 3, 2, 3, 0, 0],  # row 3
            [0, 3, 2, 1, 2, 3, 0],  # row 4
            [0, 0, 3, 2, 3, 0, 0],  # row 5
            [0, 0, 0, 3, 0, 0, 0],  # row 6
            [0, 0, 0, 0, 0, 0, 0],  # row 7
        ],
        [  # slice 4
            [0, 0, 0, 3, 0, 0, 0],  # row 1
            [0, 0, 3, 2, 3, 0, 0],  # row 2
            [0, 3, 2, 1, 2, 3, 0],  # row 3
            [3, 2, 1, 1, 1, 2, 3],  # row 4
            [0, 3, 2, 1, 2, 3, 0],  # row 5
            [0, 0, 3, 2, 3, 0, 0],  # row 6
            [0, 0, 0, 3, 0, 0, 0],  # row 7
        ],
        [  # slice 5
            [0, 0, 0, 0, 0, 0, 0],  # row 1
            [0, 0, 0, 3, 0, 0, 0],  # row 2
            [0, 0, 3, 2, 3, 0, 0],  # row 3
            [0, 3, 2, 1, 2, 3, 0],  # row 4
            [0, 0, 3, 2, 3, 0, 0],  # row 5
            [0, 0, 0, 3, 0, 0, 0],  # row 6
            [0, 0, 0, 0, 0, 0, 0],  # row 7
        ],
        [  # slice 6
            [0, 0, 0, 0, 0, 0, 0],  # row 1
            [0, 0, 0, 0, 0, 0, 0],  # row 2
            [0, 0, 0, 3, 0, 0, 0],  # row 3
            [0, 0, 3, 2, 3, 0, 0],  # row 4
            [0, 0, 0, 3, 0, 0, 0],  # row 5
            [0, 0, 0, 0, 0, 0, 0],  # row 6
            [0, 0, 0, 0, 0, 0, 0],  # row 7
        ],
        [  # slice 7
            [0, 0, 0, 0, 0, 0, 0],  # row 1
            [0, 0, 0, 0, 0, 0, 0],  # row 2
            [0, 0, 0, 0, 0, 0, 0],  # row 3
            [0, 0, 0, 3, 0, 0, 0],  # row 4
            [0, 0, 0, 0, 0, 0, 0],  # row 5
            [0, 0, 0, 0, 0, 0, 0],  # row 6
            [0, 0, 0, 0, 0, 0, 0],  # row 7
        ],
    ],
    dtype=np.uint8,
)

FILE_NAME = "octahedron.npy"
np.save(FILE_NAME, segmentation)
print(f"Saved {FILE_NAME} with shape {segmentation.shape}.")

The convert Command

automesh allows for interoperability between .spn. and .npy file types. Use the automesh help to discover the command syntax:

automesh convert --help
Converts between mesh or segmentation file types

Usage: automesh convert <COMMAND>

Commands:
  mesh          Converts mesh file types (inp | stl) -> (exo | mesh | stl | vtk)
  segmentation  Converts segmentation file types (npy | spn) -> (npy | spn)
  help          Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

For example, to convert the octahedron.npy to octahedron2.spn:

automesh convert segmentation -i octahedron.npy -o octahedron2.spn
    automesh 0.3.3
     Reading octahedron.npy       Total 213.42µs

To convert from octahedron2.spn to octahedron3.npy:

automesh convert segmentation -i octahedron2.spn -x 7 -y 7 -z 7 -o octahedron3.npy
    automesh 0.3.3
     Reading octahedron2.spn [nelx: 7, nely: 7, nelz: 7]       Total 229.79µs

Remark: Notice that the .spn requires number of voxels in each of the x, y, and z dimensions to be specified using --nelx, --nely, --nelz (or, equivalently -x, -y, -z) flags.

We can verify the two .npy files encode the same segmentation:

"""The purpose of this module is to show that the
segmentation data encoded in two .npy files is the same.
"""

import numpy as np

aa = np.load("octahedron.npy")
print(aa)

bb = np.load("octahedron3.npy")
print(bb)

comparison = aa == bb
print(comparison)
result = np.all(comparison)
print(f"Element-by-element equality is {result}.")

Mesh Generation

automesh creates several finite element mesh file types from a segmentation.

Use the automesh help to discover the command syntax:

automesh mesh --help
Creates a finite element mesh from a segmentation

Usage: automesh mesh <COMMAND>

Commands:
  hex   Creates an all-hexahedral mesh from a segmentation
  tri   Creates all-triangular isosurface(s) from a segmentation
  help  Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

To convert the octahedron.npy into an ABAQUS finite element mesh, while removing segmentation 0 from the mesh:

automesh mesh hex -r 0 -i octahedron.npy -o octahedron.inp

Smoothing

Use the automesh help to discover the command syntax:

automesh smooth --help
Applies smoothing to an existing mesh

Usage: automesh smooth <COMMAND>

Commands:
  hex   Smooths an all-hexahedral mesh
  tri   Smooths an all-triangular mesh
  help  Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

To smooth the octahedron.inp mesh with Taubin smoothing parameters for five iterations:

automesh smooth -n 5 -i octahedron.inp -o octahedron_s05.inp

The original voxel mesh and the smoothed voxel mesh are shown below:

octahedron.inpoctahedron_s05.inp
octahedron_voxelsoctahedron_voxels_s05

See the Smoothing section for more information.

Isosurface

An isosurface can be generated from a segmentation using the tri command.

To create a mesh of the outer isosurfaces contained in the octahedron example:

automesh mesh tri -r 0 1 2 -i octahedron.npy -o octahedron.stl
    automesh 0.3.3
     Reading octahedron.npy       Total 223.238µs

The surfaces are visualized below:

octahedron.stl in MeshLaboctahedron.stl in Cubit with cut plane
isosurface_mesh_labisosurface_cubit_cut_plane

automesh creates an isosurface from the boundary faces of voxels. The quadrilateral faces are divided into two triangles. The Isosurface section contains more details about alternative methods used to create an isosurface.

The Sphere with Shells section contains more examples of the command line interface.