Skip to content

Commit c26fa79

Browse files
authored
Merge pull request #86 from WIAS-PDELib/feature/multi-coupling
`CoupledDofsRestriction`: allow multiple matrices, reduce cols if redundant
2 parents 6e941a0 + 83bc1af commit c26fa79

5 files changed

Lines changed: 57 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# CHANGES
22

3+
## v1.6.0
4+
5+
### Added
6+
7+
- `CoupledDofsRestriction` accepts now an array of multiple coupling matrices.
8+
9+
### Fixed
10+
11+
- Periodic coupling with multiple redundant coupling matrices are now reduced to full rank to make the system uniquely solvable.
12+
313
## v1.5.0
414

515
### Added

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ExtendableFEM"
22
uuid = "a722555e-65e0-4074-a036-ca7ce79a4aed"
3-
version = "1.5.0"
3+
version = "1.6.0"
44
authors = ["Christian Merdon <merdon@wias-berlin.de>", "Patrick Jaap <patrick.jaap@wias-berlin.de>"]
55

66
[deps]

src/ExtendableFEM.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ using LinearSolve: LinearSolve, LinearProblem, UMFPACKFactorization, deleteat!,
7070
init, solve
7171
using Printf: Printf, @printf, @sprintf
7272
using SparseArrays: SparseArrays, AbstractSparseArray, SparseMatrixCSC, findnz, nnz,
73-
nzrange, rowvals, sparse, SparseVector, spzeros
73+
nzrange, rowvals, sparse, SparseVector, spzeros, qr, rank
7474
using StaticArrays: @MArray
7575
using SparseDiffTools: SparseDiffTools, ForwardColorJacCache,
7676
forwarddiff_color_jacobian!, matrix_colors
Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
struct CoupledDofsRestriction{TM} <: AbstractRestriction
2-
coupling_matrix::TM
2+
coupling_matrices::Vector{TM}
33
parameters::Dict{Symbol, Any}
44
end
55

66

77
"""
88
CoupledDofsRestriction(matrix::AbstractMatrix)
99
10-
Creates an restriction that couples dofs together.
10+
Creates a restriction that couples dofs together.
1111
1212
The coupling is stored in a CSC Matrix `matrix`, s.t.,
1313
@@ -16,27 +16,58 @@ end
1616
The matrix can be obtained from, e.g., `get_periodic_coupling_matrix`.
1717
"""
1818
function CoupledDofsRestriction(matrix::AbstractMatrix)
19-
return CoupledDofsRestriction(matrix, Dict{Symbol, Any}(:name => "CoupledDofsRestriction"))
19+
return CoupledDofsRestriction(
20+
[matrix],
21+
Dict{Symbol, Any}(
22+
:name => "CoupledDofsRestriction",
23+
:reduce_col_space => false
24+
)
25+
)
2026
end
2127

2228

23-
function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
29+
"""
30+
CoupledDofsRestriction(matrices::Vector{AM}) where {AM <: AbstractMatrix}
31+
32+
Creates a `CoupledDofsRestriction` from multiple given coupling matrices.
33+
34+
By default, the column space of the matrices is reduced to be of full rank.
35+
This can toggled by the `:reduce_col_space` parameter.
36+
"""
37+
function CoupledDofsRestriction(matrices::Vector{AM}) where {AM <: AbstractMatrix}
38+
return CoupledDofsRestriction(
39+
matrices,
40+
Dict{Symbol, Any}(
41+
:name => "CoupledDofsRestriction",
42+
:reduce_col_space => true
43+
)
44+
)
45+
end
2446

25-
# extract all col indices
26-
_, J, _ = findnz(R.coupling_matrix)
2747

28-
# remove duplicates
29-
unique_cols = unique(J)
48+
function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
3049

50+
# extract all col indices and remove duplicates
3151
# subtract diagonal and shrink matrix to non-empty cols
32-
B = (R.coupling_matrix - LinearAlgebra.I)[:, unique_cols]
52+
Bs = [ (matrix - LinearAlgebra.I)[:, unique(findnz(matrix)[2])] for matrix in R.coupling_matrices ]
53+
54+
# combine all into one matrix
55+
B = hcat(Bs...)
56+
57+
if R.parameters[:reduce_col_space]
58+
# eliminate redundant cols by QR:
59+
qr_result = qr(B)
60+
61+
# pick minimal number of cols that are rank preserving
62+
cols_of_interest = qr_result.pcol[1:rank(qr_result)]
63+
B = B[:, cols_of_interest]
64+
end
3365

3466
R.parameters[:matrix] = B
35-
R.parameters[:rhs] = Zeros(length(unique_cols))
67+
R.parameters[:rhs] = Zeros(size(B, 2))
3668

3769
# fixed dofs are all active rows of B
38-
I, _, _ = findnz(B)
39-
R.parameters[:fixed_dofs] = unique(I)
70+
R.parameters[:fixed_dofs] = unique(findnz(B)[1])
4071

4172
return nothing
4273
end

src/helper_functions.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ function _get_periodic_coupling_matrix(
371371
# throw error if no search area had been found for a bface
372372
for source in 1:num_sources(searchareas)
373373
if num_targets(searchareas, source) == 0
374-
throw("bface $source has no valid search area on the opposite side of the grid. Are from/to regions and give_opposite! function correct?")
374+
throw("bface $source has no valid search area on the opposite side of the grid. Double check the provided from/to regions and your give_opposite! function")
375375
end
376376
end
377377

@@ -499,7 +499,7 @@ For each x in the grid, the resulting y has to be in the grid, too: incorporate
499499
Example: If b_from is at x[1] = 0 and the opposite boundary is at y[1] = 1, then give_opposite!(y,x) = y .= [ 1-x[1], x[2] ]
500500
501501
The return value is a (𝑛 × 𝑛) sparse matrix 𝐴 (𝑛 is the total number of dofs) containing the periodic coupling information.
502-
The relation ship between the degrees of freedome is dofᵢ = ∑ⱼ Aⱼᵢ ⋅ dofⱼ.
502+
The relation ship between the degrees of freedom is dofᵢ = ∑ⱼ Aⱼᵢ ⋅ dofⱼ.
503503
It is guaranteed that
504504
i) Aᵢⱼ=0 if dofᵢ is 𝑛𝑜𝑡 on the boundary b_from.
505505
ii) Aᵢⱼ=0 if the opposite of dofᵢ is not in the same grid cell as dofⱼ.

0 commit comments

Comments
 (0)