Skip to content

Finite Element Mesh generation

Santtu Söderholm edited this page Aug 16, 2023 · 48 revisions

This page describes how one might generate a finite element mesh from an imported surface segmentation in Zeffiro Interface. The meshing algorithm is based on the article Highly Adaptive and Automated Tetrahedral Mesh Generator for Multi-Compartment Human Head Model with Deep Brain Structures in EEG (arXiv).

Generating a Mesh via the GUI

There are 2 windows in Zeffiro Interface one needs to concern themselves with, when attempting to generate a mesh from an imported surface segmentation: the Mesh tool and Forward and inverse processing options. The latter can be found under Menu tool > Settings > Forward and inverse processing options.

Mesh tool
Figure 1: Mesh tool.
Forward and inverse processing options
Figure 2: Forward and inverse processing options.


A high-resolution tetrahedral FE mesh can be created based on a polygonal (triangular) surface segmentation of the head and its compartments. A mesh can be created either on command line using, e.g., the example scripts provided in the repository, or by using the graphical user interface. If the latter is the case, one can proceed according to the following points:

  1. Start a project by defining Sensor locations and (magnetometer) orientations together with the points and triangles of the surface meshes either by importing them as a package or by using the segmentation tool. Each layer can be fine-tuned through rotation, scaling and affine mappings. Any changes to the segmentation, will be automatically committed when starting the mesh generation process and can be also obtained by clicking the Apply transform button.

  2. Check that each tissue layer will have the desired conductivity value (Sigma). Other parameters can be defined via the parameter profile.

  3. After the segmentation has been defined, visualize the surfaces by pressing the Visualize surfaces button of the Mesh Visualization tool. The Visible check box for each tissue layer will determine whether or not the layer in question will be shown. Checking the Clipping plane check box will add a clipping plane. The drop-down menu Visualization type should be set to Domain labels, meaning that the compartment structure of the volume conductor model is examined.

Surface meshes
Figure 3: Triangular surface segmentation of a brain cut by an axial, coronal and sagittal plane in the frontal lobe. The compartments correspond to the color labels given in the bottom part of the image.

  1. After defining the surface segmentation, the volumetric (tetrahedral) FE mesh can be generated by pressing the Create FEM mesh button. The mesh resolution (tetrahedron size) can be defined via the Mesh resolution. The FE mesh can be smoothed, refined and inflated. These properties can be controlled via the options of the Mesh tool and those of the Forward and inverse processing options menu. Once the FE mesh has been generated, the mesh can be fine tuned via the Postprocess FEM mesh button.

  2. When the FE mesh is ready, the result can be visualized using the Visualize volume button with Domain labels (conductivity structure) as the Visualization type. An example of a volumetric mesh is given in Figure 4.

  3. After finishing, save the project for further use.

Note: It is preferable to set Meshing accuracy to one (default value) in order to achieve the best possible perfomance. Using a value between 0 and 1 will, in principle, speed up the segmentation process, but can also reduce the quality of the outcome for thin layers.

Volumetric mesh Volumetric mesh
Figure 4: A volumetric tetrahedral mesh with 0.65 mm resolution in the active brain layers.

Generating a Mesh Programmatically

To generate a mesh programmatically, one must first start up an instance of Zeffiro Interface and capture its core struct, usually referred to as zef, so that the meshing-related fields can be modified:

% Start up Zeffiro.

zef = zeffiro_interface('start_mode', 'nodisplay');

% Set meshing-related fields.

zef.meshing_field_1 = some_value;

...

zef.meshing_field_N = some_value;

% Call the meshing routine to generate a mesh.

zef = zef_create_finite_element_mesh(zef);

% Save the project.

zef_save(zef,'zef_meshing_example.mat','data/');

The list of the meshing-related fields is given below.

Meshing-related zef fields

Below is a listing of the fields of zef needed in mesh generation in alphabetical order. The field description titles have the format

zef.fieldname (size) type { validators }

in the spirit of Matlab's class property and function argument validation syntax. See the descriptions for what they actually refer to.

zef.adaptive_refinement_compartments

size: (1,:)
type: double
validators: { .. }

This integer vector defines which compartments will have their surfaces refined during the optional adaptive surface refinement pass of mesh generation. The numbers are the ordinals of the compartments as given in the segmentation import script file import_segmentation.zef, which is used in importing a segmentation generated by FreeSurfer or other similar software. Note that the import script contains lines for both left and right hemispheres, so the number of lines in the file should be divided by 2 to get the actual total number of compartments. The special value of -1 in this vector includes all active compartments in the the set of compartments being refined.

zef.adaptive_refinement_k_param

size: (1,1)
type: double
validators: { .. }

The number of k nearest tetrahedra from a surface being refined. If this is n, then tetrahedra that are n tetrahdra away from a surface will be included into the refinement.

zef.adaptive_refinement_number

size: (1,:)
type: double
validators: { .. }

The amount of times each compartment will be refined. If size is (1,1), then all compartments will be refined the same number of times. If this is a vector, then the integer at index i will determine how many times the ith department in the list of departments to be refined will be refined.

zef.adaptive_refinement_on

size: (1,1)
type: logical
validators: { .. }

Determines whether adaptive refinement will be applied during mesh generation.

zef.adaptive_refinement_thresh_val

size: (1,1)
type: double
validators: { .. }

The threshold value which determines when adaptive refinement should stop. This corresponds to the size of the median tetrahedron in the refined tetrahedra, which based on the code seems to be the distance from one vertex to the opposing face.

zef.exclude_box

size: (1,1)
type: logical
validators: { .. }

Determines whether the assisting box that was used to construct an initial mesh will be included in post-processing such as smoothing.

zef.fem_mesh_inflation_strength

size: (1,1)
type: double
validators: { .. }

A mesh generated by Zeffiro might initially not align with the imported segmentation, which is corrected by inflation or moving of tetrahedral nodes towards segmentation boundaries. This parameter determines how aggressively tetrahedral nodes slide towards a segmented tissue boundary during mesh inflation, which occurs after labeling. This must be between 0 and 1.

zef.fix_outer_surface

size: (1,1)
type: logical
validators: { .. }

Determines whether the surface nodes of a mesh (compartment) are re-determined during each mesh smoothing step.

zef.initial_mesh_mode

size: (1,1)
type: double
validators: { .. }

This is either 1 or 2 and sets how the initial mesh is constructed. If set to 1, each cube in the initial lattice is split into 5 tetrahedra with an alternating pattern of faces and edges, and 2 results in 6 tetrahedra with a non-alternating pattern.

zef.mesh_labeling_approach

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.mesh_optimization_parameter

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.mesh_optimization_repetitions

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.mesh_relabeling

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.mesh_smoothing_repetitions

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.meshing_threshold

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.pml_max_size

size: (1,1)
type: double
validators: { TODO }

The length of the largest edge of a hexa- or tetrahedron in the discretized perfectly matched layer (PML) box, which surrounds a given finite element model.

zef.pml_max_size_unit

size: (1,1)
type: double
validators: { TODO }

Determines whether the measure zef.pml_max_size is given relative to the initial mesh size (1), or absolutely in mm (2).

zef.pml_outer_radius

size: (1,1)
type: fouble
validators: { TODO }

This is half a side length of a cube in an initial hexahedral mesh, before it has been split into tetrahedra.

zef.pml_outer_radius_unit

size: (1,1)
type: double
validators: { TODO }

Describes whether zef.pml_outer_radius is relative to the initial mesh size (1), or absolutely in mm (2).

zef.preconditioner_tolerance

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.reduce_labeling_outliers

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.refinement_surface_compartments

size: (1,:)
type: double
validators: { .. }

This integer vector defines which compartments will have their surfaces refined during the 1st optional surface refinement pass of mesh generation. The numbers are the ordinals of the compartments as given in the segmentation import script file import_segmentation.zef, which is used in importing a segmentation generated by FreeSurfer or other similar software. Note that the import script contains lines for both left and right hemispheres, so the number of lines in the file should be divided by 2 to get the actual total number of compartments. The special value of -1 in this vector includes all active compartments in the the set of compartments being refined.

zef.refinement_surface_compartments_2

size: (1,:)
type: double
validators: { .. }

This integer vector defines which compartments will have their surfaces refined during the 2nd optional surface refinement pass of mesh generation. The numbers are the ordinals of the compartments as given in the segmentation import script file import_segmentation.zef, which is used in importing a segmentation generated by FreeSurfer or other similar software. Note that the import script contains lines for both left and right hemispheres, so the number of lines in the file should be divided by 2 to get the actual total number of compartments. The special value of -1 in this vector includes all active compartments in the the set of compartments being refined.

zef.refinement_surface_number

size: (1,:)
type: double
validators: { .. }

The numbers of times each compartment selected for refinement are refined. If this is a scalar, all compartments are refined an equal number of times.

zef.refinement_surface_number_2

size: (1,:)
type: double
validators: { .. }

The numbers of times each compartment selected for refinement are refined during the post-processing step. If this is a scalar, all compartments are refined an equal number of times.

zef.refinement_surface_on

size: (1,1)
type: logical
validators: { .. }

If this is set to true, refinement is performed on the selected surfaces. If this is false, surface refinement is not performed.

zef.refinement_surface_on_2

size: (1,1)
type: logical
validators: { .. }

If this is set to true, refinement is performed on the selected surfaces during the post-processing step. If this is false, surface refinement is not performed.

zef.refinement_volume_compartments

size: (1,:)
type: double
validators: { .. }

This integer vector defines which compartments will have their surfaces refined during the optional 1st volumetric refinement pass of mesh generation. The numbers are the ordinals of the compartments as given in the segmentation import script file import_segmentation.zef, which is used in importing a segmentation generated by FreeSurfer or other similar software. Note that the import script contains lines for both left and right hemispheres, so the number of lines in the file should be divided by 2 to get the actual total number of compartments. The special value of -1 in this vector includes all active compartments in the the set of compartments being refined.

zef.refinement_volume_compartments_2

size: (1,:)
type: double
validators: { .. }

This integer vector defines which compartments will have their surfaces refined during the optional 2nd volumetric refinement pass of mesh generation. The numbers are the ordinals of the compartments as given in the segmentation import script file import_segmentation.zef, which is used in importing a segmentation generated by FreeSurfer or other similar software. Note that the import script contains lines for both left and right hemispheres, so the number of lines in the file should be divided by 2 to get the actual total number of compartments. The special value of -1 in this vector includes all active compartments in the the set of compartments being refined.

zef.refinement_volume_number

size: (1,:)
type: double
validators: { .. }

The numbers of times each compartment selected for volumetric refinement are refined. If this is a scalar, all compartments are refined an equal number of times.

zef.refinement_volume_number_2

size: (1,:)
type: double
validators: { .. }

The numbers of times each compartment selected for volumetric refinement are refined during the post-processing step. If this is a scalar, all compartments are refined an equal number of times.

zef.refinement_volume_on

size: (1,1)
type: logical
validators: { .. }

This switch enables or disables volumetric refinement during the first pass.

zef.refinement_volume_on_2

size: (1,1)
type: double
validators: { .. }

This switch enables or disables volumetric refinement during the post-processing pass.

zef.smoothing_steps_ele

size: (1,1)
type: double
validators: { TODO }

The number of times smoothing is applied to electrodes.

zef.smoothing_steps_surf

size: (1,:)
type: double
validators: { TODO }

The number of times smoothing is applied to each compartment surface. If this is a scalar, each surface is smoothed the same number of times.

zef.smoothing_steps_vol

size: (1,:)
type: double
validators: { TODO }

The number of times smoothing is applied to each compartment volume. If this is a scalar, each compartment volume is smoothed the same number of times.

zef.streamline_linewidth

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.submesh_num

size: (TODO)
type: TODO
validators: { TODO }

TODO Description.

zef.use_fem_mesh_inflation

size: (1,1)
type: logical
validators: { .. }

This switch determines whether mesh inflation is applied or not.