Wildmeshing Toolkit
|
The wildmeshing toolkit provides a set of algorithms and corresponding data structure for supporting the creation, editing, and optimization of meshes in 2D and 3D. It is designed to support algorithms that that manipulate data on a mesh whose connectivity is changing such asadaptive refinement, shape optimization, or multi-material mesh optimization.
Attribute.hpp
.Tuple.hpp
identifies a "position" on the mesh that can be used for navigation. It is the only way to public interface for accessing attributes. Indices of simplices are purposedly hiddern and not accessible to the public API.Invariant.hpp
(such as non-inversion) are automatically checked after each operation and the operation is rolled back if it does not satisfy the invariants.SimplexCollection.hpp
. Efficient replacement for the most common operations is also supported to improve performance for common operations.MultiMeshManager.hpp
, and provides a mechanism to update them as local operations are applied to either the background mesh or the embedded ones.Function.hpp
.The toolkit implements an abstract interface Mesh.hpp
, which supports simplicial meshes of dimension 0 to 3. The navigation is dimension agnostic and based on a Tuple.hpp
. We currently implement this interface for 4 simplicial mesh types: PointMesh.hpp
, EdgeMesh.hpp
, TriangleMesh.hpp
, and TetMesh.hpp
.
Internally, the data structure is stored as:
For connectivity, for a $d$-simplicial complex we store, for each $d$-simplex, the $d$-simplex and its neighbours (TT for tet, FF for tri) connected through d-1 faces as well as its faces (TF,TE,TV for tet, FE,FV for tri), and one representative for the inverse relationships (for a triangle mesh, every vertex stores the index of one of its incident triangles, and every edge also stores an index of one of the incident triangles). Note that we use only indices internally, but we do not expose this information on purpose to avoid the temptation to use indices in user code (which might be invalidated by local operations).
(TODO: diagrams)
The data structure is not allowed to dynamically resize during local operations: it is responsability of the user to reserve enough memory before attempting to modify a mesh with local operations. Unused memory can be reclaimed by using the function consolidate
. If you are using multimesh use multimesh::consolidate
(perhaps the other consolidate should not be publicly available).
A wmtk::Tuple
is our primitive for navigating a mesh, and represents a set of $d+1$ simplices on a $d$-simplicial complex. These simplices are all faces of one another, one per dimension, and if we select $d$ simplices from a tuple there is at most $1$ other tuple that uses those same $d$ simplices, so navigation is performed by "switching" one of the simplices. It is internally represented as a single global index for the $d$-simplex, and a collection of local indices identifying the local faces (for a triangle mesh, the tuple points to the triangle, and it has two local indices to identify the vertex and edge). Navigation is performed by either accessing an adjency topological relation to move to a different top simplex, or by changing the local indices. The change in local indexes is tabulated at local_switch_tuple.hpp
, making the navigation efficient. The table is generated with the scripts in the autogen folder.
The main classes in the toolkit are:
Mesh.hpp
. It stores a set of attributes and allows navigation and execution of operations. The types of meshes supported are: points (PointMesh.hpp
), edges (EdgeMesh.hpp
), triangles (TriMesh.hpp
) and tetrahedra (TetMesh.hpp
).Tuple.hpp
. A tuple is a ordered set of simplices, containing one simplex for each dimension. It allows navigation by using switch operations, see Representing geometric structures in d dimensions: topology and order.Simplex.hpp
. A simplex uniquely identifies a simplex in a mesh, and it is internally implemented as a primitive type and a tuple. A collection of simplexes can be stored in a SimplexCollection.hpp
. The operations that return collection of simplexes are: boundary.hpp
, closed_star.hpp
, link.hpp
, open_star.hpp
.Accessor.hpp
allows to access the attributes of the mesh.The attribute management system has the following functionalities:
The key concepts are:
register_attribute method.
**Accessors**. They enable safe access to an attribute. A handle can be used to request an accessor using the function
get_accessorof the mesh. There are two types of them,
Constand
Mutable. The mutable one is automatically casted to a const one if necessary.
**Scopes**. Each attribute is accessed with respect to a scope (transaction). If a scope is marked as failed then all changes made during that scope's lifetime is deleted. It is possible to have no scope where data is permanently saved and it is possible to view the mesh from a scope by using the
parent_scope` function in the Mesh class. These scopes are handled by the AttributeManager class.vector_attribute
using a Tuple
or Simplex
. scalar_attribute
can also be used if the attribute only contains a single value.The inclusion tree for storing attributes is: AttributeManager (type), MeshAttributes (simplex dimension), Attribute (simplex index), and vector<T> (final index). The actual data is stored in Attribute as a flat STL vector strided for vector-type attributes.
The inheritance for accessing attributes is: AccessorBase -> CachingAccessor -> Accessor The first two are private, the last is public. AccessorBase provides basic index-based access. CachingAccessor adds a layer on top supporting the use of an intermediate cache to store the changes temporarily. Tuple accessor hides the index access in favor of using a tuple.
The scoping mechanics is complex but entirely hidden by the Accessor interface. Every attribute stores a stack of scopes PerThreadAttributeScopeStacks<T>
. A PerThreadAttributeScopeStacks
is a wrapper for a AttributeScopeStack
. An AttributeScopeStack
is a stack of changes not yet applied to a Attribute. Each change is an AttributeScope
, which inherits from an AttributeCache
to provide the functionality to support a stack. The AttributeCache
stores an AttributeCacheData
, which stores the actual diff of the modifications done on the attribute.
This folder stores a set of scripts that generate navigation tables for the local navigation inside a simplex.
The Function.hpp
provides a generic interface for representing functiosn that might be passed into an optimization scheme, but the majority of our use cases are minimizing "energies" whose degrees of freedom are vertices but their values are defined on a top-dimension simplex, like an integral over triangles on a triangle mesh using barycentric interpolation. We therefore have an interface for defining PerSimplexFunction
s that evaluate an energy on a single simplex, but can be differentiated with respect to an attribute stored on a different simplex.
PerSimplexFunction
provides an interface for defining a function evaluated on a simplex, and whose gradient / hessian can be defined with respect to an attribute stored on faces/cofaces of the simplex.LocalNeighborhoodSumFunction.hpp
provides a sort of Function
that is evaluated in the neighborhood of a target simple so that we can evaluate the full derivative of a variable that affects the evaluation of a function on a set of neighboring simplices. For instance, when evaluating a function on triangles using barycentric interpolation the gradient of a vertex with respect to a per-triangle energy is the sum of the gradients of any triangle coface of the vertex.The simplex
folder contains multiple functions that use these interfaces.
TODO: Refactor in progress
A wmtk::Invariant
is a condition that can be test before wmtk::Invariant::before
or after wmtk::Invariant::after
an operation. If the condition is not satisfied, the operation is either not executed, or rolled back. An invariant can be applied to a simplex of any dimension, and should not rely on the before and after functions being called in order. Example of common invariants are checking for a triangle inversion wmtk::TriangleInersionInvariant
or limiting the size of an edge wmtk::MinEdgeLengthInvariant
. Invariants are associated with operations at runtime: each operation stores a collection of invariants wmtk::TupleOperation::invariants
.
TODO: Explain how to load and save a mesh, and specify the hdf5 format
TODO
TODO:
TODO: refactor in progress
TODO: refactor in progress
This folder contains a set of functions to extract and process simplicial meshes. A wmtk::Simplex
is internally represented as a wmtk::Tuple
and the simplex type wmtk::PrimitiveType
. The functions supported are: closed_star.hpp
, cofaces_single_dimension.hpp
, faces.hpp
, link.hpp
, open_star.hpp
, top_dimension_cofaces.hpp
. We refer to P.L. Homeomorphic Manifolds are Equivalent by Elementary Shellingst for the formal definition. These functions also have an iterable version (i.e. closed_star_iterable.hpp
), which should be used when possible, as it avoids unnecessary memory allocations.
Contains the logger (Logger.hpp
), the rational number type (Rational.hpp
) and additional minor utilities.