Skip to content

Commit 1f2bec4

Browse files
committed
Implement Christian's brilliant finding
1 parent 82decb0 commit 1f2bec4

1 file changed

Lines changed: 30 additions & 43 deletions

File tree

src/common_operators/combinedofs.jl

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -87,71 +87,59 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
8787
function assemble!(A::AbstractSparseArray{T}, b::AbstractVector{T}, assemble_matrix::Bool, assemble_rhs::Bool, kwargs...) where {T}
8888
if assemble_matrix
8989

90-
# put FE adjacency information into this matrix row
91-
for dof_i in 1:size(coupling_matrix, 2)
90+
# transpose the matrix once for efficient row access
91+
transposed_coupling_matrix = sparse(transpose(coupling_matrix))
92+
93+
# go through each coupled dof and update the FE adjacency info
94+
# from the constrained dofs here
95+
96+
for dof_i in 1:size(transposed_coupling_matrix, 2)
9297
# this col-view is efficient
93-
coupling_i = @views coupling_matrix[:, dof_i]
94-
# do nothing if no coupling for dof_i
98+
coupling_i = @views transposed_coupling_matrix[:, dof_i]
99+
# do nothing if dof_k is not coupled to any constrained dof
95100
if nnz(coupling_i) == 0
96101
continue
97102
end
98103

104+
# write the FE adjacency of the constrained dofs into this row
99105
targetrow = dof_i + offsetX
100106

107+
# extract the constrained dofs and the weights
101108
coupled_dofs_i, weights_i = findnz(coupling_i)
102109

103-
for dof_j in 1:size(coupling_matrix, 2)
110+
# parse through all cols and update the entries
111+
for dof_j in 1:size(transposed_coupling_matrix, 2)
104112
# this col-view is efficient
105-
coupling_j = @views coupling_matrix[:, dof_j]
113+
coupling_j = @views transposed_coupling_matrix[:, dof_j]
106114

115+
# if both dof_i and dof_j are coupled to a constrained dof, then
116+
# the FE adjacency A_ij is not updated: this is covered by the linear combinations
117+
# expressed in the rows of the constrained dofs_on_boundary
118+
# Hence, check that dof_j is not coupled to anything
107119
if nnz(coupling_j) == 0
108-
# not both i and j on the boundary
109-
110120
targetcol = dof_j + offsetY
111-
for (dof_k, weight_k) in zip(coupled_dofs_i, weights_i)
121+
for (dof_k, weight_ik) in zip(coupled_dofs_i, weights_i)
112122
sourcerow = dof_k + offsetX
113123
sourcecol = targetcol
114124
val = A[sourcerow, sourcecol]
115-
_addnz(A, targetrow, targetcol, val, weight_k)
116-
end
117-
118-
119-
else
120-
# i and j on the same boundary
121-
122-
coupled_dofs_j, weights_j = findnz(coupling_j)
123-
targetcol = dof_j + offsetY
124-
125-
for (dof_k, weight_k) in zip(coupled_dofs_i, weights_i)
126-
for (dof_l, weight_l) in zip(coupled_dofs_j, weights_j)
127-
128-
sourcerow = dof_k + offsetX
129-
sourcecol = dof_l + offsetY
130-
131-
val = A[sourcerow, sourcecol]
132-
# @show sourcerow, sourcecol, targetrow, targetcol, val, weight_k, weight_l
133-
_addnz(A, targetrow, targetcol, val, weight_k * weight_l)
134-
135-
end
125+
_addnz(A, targetrow, targetcol, val, weight_ik)
136126
end
137127
end
138128
end
139129
end
140130

141-
# replace the geometric coupling rows
131+
# replace the geometric coupling rows based
132+
# on the original coupling matrix
142133
for dof_i in 1:size(coupling_matrix, 2)
143-
# go through the rows of the matrix; use transposed matrix implicitly
144134

145-
# this row-view is not efficient :(
146-
coupling_i = coupling_matrix[dof_i, :]
135+
coupling_i = coupling_matrix[:, dof_i]
147136
# do nothing if no coupling for dof_i
148137
if nnz(coupling_i) == 0
149138
continue
150139
end
151140

152-
153141
# get the coupled dofs of dof_i and the corresponding weights
154-
coupled_dofs, weights = findnz(coupling_i)
142+
coupled_dofs_i, weights_i = findnz(coupling_i)
155143

156144
sourcerow = dof_i + offsetX
157145

@@ -162,9 +150,9 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
162150

163151
# replace sourcerow with coupling linear combination
164152
_addnz(A, sourcerow, sourcerow, -1.0, 1)
165-
for (dof_j, weight) in zip(coupled_dofs, weights)
153+
for (dof_j, weight_ij) in zip(coupled_dofs_i, weights_i)
166154
# weights for ∑ⱼ wⱼdofⱼ - dofᵢ = 0
167-
_addnz(A, sourcerow, dof_j + offsetY, weight, 1)
155+
_addnz(A, sourcerow, dof_j + offsetY, weight_ij, 1)
168156
end
169157

170158
end
@@ -173,9 +161,9 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
173161

174162
if assemble_rhs
175163

176-
for dof_i in 1:size(coupling_matrix, 2)
164+
for dof_i in 1:size(transposed_coupling_matrix, 2)
177165
# this col-view is efficient
178-
coupling_i = @views coupling_matrix[:, dof_i]
166+
coupling_i = @views transposed_coupling_matrix[:, dof_i]
179167
# do nothing if no coupling for dof_i
180168
if nnz(coupling_i) == 0
181169
continue
@@ -193,16 +181,15 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
193181
end
194182

195183

184+
# now set the rows of the constrained dofs to zero to enforce the linear combination
196185
for dof_i in 1:size(coupling_matrix, 2)
197186
coupling_i = coupling_matrix[dof_i, :]
198187
# do nothing if no coupling for dof_i
199188
if nnz(coupling_i) == 0
200189
continue
201190
end
202191

203-
sourcerow = dof_i + offsetX
204-
205-
b[sourcerow] = 0.0
192+
b[dof_i + offsetX] = 0.0
206193

207194
end
208195
end

0 commit comments

Comments
 (0)