Degrees of Freedom
Degrees of freedom (dofs) are distributed by the DofHandler
.
Ferrite.DofHandler
— TypeDofHandler(grid::Grid)
Construct a DofHandler
based on the grid grid
.
After construction any number of discrete fields can be added to the DofHandler using add!
. Construction is finalized by calling close!
.
By default fields are added to all elements of the grid. Refer to SubDofHandler
for restricting fields to subdomains of the grid.
Examples
dh = DofHandler(grid)
ip_u = Lagrange{RefTriangle, 2}()^2 # vector interpolation for a field u
ip_p = Lagrange{RefTriangle, 1}() # scalar interpolation for a field p
add!(dh, :u, ip_u)
add!(dh, :p, ip_p)
close!(dh)
Ferrite.SubDofHandler
— TypeSubDofHandler(dh::AbstractDofHandler, cellset::AbstractVecOrSet{Int})
Create an sdh::SubDofHandler
from the parent dh
, pertaining to the cells in cellset
. This allows you to add fields to parts of the domain, or using different interpolations or cell types (e.g. Triangles
and Quadrilaterals
). All fields and cell types must be the same in one SubDofHandler
.
After construction any number of discrete fields can be added to the SubDofHandler using add!
. Construction is finalized by calling close!
on the parent dh
.
Examples
We assume we have a grid
containing "Triangle" and "Quadrilateral" cells, including the cellsets "triangles" and "quadilaterals" for to these cells.
dh = DofHandler(grid)
sdh_tri = SubDofHandler(dh, getcellset(grid, "triangles"))
ip_tri = Lagrange{RefTriangle, 2}()^2 # vector interpolation for a field u
add!(sdh_tri, :u, ip_tri)
sdh_quad = SubDofHandler(dh, getcellset(grid, "quadilaterals"))
ip_quad = Lagrange{RefQuadrilateral, 2}()^2 # vector interpolation for a field u
add!(sdh_quad, :u, ip_quad)
close!(dh) # Finalize by closing the parent
Adding fields to the DofHandlers
Ferrite.add!
— Methodadd!(dh::DofHandler, name::Symbol, ip::Interpolation)
Add a field called name
approximated by ip
to the DofHandler dh
.
The field is added to all cells of the underlying grid, use SubDofHandler
s if the grid contains multiple cell types, or to add the field to subset of all the cells.
Ferrite.add!
— Methodadd!(sdh::SubDofHandler, name::Symbol, ip::Interpolation)
Add a field called name
approximated by ip
to the SubDofHandler sdh
.
Ferrite.close!
— Methodclose!(dh::AbstractDofHandler)
Closes dh
and creates degrees of freedom for each cell.
Dof renumbering
Ferrite.renumber!
— Functionrenumber!(dh::AbstractDofHandler, order)
renumber!(dh::AbstractDofHandler, ch::ConstraintHandler, order)
Renumber the degrees of freedom in the DofHandler and/or ConstraintHandler according to the ordering order
.
order
can be given by one of the following options:
- A permutation vector
perm::AbstractVector{Int}
such that dofi
is renumbered toperm[i]
. DofOrder.FieldWise()
for renumbering dofs field wise.DofOrder.ComponentWise()
for renumbering dofs component wise.DofOrder.Ext{T}
for "external" renumber permutations, see documentation forDofOrder.Ext
for details.
The dof numbering in the DofHandler and ConstraintHandler must always be consistent. It is therefore necessary to either renumber before creating the ConstraintHandler in the first place, or to renumber the DofHandler and the ConstraintHandler together.
Ferrite.DofOrder.FieldWise
— TypeDofOrder.FieldWise()
DofOrder.FieldWise(target_blocks::Vector{Int})
Dof order passed to renumber!
to renumber global dofs field wise resulting in a globally blocked system.
The default behavior is to group dofs of each field into their own block, with the same order as in the DofHandler. This can be customized by passing a vector of the same length as the total number of fields in the DofHandler (see getfieldnames(dh)
) that maps each field to a "target block": to renumber a DofHandler with three fields :u
, :v
, :w
such that dofs for :u
and :w
end up in the first global block, and dofs for :v
in the second global block use DofOrder.FieldWise([1, 2, 1])
.
This renumbering is stable such that the original relative ordering of dofs within each target block is maintained.
Ferrite.DofOrder.ComponentWise
— TypeDofOrder.ComponentWise()
DofOrder.ComponentWise(target_blocks::Vector{Int})
Dof order passed to renumber!
to renumber global dofs component wise resulting in a globally blocked system.
The default behavior is to group dofs of each component into their own block, with the same order as in the DofHandler. This can be customized by passing a vector of length ncomponents
that maps each component to a "target block" (see DofOrder.FieldWise
for details).
This renumbering is stable such that the original relative ordering of dofs within each target block is maintained.
Common methods
Ferrite.ndofs
— Functionndofs(dh::AbstractDofHandler)
Return the number of degrees of freedom in dh
Ferrite.ndofs_per_cell
— Functionndofs_per_cell(dh::AbstractDofHandler[, cell::Int=1])
Return the number of degrees of freedom for the cell with index cell
.
See also ndofs
.
Ferrite.dof_range
— Functiondof_range(sdh::SubDofHandler, field_idx::Int)
dof_range(sdh::SubDofHandler, field_name::Symbol)
dof_range(dh:DofHandler, field_name::Symbol)
Return the local dof range for a given field. The field can be specified by its name or index, where field_idx
represents the index of a field within a SubDofHandler
and field_idxs
is a tuple of the SubDofHandler
-index within the DofHandler
and the field_idx
.
The dof_range
of a field can vary between different SubDofHandler
s. Therefore, it is advised to use the field_idxs
or refer to a given SubDofHandler
directly in case several SubDofHandler
s exist. Using the field_name
will always refer to the first occurrence of field
within the DofHandler
.
Example:
julia> grid = generate_grid(Triangle, (3, 3))
Grid{2, Triangle, Float64} with 18 Triangle cells and 16 nodes
julia> dh = DofHandler(grid); add!(dh, :u, 3); add!(dh, :p, 1); close!(dh);
julia> dof_range(dh, :u)
1:9
julia> dof_range(dh, :p)
10:12
julia> dof_range(dh, (1,1)) # field :u
1:9
julia> dof_range(dh.subdofhandlers[1], 2) # field :p
10:12
Ferrite.celldofs
— Functioncelldofs(dh::AbstractDofHandler, i::Int)
Return a vector with the degrees of freedom that belong to cell i
.
See also celldofs!
.
Ferrite.celldofs!
— Functioncelldofs!(global_dofs::Vector{Int}, dh::AbstractDofHandler, i::Int)
Store the degrees of freedom that belong to cell i
in global_dofs
.
See also celldofs
.
Grid iterators
Ferrite.CellCache
— TypeCellCache(grid::Grid)
CellCache(dh::AbstractDofHandler)
Create a cache object with pre-allocated memory for the nodes, coordinates, and dofs of a cell. The cache is updated for a new cell by calling reinit!(cache, cellid)
where cellid::Int
is the cell id.
Methods with CellCache
reinit!(cc, i)
: reinitialize the cache for celli
cellid(cc)
: get the cell id of the currently cached cellgetnodes(cc)
: get the global node ids of the cellgetcoordinates(cc)
: get the coordinates of the cellcelldofs(cc)
: get the global dof ids of the cellreinit!(fev, cc)
: reinitializeCellValues
orFacetValues
See also CellIterator
.
Ferrite.CellIterator
— TypeCellIterator(grid::Grid, cellset=1:getncells(grid))
CellIterator(dh::AbstractDofHandler, cellset=1:getncells(dh))
Create a CellIterator
to conveniently iterate over all, or a subset, of the cells in a grid. The elements of the iterator are CellCache
s which are properly reinit!
ialized. See CellCache
for more details.
Looping over a CellIterator
, i.e.:
for cc in CellIterator(grid, cellset)
# ...
end
is thus simply convenience for the following equivalent snippet:
cc = CellCache(grid)
for idx in cellset
reinit!(cc, idx)
# ...
end
CellIterator
is stateful and should not be used for things other than for
-looping (e.g. broadcasting over, or collecting the iterator may yield unexpected results).
Ferrite.FacetCache
— TypeFacetCache(grid::Grid)
FacetCache(dh::AbstractDofHandler)
Create a cache object with pre-allocated memory for the nodes, coordinates, and dofs of a cell suitable for looping over faces in a grid. The cache is updated for a new face by calling reinit!(cache, fi::FacetIndex)
.
Methods with fc::FacetCache
reinit!(fc, fi)
: reinitialize the cache for facefi::FacetIndex
cellid(fc)
: get the current cellidgetnodes(fc)
: get the global node ids of the cellgetcoordinates(fc)
: get the coordinates of the cellcelldofs(fc)
: get the global dof ids of the cellreinit!(fv, fc)
: reinitializeFacetValues
See also FacetIterator
.
Ferrite.FacetIterator
— TypeFacetIterator(gridordh::Union{Grid,AbstractDofHandler}, facetset::AbstractVecOrSet{FacetIndex})
Create a FacetIterator
to conveniently iterate over the faces in facestet
. The elements of the iterator are FacetCache
s which are properly reinit!
ialized. See FacetCache
for more details.
Looping over a FacetIterator
, i.e.:
for fc in FacetIterator(grid, facetset)
# ...
end
is thus simply convenience for the following equivalent snippet: ```julia fc = FacetCache(grid) for faceindex in facetset reinit!(fc, faceindex) # ... end
Ferrite.InterfaceCache
— TypeInterfaceCache(grid::Grid)
InterfaceCache(dh::AbstractDofHandler)
Create a cache object with pre-allocated memory for the nodes, coordinates, and dofs of an interface. The cache is updated for a new cell by calling reinit!(cache, facet_a, facet_b)
where facet_a::FacetIndex
and facet_b::FacetIndex
are the two interface faces.
Struct fields of InterfaceCache
ic.a :: FacetCache
: face cache for the first face of the interfaceic.b :: FacetCache
: face cache for the second face of the interfaceic.dofs :: Vector{Int}
: global dof ids for the interface (union ofic.a.dofs
andic.b.dofs
)
Methods with InterfaceCache
reinit!(cache::InterfaceCache, facet_a::FacetIndex, facet_b::FacetIndex)
: reinitialize the cache for a new interfaceinterfacedofs(ic)
: get the global dof ids of the interface
See also InterfaceIterator
.
Ferrite.InterfaceIterator
— TypeInterfaceIterator(grid::Grid, [topology::ExclusiveTopology])
InterfaceIterator(dh::AbstractDofHandler, [topology::ExclusiveTopology])
Create an InterfaceIterator
to conveniently iterate over all the interfaces in a grid. The elements of the iterator are InterfaceCache
s which are properly reinit!
ialized. See InterfaceCache
for more details. Looping over an InterfaceIterator
, i.e.:
for ic in InterfaceIterator(grid, topology)
# ...
end
is thus simply convenience for the following equivalent snippet for grids of dimensions > 1:
ic = InterfaceCache(grid, topology)
for face in topology.face_skeleton
neighborhood = topology.face_face_neighbor[face[1], face[2]]
isempty(neighborhood) && continue
neighbor_face = neighborhood[1]
reinit!(ic, face, neighbor_face)
# ...
end
InterfaceIterator
is stateful and should not be used for things other than for
-looping (e.g. broadcasting over, or collecting the iterator may yield unexpected results).