DofManager

The DofManager is a struct that keeps track of which dofs are unknown or constrained. This can work with simple or mixed finite element spaces of various types. It is a glorified book keeper.

A DofManager can be created as follows. First we must create functions for our variables of interest from their associated function spaces.

julia> using Exodus, FiniteElementContainers
julia> mesh = UnstructuredMesh("../../test/poisson/poisson.g")UnstructuredMesh{FileMesh{Exodus.ExodusDatabase{Int32, Int32, Int32, Float64}}, H1Field{Float64, 2, Vector{Float64}, (X = 1, Y = 2)}, Vector{Symbol}, @NamedTuple{block_1::String}, @NamedTuple{block_1::Connectivity{Int64, 4, Vector{Int64}, (node_1 = 1, node_2 = 2, node_3 = 3, node_4 = 4)}}, @NamedTuple{block_1::Vector{Int64}}, @NamedTuple{nset_1::Vector{Int64}, nset_2::Vector{Int64}, nset_3::Vector{Int64}, nset_4::Vector{Int64}}, @NamedTuple{sset_1::Vector{Int64}, sset_2::Vector{Int64}, sset_3::Vector{Int64}, sset_4::Vector{Int64}}, @NamedTuple{sset_1::Vector{Int64}, sset_2::Vector{Int64}, sset_3::Vector{Int64}, sset_4::Vector{Int64}}, @NamedTuple{sset_1::Vector{Int64}, sset_2::Vector{Int64}, sset_3::Vector{Int64}, sset_4::Vector{Int64}}, @NamedTuple{sset_1::Matrix{Int64}, sset_2::Matrix{Int64}, sset_3::Matrix{Int64}, sset_4::Matrix{Int64}}, Nothing, Nothing}(FileMesh{Exodus.ExodusDatabase{Int32, Int32, Int32, Float64}}("../../test/poisson/poisson.g", ExodusDatabase: File name = ../../test/poisson/poisson.g Mode = r Initialization: Number of dim = 2 Number of nodes = 16641 Number of elem = 16384 Number of blocks = 1 Number of node sets = 4 Number of side sets = 4 Block: block_1 NodeSet: nset_1 nset_2 nset_3 nset_4 SideSet: sset_1 sset_2 sset_3 sset_4 ElementVariable: GlobalVariable: NodalVariable: NodeSetVariable: SideSetVariable: ), [1.0 0.9921875 … 0.0078125 0.0; 1.0 1.0 … 0.0 0.0], [:block_1], (block_1 = "QUAD4",), (block_1 = [1 2 … 16510 16511; 2 5 … 16511 16512; 3 6 … 16640 16641; 4 3 … 16639 16640],), (block_1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 … 16375, 16376, 16377, 16378, 16379, 16380, 16381, 16382, 16383, 16384],), (nset_1 = [1, 2, 5, 7, 9, 11, 13, 15, 17, 19 … 239, 241, 243, 245, 247, 249, 251, 253, 255, 257], nset_2 = [257, 258, 387, 516, 645, 774, 903, 1032, 1161, 1290 … 15480, 15609, 15738, 15867, 15996, 16125, 16254, 16383, 16512, 16641], nset_3 = [16513, 16514, 16515, 16516, 16517, 16518, 16519, 16520, 16521, 16522 … 16632, 16633, 16634, 16635, 16636, 16637, 16638, 16639, 16640, 16641], nset_4 = [1, 4, 260, 389, 518, 647, 776, 905, 1034, 1163 … 15353, 15482, 15611, 15740, 15869, 15998, 16127, 16256, 16385, 16514]), (sset_1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 … 119, 120, 121, 122, 123, 124, 125, 126, 127, 128], sset_2 = [128, 256, 384, 512, 640, 768, 896, 1024, 1152, 1280 … 15232, 15360, 15488, 15616, 15744, 15872, 16000, 16128, 16256, 16384], sset_3 = [16257, 16258, 16259, 16260, 16261, 16262, 16263, 16264, 16265, 16266 … 16375, 16376, 16377, 16378, 16379, 16380, 16381, 16382, 16383, 16384], sset_4 = [1, 129, 257, 385, 513, 641, 769, 897, 1025, 1153 … 15105, 15233, 15361, 15489, 15617, 15745, 15873, 16001, 16129, 16257]), (sset_1 = [1, 2, 5, 7, 9, 11, 13, 15, 17, 19 … 239, 241, 243, 245, 247, 249, 251, 253, 255, 257], sset_2 = [257, 258, 387, 516, 645, 774, 903, 1032, 1161, 1290 … 15480, 15609, 15738, 15867, 15996, 16125, 16254, 16383, 16512, 16641], sset_3 = [16513, 16514, 16515, 16516, 16517, 16518, 16519, 16520, 16521, 16522 … 16632, 16633, 16634, 16635, 16636, 16637, 16638, 16639, 16640, 16641], sset_4 = [1, 4, 260, 389, 518, 647, 776, 905, 1034, 1163 … 15353, 15482, 15611, 15740, 15869, 15998, 16127, 16256, 16385, 16514]), (sset_1 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1 … 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], sset_2 = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2 … 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], sset_3 = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3 … 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], sset_4 = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4 … 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]), (sset_1 = [1 2 … 255 257], sset_2 = [257 258 … 16512 16641], sset_3 = [16513 16514 … 16641 16640], sset_4 = [4 1 … 16514 16385]), nothing, nothing)
julia> V = FunctionSpace(mesh, H1Field, Lagrange)FunctionSpace: Type: H1Field Block: 1
julia> u = VectorFunction(V, :u)VectorFunction: names: (:u_x, :u_y)
julia> t = ScalarFunction(V, :t)ScalarFunction: names: t

Now we can supply these variables to the DofManager which takes varargs as inputs

julia> dof = DofManager(u, t)DofManager
  Number of nodes              = 16641
  Number of dofs per node      = 3
  Number of H1 dofs            = 49923
  Number of edges              = 0
  Number of dofs per edge      = 0
  Number of H(curl) dofs       = 0
  Number of faces              = 0
  Number of dofs per edge      = 0
  Number of H(div) dofs        = 0
  Number of L2 element dofs    = 0
  Number of L2 quadrature dofs = 0
  Number of total dofs         = 49923
  Storage type                 = Vector{Int64}

The print methods for this struct show simple metadata about the current dofs for each possible function space.

A set of unknowns can be set up as follows

julia> field = create_unknowns(dof)49923-element Vector{Float64}:
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 ⋮
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0

We can create fields of the right size from the DofManager with the following methods

julia> field = create_field(dof, H1Field)3×16641 H1Field{Float64, 3, Vector{Float64}, (u_x = 1, u_y = 2, t = 3)}:
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0

These methods take the backed of dof into account to ensure that the fields or unknowns produced are on the same device, e.g. CPU/GPU if dof is on the CPU/GPU.

This struct is created with all dofs initially set as unknown. To modify the unknowns we can do the following

API

FiniteElementContainers.DofManagerType
struct DofManager{T, IDs<:AbstractArray{T, 1}, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
  • H1_bc_dofs::AbstractVector

  • H1_unknown_dofs::AbstractVector

  • Hcurl_bc_dofs::AbstractVector

  • Hcurl_unknown_dofs::AbstractVector

  • Hdiv_bc_dofs::AbstractVector

  • Hdiv_unknown_dofs::AbstractVector

  • L2_element_dofs::AbstractVector

  • L2_quadrature_dofs::AbstractVector

  • H1_vars::Any

  • Hcurl_vars::Any

  • Hdiv_vars::Any

  • L2_element_vars::Any

  • L2_quadrature_vars::Any

source
FiniteElementContainers.DofManagerMethod
DofManager(
    vars...
) -> DofManager{T, _B, _C, 0, 0, _D, _E, NamedTuple{_A, var"#s178"}, @NamedTuple{}, @NamedTuple{}, NamedTuple{_A1, var"#s1781"}, NamedTuple{_A2, var"#s1782"}} where {T, _B<:AbstractVector{T}, _C, _D, _E, _A, var"#s178"<:Tuple, _A1, var"#s1781"<:Tuple, _A2, var"#s1782"<:Tuple}
source
Base.eltypeMethod
eltype(
    _::DofManager{T, IDs, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
) -> Any
source
FiniteElementContainers.update_dofs!Method
update_dofs!(
    dof::DofManager,
    dirichlet_dofs::AbstractVector{<:Integer}
)

Currently not GPU compatable.

This is only an issue if dofs that correspond to Dirichlet BCs will change often. Otherwise, setup can be achieved on the CPU and transferred to the GPU.

TODO this method need to look at the dirichlet dofs to see what type of variable is there. That way the appropriate function space book keepers can be updated. Currently this only works with H1 spaces.

source