Skip to content

Commit 74497d7

Browse files
authored
Merge pull request #106 from WIAS-PDELib/fix/store-qr
Improve handling of restriction data; compute nonlinear residual correctly
2 parents 57c44e9 + 438f1ca commit 74497d7

8 files changed

Lines changed: 70 additions & 23 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
### Fixed
66
- The linear residual takes also Lagrange multipliers and Lagrange restrictions into account.
7+
- The nonlinear residual takes also Lagrange multipliers and Lagrange restrictions into account.
8+
9+
### Added
10+
- The compressed restrictions are now stored in a `CompressedRestriction`; for internal use only
11+
- Each restriction stores the current Lagrange multipliers `:multipliers` vector in their parameters.
712

813
## v1.9.0
914

src/ExtendableFEM.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ include("common_restrictions/linear_functional_restriction.jl")
210210
export LinearFunctionalRestriction
211211
export ZeroMeanValueRestriction
212212
export MassRestriction
213+
include("common_restrictions/compressed_restriction.jl")
213214

214215
include("plots.jl")
215216
export plot_convergencehistory!

src/common_restrictions/boundarydata_restriction.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function assemble!(R::BoundaryDataRestriction, sol, SC; kwargs...)
5050
n = length(SC.b.entries)
5151
R.parameters[:matrix] = sparse(fixeddofs, 1:nvals, ones(nvals), n, nvals)
5252
R.parameters[:rhs] = fixedvals
53-
R.parameters[:fixed_dofs] = fixeddofs
53+
R.parameters[:multiplier] = zeros(nvals)
5454

5555
return nothing
5656
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
struct CompressedRestriction <: AbstractRestriction
2+
parameters::Dict{Symbol, Any}
3+
end
4+
5+
6+
"""
7+
CompressedRestriction(matrix::AbstractMatrix, rhs::AbstractVector)
8+
9+
Creates a simple linear restriction as a result of the QR compression of multiple restrictions
10+
in the `solve` call. The compressed matrix and the compressed can be handed over directly in
11+
the constructor.
12+
13+
This is 𝑛𝑜𝑡 exported, for internal use only!
14+
"""
15+
function CompressedRestriction(matrix::AbstractMatrix, rhs::AbstractVector)
16+
return CompressedRestriction(
17+
Dict{Symbol, Any}(
18+
:name => "CompressedRestriction",
19+
:matrix => matrix,
20+
:rhs => rhs,
21+
:multiplier => zero(rhs)
22+
)
23+
)
24+
end

src/common_restrictions/coupled_dofs_restriction.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,7 @@ function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
134134

135135
R_orig.parameters[:matrix] = B
136136
R_orig.parameters[:rhs] = zeros(size(B, 2))
137-
138-
# fixed dofs are all active rows of B
139-
R_orig.parameters[:fixed_dofs] = unique(findnz(B)[1])
137+
R_orig.parameters[:multiplier] = zeros(size(B, 2))
140138

141139
return nothing
142140
end

src/common_restrictions/linear_functional_restriction.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ function assemble!(R::LinearFunctionalRestriction{T, Tv}, sol, SC; kwargs...) wh
7474

7575
R.parameters[:matrix] = sparse(reshape(b.entries, n, 1))
7676
R.parameters[:rhs] = Tv[R.value]
77-
R.parameters[:fixed_dofs] = []
77+
R.parameters[:multiplier] = zeros(1)
7878

7979
return nothing
8080
end

src/restrictions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ end
1818

1919
function assemble!(R::AbstractRestriction, SC; kwargs...)
2020
## assembles internal restriction matrix in R
21+
@warn "assemble! not implemented for $(typeof(R))"
2122
return nothing
2223
end
2324

2425
restriction_matrix(R::AbstractRestriction) = R.parameters[:matrix]
2526
restriction_rhs(R::AbstractRestriction) = R.parameters[:rhs]
26-
fixed_dofs(R::AbstractRestriction) = R.parameters[:fixed_dofs]

src/solvers.jl

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ Compute the nonlinear residual for the current solution.
3838
function compute_nonlinear_residual!(residual, A, b, sol, unknowns, PD, SC, freedofs)
3939
residual.entries .= b.entries
4040
for j in 1:length(b), k in 1:length(b)
41-
addblock_matmul!(residual[j], A[j, k], sol[unknowns[k]], factor = -1)
41+
addblock_matmul!(residual[j], A[j, k], sol[unknowns[k]], factor = -1.0)
4242
end
4343

44-
for op in PD.operators
45-
residual.entries[fixed_dofs(op)] .= 0
44+
# add Lagrange residuals
45+
for rs in PD.restrictions
46+
mul!(residual.entries, rs.parameters[:matrix], rs.parameters[:multiplier], -1.0, 1.0)
4647
end
4748

48-
mask_nonrestricted = ones(Bool, length(residual.entries))
49-
for rs in PD.restrictions
50-
mask_nonrestricted[fixed_dofs(rs)] .= false
49+
50+
for op in PD.operators
51+
residual.entries[fixed_dofs(op)] .= 0
5152
end
5253

5354
for u_off in SC.parameters[:inactive]
@@ -57,10 +58,22 @@ function compute_nonlinear_residual!(residual, A, b, sol, unknowns, PD, SC, free
5758
end
5859
end
5960

60-
nlres = length(freedofs) > 0 ? norm(residual.entries[freedofs]) : norm(residual.entries[mask_nonrestricted])
61+
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]
6163

62-
if SC.parameters[:verbosity] > 0 && length(residual) > 1
63-
@info "sub-residuals = $(norms(residual))"
64+
if length(PD.restrictions) > 0
65+
nlres = sqrt(nlres^2 + norm(restriction_residuals)^2)
66+
end
67+
68+
for rs in PD.restrictions
69+
mul!(residual.entries, rs.parameters[:matrix], rs.parameters[:multiplier], 1.0, 1.0)
70+
end
71+
72+
if SC.parameters[:verbosity] > 0
73+
if length(residual) > 1
74+
@info "sub-residuals = $(norms(residual))"
75+
end
76+
@info "nonlinear residuals of restrictions = $restriction_residuals"
6477
end
6578

6679
return nlres
@@ -244,8 +257,6 @@ function solve_linear_system!(A, b, sol, soltemp, residual, linsolve, unknowns,
244257
else
245258
A_unrestricted = A.entries.cscmatrix
246259
end
247-
#else
248-
# A_unrestricted = A.entries.cscmatrix
249260
end
250261

251262
# we solve for A Δx = r
@@ -267,7 +278,7 @@ function solve_linear_system!(A, b, sol, soltemp, residual, linsolve, unknowns,
267278
else
268279
# add possible Lagrange restrictions
269280
restriction_matrices = [length(freedofs) > 0 ? view(restriction_matrix(re), freedofs, :) : restriction_matrix(re) for re in PD.restrictions ]
270-
restriction_rhss = [length(freedofs) > 0 ? view(restriction_rhs(re), freedofs) : restriction_rhs(re) for re in PD.restrictions ]
281+
restriction_rhss = deepcopy([length(freedofs) > 0 ? view(restriction_rhs(re), freedofs) : restriction_rhs(re) for re in PD.restrictions ])
271282

272283
# block sizes for the block matrix
273284
block_sizes = [length(b_unrestricted), [ length(b) for b in restriction_rhss ]...]
@@ -278,11 +289,6 @@ function solve_linear_system!(A, b, sol, soltemp, residual, linsolve, unknowns,
278289

279290
@timeit timer "LM restrictions (nLMs = $nLMs)" begin
280291

281-
## we need to add the (initial) solution to the rhs, since we work with the residual equation
282-
for (B, rhs) in zip(restriction_matrices, restriction_rhss)
283-
rhs .-= B'sol_freedofs
284-
end
285-
286292
Tv = eltype(b_unrestricted)
287293

288294
## create block matrix
@@ -318,6 +324,9 @@ function solve_linear_system!(A, b, sol, soltemp, residual, linsolve, unknowns,
318324
restriction_matrices = [combined_restriction_matrix]
319325
restriction_rhss = [combined_restriction_rhs]
320326

327+
# remove previously defined restrictions (with explicit copy of the rhs; it is otherwise modified later)
328+
PD.restrictions = [CompressedRestriction(combined_restriction_matrix, deepcopy(combined_restriction_rhs))]
329+
321330
# update sizes
322331
block_sizes = [length(b_unrestricted), length(combined_restriction_rhs)]
323332
total_size = sum(block_sizes)
@@ -327,6 +336,11 @@ function solve_linear_system!(A, b, sol, soltemp, residual, linsolve, unknowns,
327336
A_block[Block(1, 1)] = A_unrestricted
328337
end
329338

339+
## we need to add the (initial) solution to the rhs, since we work with the residual equation
340+
for (B, rhs) in zip(restriction_matrices, restriction_rhss)
341+
rhs .-= B'sol_freedofs
342+
end
343+
330344
b_block = BlockVector(zeros(Tv, total_size), block_sizes)
331345

332346
b_block[Block(1)] = b_unrestricted
@@ -406,6 +420,11 @@ function solve_linear_system!(A, b, sol, soltemp, residual, linsolve, unknowns,
406420
block_ends = cumsum(block_sizes)
407421
restriction_residuals = [norm(residual_flat[(block_ends[i] + 1):block_ends[i + 1]]) for i in 1:(length(block_sizes) - 1) ]
408422
push!(stats[:restriction_residuals], restriction_residuals)
423+
424+
# store Lagrange multipliers
425+
for (i, rs) in enumerate(PD.restrictions)
426+
rs.parameters[:multiplier] = linsolve.u[(block_ends[i] + 1):block_ends[i + 1]]
427+
end
409428
end
410429

411430
linres = norm(residual_flat)

0 commit comments

Comments
 (0)