|
1 | 1 | struct CoupledDofsRestriction{TM} <: AbstractRestriction |
2 | | - coupling_matrix::TM |
| 2 | + coupling_matrices::Vector{TM} |
3 | 3 | parameters::Dict{Symbol, Any} |
4 | 4 | end |
5 | 5 |
|
6 | 6 |
|
7 | 7 | """ |
8 | 8 | CoupledDofsRestriction(matrix::AbstractMatrix) |
9 | 9 |
|
10 | | - Creates an restriction that couples dofs together. |
| 10 | + Creates a restriction that couples dofs together. |
11 | 11 |
|
12 | 12 | The coupling is stored in a CSC Matrix `matrix`, s.t., |
13 | 13 |
|
|
16 | 16 | The matrix can be obtained from, e.g., `get_periodic_coupling_matrix`. |
17 | 17 | """ |
18 | 18 | 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 | + ) |
20 | 26 | end |
21 | 27 |
|
22 | 28 |
|
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 |
24 | 46 |
|
25 | | - # extract all col indices |
26 | | - _, J, _ = findnz(R.coupling_matrix) |
27 | 47 |
|
28 | | - # remove duplicates |
29 | | - unique_cols = unique(J) |
| 48 | +function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...) |
30 | 49 |
|
| 50 | + # extract all col indices and remove duplicates |
31 | 51 | # 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 |
33 | 65 |
|
34 | 66 | R.parameters[:matrix] = B |
35 | | - R.parameters[:rhs] = Zeros(length(unique_cols)) |
| 67 | + R.parameters[:rhs] = Zeros(size(B, 2)) |
36 | 68 |
|
37 | 69 | # 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]) |
40 | 71 |
|
41 | 72 | return nothing |
42 | 73 | end |
0 commit comments