@@ -43,7 +43,7 @@ function compute_nonlinear_residual!(residual, A, b, sol, unknowns, PD, SC, free
4343
4444 # add Lagrange residuals
4545 for rs in PD. restrictions
46- mul! (residual. entries , rs. parameters[:matrix ], rs. parameters[:multiplier ], - 1.0 , 1.0 )
46+ mul! (view ( residual[rs . parameters[ :unknown ]]) , rs. parameters[:matrix ], rs. parameters[:multiplier ], - 1.0 , 1.0 )
4747 end
4848
4949
@@ -59,14 +59,14 @@ function compute_nonlinear_residual!(residual, A, b, sol, unknowns, PD, SC, free
5959 end
6060
6161 nlres = length (freedofs) > 0 ? norm (residual. entries[freedofs]) : norm (residual. entries)
62- restriction_residuals = [norm (rs. parameters[:matrix ]' * sol. entries - rs. parameters[:rhs ]) for rs in PD. restrictions]
62+ restriction_residuals = [norm (rs. parameters[:matrix ]' * view ( sol[rs . parameters[ :unknown ]]) - rs. parameters[:rhs ]) for rs in PD. restrictions]
6363
6464 if length (PD. restrictions) > 0
6565 nlres = sqrt (nlres^ 2 + norm (restriction_residuals)^ 2 )
6666 end
6767
6868 for rs in PD. restrictions
69- mul! (residual. entries, rs. parameters[:matrix ], rs. parameters[:multiplier ], 1.0 , 1.0 )
69+ view (residual[rs . parameters[ :unknown ]]) .+ = rs. parameters[:matrix ] * rs. parameters[:multiplier ]
7070 end
7171
7272 if SC. parameters[:verbosity ] > 0
@@ -278,9 +278,6 @@ function solve_linear_system!(A, b, sol, soltemp, residual, unknowns, freedofs,
278278 b_unrestricted = residual. entries
279279 end
280280
281- # # restrictions only involve the blocks coressponding to the unknowns and not necessarily the full sol.entries
282- sol_freedofs = vcat ([view (sol[u]) for u in unknowns]. .. )
283-
284281 if length (PD. restrictions) == 0
285282 if linsolve_needs_matrix
286283 linsolve_A = A_unrestricted
@@ -306,68 +303,97 @@ function solve_linear_system!(A, b, sol, soltemp, residual, unknowns, freedofs,
306303 if linsolve_needs_matrix
307304 if SC. parameters[:compress_restrictions ]
308305
306+ # compress only once and for all
307+ SC. parameters[:compress_restrictions ] = false
308+
309309 SC. parameters[:verbosity ] > 1 && @info " Compressing the restriction matrices..."
310310
311- # combine all restriction matrices into one:
312- combined_transposed_restriction_matrix = vcat (restriction_matrices' ... )
313- combined_restriction_rhs = vcat (restriction_rhss... )
311+ compressed_restrictions = []
312+ compressed_matrices = []
313+ compressed_rhss = []
314+
315+ # find all restricted unknowns
316+ restricted_unknowns = unique ([ re. parameters[:unknown ] for re in PD. restrictions])
317+
318+ for u in restricted_unknowns
314319
315- # compute rank revealing QR decomposition (of the transposed matrix)
316- qr_result = qr (combined_transposed_restriction_matrix )
320+ # which restrictions belong to `u`?
321+ indices = filter (i -> PD . restrictions[i] . parameters[ :unknown ] == u, 1 : length (PD . restrictions) )
317322
318- SC. parameters[:verbosity ] > 1 && @info " QR decomposition computed"
323+ # combine all restriction matrices into one:
324+ combined_transposed_restriction_matrix = vcat (restriction_matrices[indices]' ... )
325+ combined_restriction_rhs = vcat (restriction_rhss[indices]. .. )
319326
320- # extract components (from docs: Q*R = combined_transposed_restriction_matrix[prow, pcol] )
321- (; Q, R, prow, pcol) = qr_result
327+ # compute rank revealing QR decomposition (of the transposed matrix )
328+ qr_result = qr (combined_transposed_restriction_matrix)
322329
323- # we need the inverse column permutation
324- ipcol = invperm (pcol)
330+ SC. parameters[:verbosity ] > 1 && @info " QR decomposition computed"
325331
326- # the new combined restriction block (add another transpose and convert into CSC matrix )
327- combined_restriction_matrix = sparse (R[:, ipcol] ' )
332+ # extract components (from docs: Q*R = combined_transposed_restriction_matrix[prow, pcol] )
333+ (; Q, R, prow, pcol) = qr_result
328334
329- # the new combined restriction rhs
330- combined_restriction_rhs = Q ' combined_restriction_rhs[prow]
335+ # we need the inverse column permutation
336+ ipcol = invperm (pcol)
331337
332- # compress the column space
333- qr_rank = rank (qr_result)
334- SC. parameters[:verbosity ] > 1 && @info " QR decomposition has rank $qr_rank "
335- @assert norm (combined_restriction_rhs[(qr_rank + 1 ): end ]) ≤ 1.0e-12 * norm (combined_restriction_rhs) " the rhs of the restriction is not in the image"
338+ # the new combined restriction block (add another transpose and convert into CSC matrix)
339+ combined_restriction_matrix = sparse (R[:, ipcol]' )
336340
337- combined_restriction_matrix = combined_restriction_matrix[:, 1 : qr_rank]
338- combined_restriction_rhs = combined_restriction_rhs[1 : qr_rank ]
341+ # the new combined restriction rhs
342+ combined_restriction_rhs = Q ' combined_restriction_rhs[prow ]
339343
340- # replace by single entries
341- restriction_matrices = [combined_restriction_matrix]
342- restriction_rhss = [combined_restriction_rhs]
344+ # compress the column space
345+ qr_rank = rank (qr_result)
346+ SC. parameters[:verbosity ] > 1 && @info " QR decomposition has rank $qr_rank "
347+ @assert norm (combined_restriction_rhs[(qr_rank + 1 ): end ]) ≤ 1.0e-12 * norm (combined_restriction_rhs) " the rhs of the restriction is not in the image"
343348
344- # remove previously defined restrictions (with explicit copy of the rhs; it is otherwise modified later)
345- PD. restrictions = [CompressedRestriction (combined_restriction_matrix, deepcopy (combined_restriction_rhs))]
349+ combined_restriction_matrix = combined_restriction_matrix[:, 1 : qr_rank]
350+ combined_restriction_rhs = combined_restriction_rhs[1 : qr_rank]
351+
352+ # replace by single entries
353+ push! (compressed_matrices, combined_restriction_matrix)
354+ push! (compressed_rhss, combined_restriction_rhs)
355+
356+ # explicit copy of the rhs; it is otherwise modified later
357+ compressed_restriction = CompressedRestriction (u, combined_restriction_matrix, deepcopy (combined_restriction_rhs))
358+ push! (compressed_restrictions, compressed_restriction)
359+
360+ SC. parameters[:verbosity ] > 1 && @info " Created new CompressedRestriction for unknown $u "
361+ end
362+
363+ # remove previously defined restrictions
364+ PD. restrictions = compressed_restrictions
365+
366+ restriction_matrices = compressed_matrices
367+ restriction_rhss = compressed_rhss
346368
347369 # update sizes
348- block_sizes = [length (b_unrestricted), length (combined_restriction_rhs) ]
370+ block_sizes = [length (b_unrestricted), length .(compressed_rhss) ... ]
349371 block_ends = cumsum (block_sizes)
350-
351- SC. parameters[:verbosity ] > 1 && @info " Created new CompressedRestriction"
352372 end
353373
354374 linsolve_A = spzeros (Tv, block_ends[end ], block_ends[end ])
355375 linsolve_A[1 : block_ends[1 ], 1 : block_ends[1 ]] = A_unrestricted
356376 end
357377
378+ # corresponding sol entries for each restriction
379+ restricted_sol_entries = [view (sol[re. parameters[:unknown ]]) for re in PD. restrictions]
380+
358381 # # we need to add the (initial) solution to the rhs, since we work with the residual equation
359- for (B, rhs) in zip (restriction_matrices, restriction_rhss)
360- # rhs -= B'sol_freedofs
361- mul! (rhs, B' , sol_freedofs , - 1.0 , 1.0 )
382+ for (B, rhs, sol_entries ) in zip (restriction_matrices, restriction_rhss, restricted_sol_entries )
383+ # rhs -= B'sol_entries
384+ mul! (rhs, B' , sol_entries , - 1.0 , 1.0 )
362385 end
363386
364387 linsolve_b = zeros (Tv, block_ends[end ])
365388 linsolve_b[1 : block_ends[1 ]] = b_unrestricted
366389
367390 for i in eachindex (restriction_matrices)
391+ # index range of the restricted unknown
392+ dof_range = (sol[PD. restrictions[i]. parameters[:unknown ]]. offset + 1 ): (sol[PD. restrictions[i]. parameters[:unknown ]]. last_index)
393+
368394 if linsolve_needs_matrix
369- linsolve_A[1 : block_ends[ 1 ] , (block_ends[i] + 1 ): block_ends[i + 1 ]] = restriction_matrices[i]
370- linsolve_A[(block_ends[i] + 1 ): block_ends[i + 1 ], 1 : block_ends[ 1 ] ] = restriction_matrices[i]'
395+ linsolve_A[dof_range , (block_ends[i] + 1 ): block_ends[i + 1 ]] = restriction_matrices[i]
396+ linsolve_A[(block_ends[i] + 1 ): block_ends[i + 1 ], dof_range ] = restriction_matrices[i]'
371397 end
372398 linsolve_b[(block_ends[i] + 1 ): block_ends[i + 1 ]] = restriction_rhss[i]
373399
0 commit comments