DoF handler
Type definitions
Dof handlers are subtypes of AbstractDofhandler{sdim}, i.e. they are parametrized by the spatial dimension. Internally a helper struct InterpolationInfo is utilized to enforce type stability during dof distribution, because the interpolations are not available as concrete types.
Ferrite.InterpolationInfo — Type
InterpolationInfoGathers all the information needed to distribute dofs for a given interpolation. Note that this cache is of the same type no matter the interpolation: the purpose is to make dof-distribution type-stable.
Ferrite.PathOrientationInfo — Type
PathOrientationInfoOrientation information for 1D entities.
The orientation for 1D entities is defined by the indices of the grid nodes associated to the vertices. To give an example, the oriented path
1 ---> 2is called regular, indicated by regular=true, while the oriented path
2 ---> 1is called inverted, indicated by regular=false.
Ferrite.SurfaceOrientationInfo — Type
SurfaceOrientationInfoOrientation information for 2D entities.
The orientation is defined by the indices of the grid nodes associated to the vertices. 2D entities can be flipped (i.e. the defining vertex order is reverse to the spanning vertex order) and the vertices can be rotated against each other.
The reference entity is one where its first node is the lowest index vertex and its vertices span counter-clock-wise. Take for example the faces
1 2| \ | \| \ | \| A \ | B \| \ | \2-----3 3-----1which are rotated against each other by 240° after transforming to an equilateral triangle (shift index is 2). Or the faces
3 2| \ | \| \ | \| A \ | B \| \ | \2-----1 3-----1which are flipped against each other.
The same applies to quadrilateral faces. Take for example the faces
1---2 2---3| A | | B |4---3 1---4which are rotated against each other by 90° (shift index is 1). Or the faces
1---2 2---1| A | | B |4---3 3---4which are flipped against each other.
Internal API
The main entry point for dof distribution is __close!.
Ferrite.__close! — Function
__close!(dh::DofHandler)Internal entry point for dof distribution.
Dofs are distributed as follows: For the DofHandler each SubDofHandler is visited in the order they were added. For each field in the SubDofHandler create dofs for the cell. This means that dofs on a particular cell will be numbered in groups for each field, so first the dofs for field 1 are distributed, then field 2, etc. For each cell dofs are first distributed on its vertices, then on the interior of edges (if applicable), then on the interior of faces (if applicable), and finally on the cell interior. The entity ordering follows the geometrical ordering found in vertices, faces and edges.
Ferrite.get_grid — Function
get_grid(dh::AbstractDofHandler)Access some grid representation for the dof handler.
Ferrite.find_field — Function
find_field(dh::DofHandler, field_name::Symbol)::NTuple{2, Int}Return the index of the field with name field_name in a DofHandler. The index is a NTuple{2,Int}, where the 1st entry is the index of the SubDofHandler within which the field was found and the 2nd entry is the index of the field within the SubDofHandler.
See also: find_field(sdh::SubDofHandler, field_name::Symbol), Ferrite._find_field(sdh::SubDofHandler, field_name::Symbol).
find_field(sdh::SubDofHandler, field_name::Symbol)::IntReturn the index of the field with name field_name in a SubDofHandler. Throw an error if the field is not found.
See also: find_field(dh::DofHandler, field_name::Symbol), _find_field(sdh::SubDofHandler, field_name::Symbol).
Ferrite._find_field — Function
_find_field(sdh::SubDofHandler, field_name::Symbol)::IntReturn the index of the field with name field_name in the SubDofHandler sdh. Return nothing if the field is not found.
See also: find_field(dh::DofHandler, field_name::Symbol), find_field(sdh::SubDofHandler, field_name::Symbol).
Ferrite._close_subdofhandler! — Function
_close_subdofhandler!(dh::DofHandler{sdim}, sdh::SubDofHandler, sdh_index::Int, nextdof::Int, vertexdicts, edgedicts, facedicts) where {sdim}Main entry point to distribute dofs for a single SubDofHandler on its subdomain.
Ferrite._distribute_dofs_for_cell! — Function
_distribute_dofs_for_cell!(dh::DofHandler{sdim}, cell::AbstractCell, ip_info::InterpolationInfo, nextdof::Int, vertexdict, edgedict, facedict) where {sdim}Main entry point to distribute dofs for a single cell.
Ferrite.permute_and_push! — Function
permute_and_push!For interpolations with more than one interior dof per edge it may be necessary to adjust the dofs. Since dofs are (initially) enumerated according to the local edge direction there can be a direction mismatch with the neighboring element. For example, in the following nodal interpolation example, with three interior dofs on each edge, the initial pass have distributed dofs 4, 5, 6 according to the local edge directions:
+-----------+| A |+--4--5--6->+ local edge on element A ----------> global edge+<-6--5--4--+ local edge on element B| B |+-----------+For most scalar-valued interpolations we can simply compensate for this by reversing the numbering on all edges that do not match the global edge direction, i.e. for the edge on element B in the example.
In addition, we also have to preserve the ordering at each dof location.
For more details we refer to Scroggs et al. [20] as we follow the methodology described therein.
References
- [20] Scroggs et al. ACM Trans. Math. Softw. 48 (2022).
permute_and_push!(cell_dofs::Vector{Int}, dofs::StepRange{Int, Int}, orientation::SurfaceOrientationInfo, adjust_during_distribution::Bool, interior_facedofs_on_lattice::Bool, nfacevertices::Int, rdim::Int)Push the dofs belonging to a face onto cell_dofs, in the order corresponding to the local orientation of the face.
For interpolations with multiple interior dofs per face the dofs must be permuted such that all cells sharing the face associate the same dof with the same location on the face. The dofs are stored according to the canonical orientation of the face (the face as spanned by its sorted vertex tuple, see sortface) and this function maps them to the local orientation, given by orientation (see SurfaceOrientationInfo).
This adjustment is necessary for faces that can be shared between 3D cells. Lattice face dofs on 2D cells are canonicalized as well, because a 2D cell can share its interior with a face of a 3D cell when the same field is used in multiple SubDofHandlers. Face dofs on 2D cells that have not opted in to the lattice assumption are pushed in the stored order (such dofs are not necessarily placed on a lattice, e.g. for RaviartThomas{RefTriangle, 2}).
The permutation assumes that the interior dofs are placed on a regular lattice, in the enumeration order specified by facedof_interior_indices. An interpolation must opt in to this assumption via interior_facedofs_on_lattice; otherwise distributing more than one dof on a shared 3D face errors. For a triangular face with vertices $(v_1, v_2, v_3)$ the interior dofs make up a smaller triangular lattice, which is traversed row by row, where rows are lines of constant barycentric $v_2$-weight, starting with the row closest to the edge $(v_3, v_1)$, and each row is traversed with increasing barycentric $v_1$-weight (i.e. starting from the point closest to $v_3$). This matches the interior node ordering of Lagrange{RefTriangle, order}. For a quadrilateral face the interior dofs make up a regular grid which is traversed row by row, where rows are lines of constant local $v_1 \to v_4$ coordinate, starting with the row closest to the edge $(v_1, v_2)$, and each row is traversed in the direction $v_1 \to v_2$. This matches the interior node ordering of Lagrange{RefQuadrilateral, order}.
For more details we refer to Scroggs et al. [20] as we follow the methodology described therein.
References
- [20] Scroggs et al. ACM Trans. Math. Softw. 48 (2022).