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.DofManager
— Typestruct 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
FiniteElementContainers.DofManager
— MethodDofManager(
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}
Base.eltype
— Methodeltype(
_::DofManager{T, IDs, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
) -> Any
Base.length
— Methodlength(dof::DofManager) -> Any
FiniteElementContainers.create_field
— Methodcreate_field(
dof::DofManager,
_::Type{H1Field},
syms
) -> H1Field{Float64, _A, Vector{Float64}} where _A
FiniteElementContainers.create_field
— Methodcreate_field(
dof::DofManager,
_::Type{H1Field}
) -> H1Field{Float64, _A, Vector{Float64}} where _A
FiniteElementContainers.create_field
— Methodcreate_field(dof::DofManager, _::Type{L2QuadratureField})
FiniteElementContainers.create_unknowns
— Methodcreate_unknowns(dof::DofManager) -> Any
FiniteElementContainers.num_dofs_per_edge
— Methodnum_dofs_per_edge(
_::DofManager{T, IDs, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
) -> Any
FiniteElementContainers.num_dofs_per_element
— Methodnum_dofs_per_element(
_::DofManager{T, IDs, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
) -> Any
FiniteElementContainers.num_dofs_per_face
— Methodnum_dofs_per_face(
_::DofManager{T, IDs, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
) -> Any
FiniteElementContainers.num_dofs_per_node
— Methodnum_dofs_per_node(
_::DofManager{T, IDs, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
) -> Any
FiniteElementContainers.num_dofs_per_quadrature_point
— Methodnum_dofs_per_quadrature_point(
_::DofManager{T, IDs, NH1Dofs, NHcurlDofs, NHdivDofs, NL2EDofs, NL2QDofs, H1Vars, HcurlVars, HdivVars, L2EVars, L2QVars}
) -> Any
FiniteElementContainers.num_edges
— Methodnum_edges(dof::DofManager) -> Any
FiniteElementContainers.num_faces
— Methodnum_faces(dof::DofManager) -> Any
FiniteElementContainers.num_unknowns
— Methodnum_unknowns(dof::DofManager) -> Any
FiniteElementContainers.update_dofs!
— Methodupdate_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.
FiniteElementContainers.update_field_unknowns!
— Methodupdate_field_unknowns!(
U::H1Field,
dof::DofManager,
Uu::AbstractVector{<:Number}
)
Does a simple copy on CPUs. On GPUs it uses a KernelAbstractions
kernel