Skip to content

Linear Mesh Adaptations

Morteza edited this page Jun 15, 2022 · 1 revision

Linear Mesh Adaptations

SCOREC/Core provides APIs for conforming mesh adaptation for linear meshes for both isotropic and anisotropic size fields. These APIS are in the namespace ma and the header file ma.h needs to be included in the high-level application program code.

The mesh adapt is driven by a size-field that is specified on the vertices of the input mesh. The size-field could be either isotropic (i.e. 1 scalar value per vertex) or a metric field (i.e., a size vector and a set of 3 directions provided as the columns of a 3x3 matrix).

Size Fields

Isotropic size-fields can be computed using spr error estimation (see https://www.scorec.rpi.edu/pumi/doxygen/namespacespr.html) for more details. We currently do not have support for computing anisotropic size-fields using error estimation techniques. For such cases, users need to come up with their own algorithms to compute the size-field using things like Hessians, etc. The following code snippets show how one can define these field in a way that can be passed to the mesh adapt routines

Isotropic sizefield

Assuming that we have an apf::Mesh2* mesh named mesh, one can define a linear size field as follows:

apf::Field* size = apf::createField(mesh, "field_name", apf::SCALAR, apf::getLagrange(1));

apf::MeshEntity* vert;
apf::MeshIterator* it = mesh->begin(0);

while ( (vert = mesh->iterate(it)) )
{
   apf::setScalar(size, vert, 0, value); // value is the desired edge length at this vertex location
}
mesh->end(it);

Note that for parallel meshes you have to make sure the same value is assigned to vertex on the part boundary, otherwise mesh adapt is going to fail with an error complaining about consistency. One way to ensure this is to call apf::synchronize(size) after the last line of the above code snippet.

Anisotropic sizefield

For anisotropic mesh adapt we will need a vector field for the 3 sizes and a matrix field with the 3 directions. Assuming that we have an apf::Mesh2* mesh named mesh, one can define these fields as follows:

apf::Field* sizes = apf::createField(mesh, "sizes_field_name", apf::VECTOR, apf::getLagrange(1));
apf::Field* frame = apf::createField(mesh, "frame_field_name", apf::MATRIX, apf::getLagrange(1));

apf::MeshEntity* vert;
apf::MeshIterator* it = mesh->begin(0);

while ( (vert = mesh->iterate(it)) )
{
   apf::setVector(sizes, vert, 0, svalue); // svalue is a apf::Vector3 with the 3 desired edge lengths in the 3 principal directions
   apf::setMatrix(frame, vert, 0, fvalue); // fvalue is a apf::Matrix3x3 with each of the 3 eigen-directions in each row of the matrix
}
mesh->end(it);

The same note applies here in terms of the consistency of the fields. In other words, one has to make sure shared vertices on part boundaries are assigned the same sizes and frame values.

Running Mesh Adapt

Once the size-fields are defined mesh adapt can be called as follows

Isotropic Mesh Adapt

ma::Input* in = ma::configure(mesh, size); // where "size" is the apf::Field* object defined above
ma::adapt(in);

Anisotropic Mesh Adapt

ma::Input* in = ma::configure(mesh, sizes, frame, 0, true); // where "sizes" and "frame" are the apf::Field* objects defined above
ma::adapt(in);

Note that the above examples are for demonstration purposes only. There are more functionalities available in SCOREC/Core to handle more cases and situations. Users can always consult the API Documentation Page here (https://www.scorec.rpi.edu/pumi/doxygen/index.html) for more info.