Skip to content

Commit 00f19fd

Browse files
committed
Add high-level abstract coupling restriction
This may be much more user friendly
1 parent 6a62533 commit 00f19fd

4 files changed

Lines changed: 83 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGES
22

3+
## v1.9.0
4+
5+
### Added
6+
- It is now possible to create a `CoupledDofsRestriction(unknown, source_region, target_region, axis)` only from abstract data without knowledge of the grid or the FES.
7+
It is assumed that the coupling is given between the extreme coordinates of the grid along the given axis.
8+
39
## v1.8.0
410

511
### Added

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ExtendableFEM"
22
uuid = "a722555e-65e0-4074-a036-ca7ce79a4aed"
3-
version = "1.8.0"
3+
version = "1.9.0"
44
authors = ["Christian Merdon <merdon@wias-berlin.de>", "Patrick Jaap <patrick.jaap@wias-berlin.de>"]
55

66
[deps]

examples/Example312_PeriodicBoundary3D.jl

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ end
129129

130130
function main(;
131131
order = 1,
132-
periodic = true,
133-
use_LM_restrictions = true,
132+
periodic_coupling = :none, # :restriction, :operator, :high_level_restriction
134133
Plotter = nothing,
135134
force = 1.0,
136135
h = 1.0e-4,
@@ -164,16 +163,22 @@ function main(;
164163

165164
assign_operator!(PD, HomogeneousBoundaryData(u; regions = [reg_dirichlet]))
166165

167-
if periodic
166+
if periodic_coupling == :high_level_restriction
167+
168+
# new high-level call
169+
assign_restriction!(PD, CoupledDofsRestriction(u, reg_left, reg_right, 1; parallel = threads > 1, threads))
170+
171+
elseif periodic_coupling != :none
172+
168173
function give_opposite!(y, x)
169174
y .= x
170175
y[1] = width - x[1]
171176
return nothing
172177
end
173178
@showtime coupling_matrix = get_periodic_coupling_matrix(FES, reg_left, reg_right, give_opposite!; parallel = threads > 1, threads)
174-
if use_LM_restrictions
179+
if periodic_coupling == :restriction
175180
assign_restriction!(PD, CoupledDofsRestriction(coupling_matrix))
176-
else
181+
else # :operator
177182
assign_operator!(PD, CombineDofs(u, u, coupling_matrix; kwargs...))
178183
end
179184
end
@@ -191,15 +196,18 @@ end
191196

192197
generateplots = ExtendableFEM.default_generateplots(Example312_PeriodicBoundary3D, "example312.png") #hide
193198
function runtests() #hide
194-
sol1, _ = main(use_LM_restrictions = false, threads = 1) #hide
199+
sol1, _ = main(periodic_coupling = :operator, threads = 1) #hide
195200
@test abs(maximum(view(sol1[1])) - 1.8004602502175202) < 2.0e-3 #hide
196201

197-
sol2, _ = main(use_LM_restrictions = false, threads = 4) #hide
202+
sol2, _ = main(periodic_coupling = :operator, threads = 4) #hide
198203
@test sol1.entries sol2.entries #hide
199204

200-
sol3, _ = main(use_LM_restrictions = true, threads = 4) #hide
205+
sol3, _ = main(periodic_coupling = :restriction, threads = 4) #hide
201206
@test sol1.entries sol3.entries #hide
202207

208+
sol4, _ = main(periodic_coupling = :high_level_restriction, threads = 4) #hide
209+
@test sol1.entries sol4.entries #hide
210+
203211
return nothing #hide
204212
end #hide
205213

src/common_restrictions/coupled_dofs_restriction.jl

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,65 @@ function CoupledDofsRestriction(matrices::Vector{AM}) where {AM <: AbstractMatri
4545
end
4646

4747

48+
"""
49+
CoupledDofsRestriction(source::Ti, target::Ti, axis::Ti) where Ti
50+
51+
Create an incomplete CoupledDofsRestriction by only providing abstract information:
52+
- unknown: the unknown to be coupled
53+
- source: source boundary region
54+
- target: target boundary region
55+
- axis: axis along which the coupling is given
56+
57+
This constructor assumes that the coupling is given between the extrema of the grid coordinates
58+
along the given axis.
59+
60+
The concrete coupling matrix will be computed in the solver, when the grid geometry and the FES is known.
61+
"""
62+
function CoupledDofsRestriction(unknown::Unknown, source_region::Ti, target_region::Ti, axis::Ti; kwargs...) where {Ti}
63+
return CoupledDofsRestriction(
64+
[nothing],
65+
Dict{Symbol, Any}(
66+
:name => "CoupledDofsRestriction",
67+
:reduce_col_space => false,
68+
:unknown => unknown,
69+
:source_region => source_region,
70+
:target_region => target_region,
71+
:axis => axis,
72+
:kwargs => kwargs
73+
)
74+
)
75+
end
76+
77+
4878
function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
4979

80+
# remember original R
81+
R_orig = R
82+
83+
# compute the coupling matrix first, if necessary
84+
if R.coupling_matrices[begin] === nothing
85+
FES = sol[R.parameters[:unknown]].FES
86+
source_region = R.parameters[:source_region]
87+
target_region = R.parameters[:target_region]
88+
axis = R.parameters[:axis]
89+
R_kwargs = R.parameters[:kwargs]
90+
91+
xrange = @views extrema(FES.dofgrid[Coordinates][axis, :])
92+
93+
temp = sum(xrange)
94+
function give_opposite!(a, b)
95+
a .= b
96+
a[axis] = temp - b[axis] # then, x ↔ y are opposite
97+
return nothing
98+
end
99+
100+
coupling_matrix = get_periodic_coupling_matrix(FES, source_region, target_region, give_opposite!; R_kwargs...)
101+
102+
# replace R (in this scope)
103+
R = CoupledDofsRestriction(coupling_matrix)
104+
end
105+
106+
50107
# extract all col indices and remove duplicates
51108
# subtract diagonal and shrink matrix to non-empty cols
52109
Bs = [ (matrix - LinearAlgebra.I)[:, unique(findnz(matrix)[2])] for matrix in R.coupling_matrices ]
@@ -63,11 +120,11 @@ function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
63120
B = B[:, cols_of_interest]
64121
end
65122

66-
R.parameters[:matrix] = B
67-
R.parameters[:rhs] = zeros(size(B, 2))
123+
R_orig.parameters[:matrix] = B
124+
R_orig.parameters[:rhs] = zeros(size(B, 2))
68125

69126
# fixed dofs are all active rows of B
70-
R.parameters[:fixed_dofs] = unique(findnz(B)[1])
127+
R_orig.parameters[:fixed_dofs] = unique(findnz(B)[1])
71128

72129
return nothing
73130
end

0 commit comments

Comments
 (0)