@@ -84,8 +84,10 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
8484 if CD. parameters[:verbosity ] > 0
8585 @info " .... coupling $(length (coupling_matrix. nzval)) dofs"
8686 end
87- function assemble (A:: AbstractSparseArray{T} , b:: AbstractVector{T} , assemble_matrix:: Bool , assemble_rhs:: Bool , kwargs... ) where {T}
87+ function assemble! (A:: AbstractSparseArray{T} , b:: AbstractVector{T} , assemble_matrix:: Bool , assemble_rhs:: Bool , kwargs... ) where {T}
8888 if assemble_matrix
89+
90+ # put FE adjacency information into this matrix row
8991 for dof_i in 1 : size (coupling_matrix, 2 )
9092 # this col-view is efficient
9193 coupling_i = @views coupling_matrix[:, dof_i]
@@ -94,23 +96,69 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
9496 continue
9597 end
9698
97- # get the coupled dofs of dof_i and the corresponding weights
98- coupled_dofs, weights = findnz (coupling_i)
99+ targetrow = dof_i + offsetX
100+
101+ coupled_dofs_i, weights_i = findnz (coupling_i)
102+
103+ for dof_j in 1 : size (coupling_matrix, 2 )
104+ # this col-view is efficient
105+ coupling_j = @views coupling_matrix[:, dof_j]
106+
107+ if nnz (coupling_j) == 0
108+ # not both i and j on the boundary
109+
110+ targetcol = dof_j + offsetY
111+ for (dof_k, weight_k) in zip (coupled_dofs_i, weights_i)
112+ sourcerow = dof_k + offsetX
113+ sourcecol = targetcol
114+ 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
99124
100- # transfer all assembly information of dof_i to the
101- # coupled dofs: add the corresponding matrix row
102- sourcerow = dof_i + offsetY
103- for sourcecol in 1 : size (A, 2 )
104- val = A[sourcerow, sourcecol]
105- for dof_j in coupled_dofs
106- targetrow = dof_j + offsetX
107- targetcol = sourcecol
108- _addnz (A, targetrow, targetcol, val, 1 )
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
136+ end
109137 end
110- # eliminate the sourcerow
111- A[sourcerow, sourcecol] = 0
112138 end
139+ end
140+
141+ # replace the geometric coupling rows
142+ for dof_i in 1 : size (coupling_matrix, 2 )
143+ # go through the rows of the matrix; use transposed matrix implicitly
144+
145+ # this row-view is not efficient :(
146+ coupling_i = coupling_matrix[dof_i, :]
147+ # do nothing if no coupling for dof_i
148+ if nnz (coupling_i) == 0
149+ continue
150+ end
151+
152+
153+ # get the coupled dofs of dof_i and the corresponding weights
154+ coupled_dofs, weights = findnz (coupling_i)
113155
156+ sourcerow = dof_i + offsetX
157+
158+ # eliminate the sourcerow
159+ for col in 1 : size (A, 2 )
160+ A[sourcerow, col] = 0
161+ end
114162
115163 # replace sourcerow with coupling linear combination
116164 _addnz (A, sourcerow, sourcerow, - 1.0 , 1 )
@@ -119,11 +167,12 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
119167 _addnz (A, sourcerow, dof_j + offsetY, weight, 1 )
120168 end
121169
122- flush! (A)
123170 end
171+ flush! (A)
124172 end
125173
126174 if assemble_rhs
175+
127176 for dof_i in 1 : size (coupling_matrix, 2 )
128177 # this col-view is efficient
129178 coupling_i = @views coupling_matrix[:, dof_i]
@@ -132,22 +181,36 @@ function build_assembler!(CD::CombineDofs{UT, CT}, FE::Array{<:FEVectorBlock, 1}
132181 continue
133182 end
134183
184+ # get the coupled dofs of dof_i and the corresponding weights
135185 coupled_dofs, weights = findnz (coupling_i)
136- sourcerow = dof_i + offsetY
137186
138- for dof_j in coupled_dofs
139- targetrow = dof_j + offsetX
140- b[targetrow] += b[sourcerow]
187+ # transfer all assembly information to dof_i
188+ targetrow = dof_i + offsetY
189+ for (dof_j, weight) in zip (coupled_dofs, weights)
190+ sourcerow = dof_j + offsetY
191+ b[targetrow] += weight * b[sourcerow]
192+ end
193+ end
194+
195+
196+ for dof_i in 1 : size (coupling_matrix, 2 )
197+ coupling_i = coupling_matrix[dof_i, :]
198+ # do nothing if no coupling for dof_i
199+ if nnz (coupling_i) == 0
200+ continue
141201 end
142202
203+ sourcerow = dof_i + offsetX
204+
143205 b[sourcerow] = 0.0
206+
144207 end
145208 end
146209
147210 return nothing
148211 end
149212
150- CD. assembler = assemble
213+ CD. assembler = assemble!
151214 CD. FESX = FESX
152215 CD. FESY = FESY
153216 end
0 commit comments