Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross-elements coupling for DiscontinuousLagrange sparsity patterns. #710

Merged
merged 71 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
3b74b2e
Basic full coupling -- starting point
AbdAlazezAhmed Apr 18, 2023
453ed62
Workaround for topology to work in 1D
AbdAlazezAhmed Apr 18, 2023
8424805
Merge branch 'master' into elements-coupling
AbdAlazezAhmed Apr 26, 2023
941d1b7
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed May 10, 2023
945c87a
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed May 15, 2023
d98ba70
Use Codegen.
AbdAlazezAhmed May 15, 2023
3d26fbc
Updated `create_sparsity_pattern`
AbdAlazezAhmed May 15, 2023
ddba70c
Some edits in docstrings
AbdAlazezAhmed May 15, 2023
ac20866
Fix multiple `DiscontinuousLagrange` case
AbdAlazezAhmed May 15, 2023
ae11a01
Commenting L302-L306 makes the example symmetric
AbdAlazezAhmed May 17, 2023
788317a
Undo last commit comment + comment L304
AbdAlazezAhmed May 17, 2023
da9c44b
Note to myself: don't code at 4 am
AbdAlazezAhmed May 17, 2023
15c76b6
Useing `coupling`, fixes symmetry problems
AbdAlazezAhmed May 17, 2023
7dfd6b2
I'm not sure why it was working but I believe this should be the righ…
AbdAlazezAhmed May 18, 2023
072c6f7
Multiple `DiscontinuousLagrange` should couple all dof IIRC.
AbdAlazezAhmed May 18, 2023
3761828
`IsDiscontinuous`
AbdAlazezAhmed May 18, 2023
be7fac6
WIP : tests
AbdAlazezAhmed May 18, 2023
1de25a4
Fixed coupling issue with mixed-dim ip + test now works
AbdAlazezAhmed May 18, 2023
cd95355
Hopefully fixes CI
AbdAlazezAhmed May 18, 2023
33c0baa
Merge branch 'Ferrite-FEM:master' into elements-coupling
AbdAlazezAhmed May 18, 2023
695fa16
Hopefully Hoefully Fixes CI
AbdAlazezAhmed May 18, 2023
bb8ff3f
Dispatch `get_continuous_interpolation` and `IsDiscontinuous` for bot…
AbdAlazezAhmed May 19, 2023
779d395
Add line at the end of sparsity_patterns.jl
AbdAlazezAhmed May 19, 2023
f64cb23
More dispatch edits
AbdAlazezAhmed May 19, 2023
76ff5ab
Fix subdomain `DiscontinuousLagrange` sparsity patterns
AbdAlazezAhmed May 19, 2023
c421f30
Fixing componenents coupling test.
AbdAlazezAhmed May 19, 2023
d75e9cc
Subdomains now works :)
AbdAlazezAhmed May 20, 2023
2cbd306
Always allocate diagonal in tests.
AbdAlazezAhmed May 20, 2023
db3cba8
Merge branch 'Ferrite-FEM:master' into elements-coupling
AbdAlazezAhmed May 20, 2023
a9bf93b
Merge branch 'elements-coupling' of https://github.com/AbdAlazezAhmed…
AbdAlazezAhmed May 20, 2023
462abca
~5000 -> 320 allocations
AbdAlazezAhmed May 21, 2023
0962158
Merge branch 'Ferrite-FEM:master' into elements-coupling
AbdAlazezAhmed May 21, 2023
671493a
Buffer nbasefunctions separately
AbdAlazezAhmed May 21, 2023
3a3c409
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed May 23, 2023
a44ba2d
Hapefully better performance (in terms of allocations) 200*200 grid =…
AbdAlazezAhmed May 23, 2023
0bc790e
Using `push!` and mutating I,J would be better in terms of allocation…
AbdAlazezAhmed May 23, 2023
b7b880d
Fix for 1D elements
AbdAlazezAhmed May 24, 2023
db675e0
Make `elements_coupling` its own coupling matrix.
AbdAlazezAhmed May 31, 2023
cbf319c
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed May 31, 2023
5c766b0
Merge branch 'Ferrite-FEM:master' into elements-coupling
AbdAlazezAhmed Jun 2, 2023
d4bf572
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed Jun 8, 2023
2fe184f
Remove `get_continuous_interpolation`
AbdAlazezAhmed Jun 8, 2023
78a5db3
`adjust_dofs_during_distribution` for `DiscontinuousLagrange`
AbdAlazezAhmed Jun 8, 2023
2eda8d7
Initial test
AbdAlazezAhmed Jun 15, 2023
c4bb299
Eliminate need for testing matrices
AbdAlazezAhmed Jun 16, 2023
f150111
a bit better test?
AbdAlazezAhmed Jun 16, 2023
b65a469
Just a note for subdomain test
AbdAlazezAhmed Jun 16, 2023
1d1c6c4
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed Jun 29, 2023
24ebc14
IsDiscontinuous -> is_discontinuous
AbdAlazezAhmed Jun 29, 2023
d8ef832
using subdofhandlers instead of fieldhandlers
AbdAlazezAhmed Jun 29, 2023
0e86c90
Make `celldofs()` use @view
AbdAlazezAhmed Jun 29, 2023
b27e646
No indexing magic UwU
AbdAlazezAhmed Jun 29, 2023
1539476
Some comments
AbdAlazezAhmed Jun 29, 2023
b719411
Minor update to docs
AbdAlazezAhmed Jun 29, 2023
ccd0e71
celldofsview
AbdAlazezAhmed Jun 29, 2023
83a7425
Crouzeix-Raviart
AbdAlazezAhmed Jul 5, 2023
0e34012
remove view
AbdAlazezAhmed Jul 5, 2023
9649bea
requested edits (please remind me if I missed sth)
AbdAlazezAhmed Jul 5, 2023
c1bd454
Merge branch 'Ferrite-FEM:master' into elements-coupling
AbdAlazezAhmed Jul 6, 2023
2aa9d64
CR is continuous
AbdAlazezAhmed Jul 6, 2023
28d907a
Merge branch 'elements-coupling' of https://github.com/AbdAlazezAhmed…
AbdAlazezAhmed Jul 6, 2023
5d87f9f
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed Jul 6, 2023
bb16acb
Vroom
AbdAlazezAhmed Jul 6, 2023
2e4a07a
use InterfaceIterator
AbdAlazezAhmed Jul 19, 2023
073e29d
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed Jul 19, 2023
3d8018e
UwU
AbdAlazezAhmed Jul 19, 2023
1130709
rename elements_coupling to cross_coupling
fredrikekre Jul 20, 2023
f93c311
Enable coupling in continuous interpolations
AbdAlazezAhmed Jul 20, 2023
7aaada1
Comment
AbdAlazezAhmed Jul 20, 2023
2a72dbb
Merge branch 'master' of https://github.com/AbdAlazezAhmed/Ferrite.jl…
AbdAlazezAhmed Jul 20, 2023
536249d
work with master
AbdAlazezAhmed Jul 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/src/devdocs/interpolations.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Ferrite.edgedof_interior_indices(::Interpolation)
Ferrite.celldof_interior_indices(::Interpolation)
Ferrite.getnbasefunctions(::Interpolation)
Ferrite.reference_coordinates(::Interpolation)
Ferrite.IsDiscontinuous(::Interpolation)
Ferrite.get_continuous_interpolation(::Interpolation)
```

for all entities which exist on that reference element. The dof functions default to having no
Expand Down
132 changes: 114 additions & 18 deletions src/Dofs/sparsity_pattern.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
create_sparsity_pattern(dh::DofHandler; coupling)
create_sparsity_pattern(dh::DofHandler; coupling, topology::Union{Nothing, AbstractTopology} = nothing)
fredrikekre marked this conversation as resolved.
Show resolved Hide resolved

Create the sparsity pattern corresponding to the degree of freedom
numbering in the [`DofHandler`](@ref). Return a `SparseMatrixCSC`
Expand All @@ -12,44 +12,82 @@ in the DofHandler with `true` if fields are coupled and `false` if
not. By default full coupling is assumed.

See the [Sparsity Pattern](@ref) section of the manual.

```julia-repl
julia> using Ferrite

julia> grid = generate_grid(Line, (3,));

julia> topology = ExclusiveTopology(grid);

julia> ip = DiscontinuousLagrange{1, RefCube, 2}();

julia> ipc = Lagrange{1, RefCube, 1}();

julia> dh = DofHandler(grid);

julia> add!(dh, :u, 1,ip);

julia> add!(dh, :v, 1,ipc);

julia> close!(dh);;

julia> K = create_sparsity_pattern(dh, topology = topology)
13×13 SparseMatrixCSC{Float64, Int64} with 109 stored entries:
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 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 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
```
"""
function create_sparsity_pattern(dh::AbstractDofHandler; coupling=nothing)
return _create_sparsity_pattern(dh, nothing, false, true, coupling)
function create_sparsity_pattern(dh::AbstractDofHandler; coupling=nothing,
topology::Union{Nothing, AbstractTopology} = nothing)
return _create_sparsity_pattern(dh, nothing, false, true, coupling; topology)
end

"""
create_symmetric_sparsity_pattern(dh::DofHandler; coupling)
create_symmetric_sparsity_pattern(dh::DofHandler; coupling, topology::Union{Nothing, AbstractTopology} = nothing)

Create the symmetric sparsity pattern corresponding to the degree of freedom
numbering in the [`DofHandler`](@ref) by only considering the upper
triangle of the matrix. Return a `Symmetric{SparseMatrixCSC}`.

See the [Sparsity Pattern](@ref) section of the manual.
"""
function create_symmetric_sparsity_pattern(dh::AbstractDofHandler; coupling=nothing)
return Symmetric(_create_sparsity_pattern(dh, nothing, true, true, coupling), :U)
function create_symmetric_sparsity_pattern(dh::AbstractDofHandler; coupling=nothing,
topology::Union{Nothing, AbstractTopology} = nothing)
return Symmetric(_create_sparsity_pattern(dh, nothing, true, true, coupling; topology), :U)
end

"""
create_symmetric_sparsity_pattern(dh::AbstractDofHandler, ch::ConstraintHandler, coupling)
create_symmetric_sparsity_pattern(dh::AbstractDofHandler, ch::ConstraintHandler, coupling, topology::Union{Nothing, AbstractTopology} = nothing)

Create a symmetric sparsity pattern accounting for affine constraints in `ch`. See
the Affine Constraints section of the manual for further details.
"""
function create_symmetric_sparsity_pattern(dh::AbstractDofHandler, ch::ConstraintHandler;
keep_constrained::Bool=true, coupling=nothing)
return Symmetric(_create_sparsity_pattern(dh, ch, true, keep_constrained, coupling), :U)
keep_constrained::Bool=true, coupling=nothing, topology::Union{Nothing, AbstractTopology} = nothing)
return Symmetric(_create_sparsity_pattern(dh, ch, true, keep_constrained, coupling; topology), :U)
end

"""
create_sparsity_pattern(dh::AbstractDofHandler, ch::ConstraintHandler; coupling)
create_sparsity_pattern(dh::AbstractDofHandler, ch::ConstraintHandler; coupling, topology::Union{Nothing, AbstractTopology} = nothing)

Create a sparsity pattern accounting for affine constraints in `ch`. See
the Affine Constraints section of the manual for further details.
"""
function create_sparsity_pattern(dh::AbstractDofHandler, ch::ConstraintHandler;
keep_constrained::Bool=true, coupling=nothing)
return _create_sparsity_pattern(dh, ch, false, keep_constrained, coupling)
keep_constrained::Bool=true, coupling=nothing, topology::Union{Nothing, AbstractTopology} = nothing)
return _create_sparsity_pattern(dh, ch, false, keep_constrained, coupling; topology)
end

# Compute a coupling matrix of size (ndofs_per_cell × ndofs_per_cell) based on the input
Expand Down Expand Up @@ -96,21 +134,78 @@ function _coupling_to_local_dof_coupling(dh::DofHandler, coupling::AbstractMatri
return outs
end

function _create_sparsity_pattern(dh::AbstractDofHandler, ch#=::Union{ConstraintHandler, Nothing}=#, sym::Bool, keep_constrained::Bool, coupling::Union{AbstractMatrix{Bool},Nothing})
"""
cross_element_coupling!(dh::AbstractDofHandler, topology::ExclusiveTopology, sym::Bool, keep_constrained::Bool, couplings::Union{AbstractVector{<:AbstractMatrix{Bool}},Nothing}, cnt::Int, I::Vector{Int}, J::Vector{Int})
Calculates `I, J` for cross-element coupling
Returns the updated value of `cnt`
Used internally for sparsity patterns with discontinuous interpolations.
"""
function cross_element_coupling!(dh::AbstractDofHandler, topology::ExclusiveTopology, sym::Bool, keep_constrained::Bool, couplings::Union{AbstractVector{<:AbstractMatrix{Bool}},Nothing}, cnt::Int, I::Vector{Int}, J::Vector{Int})
for (fhi, fh) in pairs(dh.fieldhandlers)
ip_infos = InterpolationInfo[]
nbasefunctions = Int[]
for cell_field in fh.fields
ip_info = InterpolationInfo(cell_field.interpolation)
push!(ip_infos, ip_info)
push!(nbasefunctions, getnbasefunctions(cell_field.interpolation))
end
element_dof_start = 0
isnothing(couplings) || (coupling_fh = couplings[fhi])
for (cell_field_i, cell_field) in enumerate(fh.fields)
fii = ip_infos[cell_field_i]
if(!fii.is_discontinuous)
element_dof_start += nbasefunctions[cell_field_i]
continue
end
for cell_idx in eachindex(getcells(dh.grid))
cell_field ∈ dh.fieldhandlers[dh.cell_to_fieldhandler[cell_idx]].fields || continue
cell_dofs = @view dh.cell_dofs[dh.cell_dofs_offset[cell_idx] : dh.cell_dofs_offset[cell_idx] + ndofs_per_cell(dh, cell_idx) - 1]
cell_field_dofs = @view cell_dofs[element_dof_start + 1 : element_dof_start + nbasefunctions[cell_field_i]]
for neighbor_cell in (getdim(dh.grid.cells[cell_idx]) >1 ? topology.cell_face_neighbor[cell_idx] : topology.cell_neighbor[cell_idx])
fredrikekre marked this conversation as resolved.
Show resolved Hide resolved
neighbour_dof_start = 0
for (neighbor_field_i, neighbor_field) in enumerate(fh.fields)
fii2 = ip_infos[neighbor_field_i]
neighbor_field ∈ dh.fieldhandlers[dh.cell_to_fieldhandler[neighbor_cell.idx]].fields || continue
if(!fii2.is_discontinuous)
neighbour_dof_start += nbasefunctions[neighbor_field_i]
continue
end
neighbor_dofs = @view dh.cell_dofs[dh.cell_dofs_offset[neighbor_cell.idx] : dh.cell_dofs_offset[neighbor_cell.idx] + ndofs_per_cell(dh, neighbor_cell.idx) - 1]
neighbor_field_dofs = @view neighbor_dofs[neighbour_dof_start + 1 : neighbour_dof_start + nbasefunctions[neighbor_field_i]]
for j in eachindex(neighbor_field_dofs), i in eachindex(cell_field_dofs)
isnothing(couplings) || coupling_fh[i+element_dof_start,j+neighbour_dof_start] || continue
dofi = cell_field_dofs[i]
dofj = neighbor_field_dofs[j]
sym && (dofi > dofj && continue)
!keep_constrained && (haskey(ch.dofmapping, dofi) || haskey(ch.dofmapping, dofj)) && continue
cnt += 1
_add_or_grow(cnt, I, J, dofi, dofj)
end
neighbour_dof_start += nbasefunctions[neighbor_field_i]
end
end
end
element_dof_start += nbasefunctions[cell_field_i]
end
end
return cnt
end

function _create_sparsity_pattern(dh::AbstractDofHandler, ch#=::Union{ConstraintHandler, Nothing}=#, sym::Bool, keep_constrained::Bool, coupling::Union{AbstractMatrix{Bool},Nothing};
topology::Union{Nothing, AbstractTopology} = nothing)
@assert isclosed(dh)
if !keep_constrained
@assert ch !== nothing && isclosed(ch)
end
if coupling !== nothing
# Extend coupling to be of size (ndofs_per_cell × ndofs_per_cell)
couplings = _coupling_to_local_dof_coupling(dh, coupling, sym)
end

couplings = isnothing(coupling) ? nothing : _coupling_to_local_dof_coupling(dh, coupling, sym)

# Allocate buffers. Compute an upper bound for the buffer length and allocate it all up
# front since they will become large and expensive to re-allocate. The bound is exact
# when keeping constrained dofs (default) and if not it only over-estimates with number
# of entries eliminated by constraints.
max_buffer_length = ndofs(dh) # diagonal elements
has_discontinuous_ip = false
for (fhi, fh) in pairs(dh.fieldhandlers)
set = fh.cellset
n = ndofs_per_cell(fh)
Expand All @@ -120,6 +215,7 @@ function _create_sparsity_pattern(dh::AbstractDofHandler, ch#=::Union{Constraint
coupling_fh = couplings[fhi]
count(coupling_fh[i, j] for i in 1:n for j in (sym ? i : 1):n)
end
has_discontinuous_ip = any(ip -> IsDiscontinuous(ip),fh.field_interpolations)
max_buffer_length += entries_per_cell * length(set)
end
I = Vector{Int}(undef, max_buffer_length)
Expand Down Expand Up @@ -147,7 +243,7 @@ function _create_sparsity_pattern(dh::AbstractDofHandler, ch#=::Union{Constraint
end
end
end

has_discontinuous_ip && (cnt = cross_element_coupling!(dh,topology,sym, keep_constrained, couplings, cnt, I, J))
fredrikekre marked this conversation as resolved.
Show resolved Hide resolved
# Always add diagonal entries
resize!(I, cnt + ndofs(dh))
resize!(J, cnt + ndofs(dh))
Expand Down
Loading