Skip to content

Commit cb2e992

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

5 files changed

Lines changed: 96 additions & 13 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)` only from abstract data without knowledge of the grid or the FES.
7+
It is assumed that the coupling is given between the source and target region and that these regions are parallel hyperplanes.
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; 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/ExtendableFEM.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ using ExtendableFEMBase: ExtendableFEMBase, AbstractFiniteElement,
4040
norms, unicode_gridplot, unicode_scalarplot,
4141
update_basis!, SymmetricGradient
4242
using ExtendableGrids: ExtendableGrids, AT_NODES, AbstractElementGeometry,
43-
Adjacency, AssemblyType, BEdgeNodes, BFaceFaces,
43+
Adjacency, AssemblyType, BEdgeNodes, BFaceFaces, BFaceNormals,
4444
BFaceNodes, BFaceRegions, CellAssemblyGroups,
4545
CellFaceOrientations, CellFaces, CellGeometries,
4646
CellNodes, CellRegions, Coordinates, EdgeNodes,

src/common_restrictions/coupled_dofs_restriction.jl

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,77 @@ 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_region: source boundary region
54+
- target_region: target boundary region
55+
56+
This constructor assumes that
57+
- the source and target boundary regions form two parallel hyperplanes
58+
- the coupling is performed orthogonally between the given hyperplanes
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; 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+
:kwargs => kwargs
72+
)
73+
)
74+
end
75+
76+
4877
function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
4978

79+
# remember original R
80+
R_orig = R
81+
82+
# compute the coupling matrix first, if necessary
83+
if R.coupling_matrices[begin] === nothing
84+
FES = sol[R.parameters[:unknown]].FES
85+
source_region = R.parameters[:source_region]
86+
target_region = R.parameters[:target_region]
87+
R_kwargs = R.parameters[:kwargs]
88+
89+
grid = FES.dofgrid
90+
91+
# at first, we select one face on source/target region
92+
source_bface = findfirst(==(source_region), grid[BFaceRegions])
93+
target_bface = findfirst(==(target_region), grid[BFaceRegions])
94+
95+
# the normal (it should really be opposite to the normal on the other side)
96+
normal = grid[BFaceNormals][:, source_bface]
97+
@assert normal -grid[BFaceNormals][:, target_bface]
98+
99+
# pick a coordinate on each boundary region
100+
source_coord = grid[Coordinates][:, grid[BFaceNodes][1, source_bface]]
101+
target_coord = grid[Coordinates][:, grid[BFaceNodes][1, target_bface]]
102+
103+
# compute the sum of scalar product with the normals (reflection point)
104+
γ = source_coord'normal + target_coord'normal
105+
106+
function give_opposite!(y, x)
107+
σ = 2.0 * normal'x
108+
@. y = x +- σ) * normal # then x ⇔ y are opposite along the normal vector
109+
return nothing
110+
end
111+
112+
coupling_matrix = get_periodic_coupling_matrix(FES, source_region, target_region, give_opposite!; R_kwargs...)
113+
114+
# replace R (in this scope)
115+
R = CoupledDofsRestriction(coupling_matrix)
116+
end
117+
118+
50119
# extract all col indices and remove duplicates
51120
# subtract diagonal and shrink matrix to non-empty cols
52121
Bs = [ (matrix - LinearAlgebra.I)[:, unique(findnz(matrix)[2])] for matrix in R.coupling_matrices ]
@@ -63,11 +132,11 @@ function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
63132
B = B[:, cols_of_interest]
64133
end
65134

66-
R.parameters[:matrix] = B
67-
R.parameters[:rhs] = zeros(size(B, 2))
135+
R_orig.parameters[:matrix] = B
136+
R_orig.parameters[:rhs] = zeros(size(B, 2))
68137

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

72141
return nothing
73142
end

0 commit comments

Comments
 (0)