-
Notifications
You must be signed in to change notification settings - Fork 63
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).
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
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.
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.
Once the size-fields are defined mesh adapt can be called as follows
ma::Input* in = ma::configure(mesh, size); // where "size" is the apf::Field* object defined above
ma::adapt(in);
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.