Skip to content

Commit 601a7ee

Browse files
authored
Merge pull request #34 from WIAS-PDELib/feature/speed-up-periodic-coupling
speed up periodic boundary coupling
2 parents 1112a30 + 01d8d29 commit 601a7ee

1 file changed

Lines changed: 110 additions & 46 deletions

File tree

src/helper_functions.jl

Lines changed: 110 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,45 @@ function get_periodic_coupling_info(
158158
end
159159

160160

161+
# compact variant of lazy_interpolate! specialized on ON_FACES interpolations
162+
function interpolate_on_boundaryfaces(
163+
source::FEVector{Tv, TvG, TiG},
164+
give_opposite,
165+
start_cell::Int = 1, # TODO we interpolate on the "b_from" side: a proper start cell should be given
166+
eps = 1.0e-13,
167+
kwargs...,
168+
) where {Tv, TvG, TiG}
169+
170+
# wrap point evaluation into function that is put into normal interpolate!
171+
xgrid = source[1].FES.xgrid
172+
xdim::Int = size(xgrid[Coordinates], 1)
173+
PE = PointEvaluator([(1, Identity)], source)
174+
xref = zeros(TvG, xdim)
175+
x_source = zeros(TvG, xdim)
176+
CF::ExtendableGrids.CellFinder{TvG, TiG} = ExtendableGrids.CellFinder(xgrid)
177+
last_cell = zeros(Int, 1)
178+
last_cell[1] = start_cell
179+
180+
function __setstartcell(new)
181+
return last_cell[1] = Int(new)
182+
end
183+
184+
function __eval_point(result, qpinfo)
185+
give_opposite(x_source, qpinfo.x)
186+
187+
cell = ExtendableGrids.gFindLocal!(xref, CF, x_source; icellstart = last_cell[1], eps)
188+
if cell == 0
189+
@error "boundary coordinate $(qpinfo.x) opposite to $x_source could not be found in the grid"
190+
else
191+
evaluate_bary!(result, PE, xref, cell)
192+
last_cell[1] = cell
193+
end
194+
return nothing
195+
end
196+
197+
return __eval_point, __setstartcell
198+
end
199+
161200
"""
162201
get_periodic_coupling_matrix(
163202
FES::FESpace,
@@ -178,7 +217,7 @@ Input:
178217
- b_to: boundary region of the grid with dofs to replace the dofs in b_from
179218
- give_opposite! Function in (y,x)
180219
- mask: (optional) vector of masking components
181-
. sparsity_tol: threshold for treating an interpolated value as zero
220+
- sparsity_tol: threshold for treating an interpolated value as zero
182221
183222
give_opposite!(y,x) has to be defined in a way that for each x ∈ b_from the resulting y is in the opposite boundary.
184223
For each x in the grid, the resulting y has to be in the grid, too: incorporate some mirroring of the coordinates.
@@ -193,54 +232,17 @@ Note that A is transposed for efficient col-wise storage.
193232
194233
"""
195234
function get_periodic_coupling_matrix(
196-
FES::FESpace,
197-
xgrid::ExtendableGrid,
235+
FES::FESpace{Tv},
236+
xgrid::ExtendableGrid{TvG, TiG},
198237
b_from,
199238
b_to,
200239
give_opposite!::Function;
201240
mask = :auto,
202241
sparsity_tol = 1.0e-12
203-
)
242+
) where {Tv, TvG, TiG}
204243

205244
@info "Computing periodic coupling matrix. This may take a while."
206245

207-
# compact variant of lazy_interpolate! specialized on ON_FACES interpolations
208-
function interpolate_on_boundaryfaces(
209-
target::FEVectorBlock{T1, Tv, Ti},
210-
source,
211-
give_opposite,
212-
boundary_faces,
213-
start_cell = 1, # TODO we interpolate on the "b_from" side: a proper start cell should be given
214-
eps = 1.0e-13,
215-
kwargs...
216-
) where {T1, Tv, Ti}
217-
218-
# wrap point evaluation into function that is put into normal interpolate!
219-
xgrid = source[1].FES.xgrid
220-
xdim::Int = size(xgrid[Coordinates], 1)
221-
PE = PointEvaluator([(1, Identity)], source)
222-
xref = zeros(Tv, xdim)
223-
x_source = zeros(Tv, xdim)
224-
CF::ExtendableGrids.CellFinder{Tv, Ti} = ExtendableGrids.CellFinder(xgrid)
225-
last_cell = start_cell
226-
227-
function eval_point(result, qpinfo)
228-
x = qpinfo.x
229-
give_opposite(x_source, x)
230-
231-
cell = ExtendableGrids.gFindLocal!(xref, CF, x_source; icellstart = last_cell, eps)
232-
if cell == 0
233-
@error "boundary coordinate $x opposite to $x_source could not be found in the grid"
234-
else
235-
evaluate_bary!(result, PE, xref, cell)
236-
last_cell = cell
237-
end
238-
return nothing
239-
end
240-
241-
return interpolate!(target, ON_FACES, eval_point, items = boundary_faces, kwargs...)
242-
end
243-
244246
# total number of grid boundary faces
245247
boundary_nodes = xgrid[BFaceNodes]
246248
n_boundary_faces = size(boundary_nodes, 2)
@@ -267,10 +269,13 @@ function get_periodic_coupling_matrix(
267269
face_numbers_of_bfaces = xgrid[BFaceFaces]
268270

269271
# find all faces in b_to
270-
faces_in_b_to = Int[]
272+
faces_in_b_to = TiG[]
273+
faces_in_b_from = TiG[]
271274
for (i, region) in enumerate(boundary_regions)
272275
if region == b_to
273276
push!(faces_in_b_to, face_numbers_of_bfaces[i])
277+
elseif region == b_from
278+
push!(faces_in_b_from, face_numbers_of_bfaces[i])
274279
end
275280
end
276281

@@ -285,6 +290,66 @@ function get_periodic_coupling_matrix(
285290
@assert length(mask) == ncomponents "component mask has to match number of components"
286291
end
287292

293+
# do the intervals a=[a1,a2] and b=[b1,b2] overlap?
294+
safety = 1.0e-12 # we would be sad if we miss an overlap due to rounding errors
295+
do_intervals_overlap(a, b) = a[1] b[2] + safety && b[1] a[2] + safety
296+
297+
# do the boxes 𝑓 and 𝑔 overlap?
298+
# we provide the Vector of the coordinate intervals
299+
function do_boxes_overlap(box_f::AbstractVector, box_g::AbstractVector)
300+
for i in eachindex(box_f)
301+
if !do_intervals_overlap(box_f[i], box_g[i])
302+
return false
303+
end
304+
end
305+
306+
# all coordinates overlap
307+
return true
308+
end
309+
310+
dummy = zeros(TvG, size(xgrid[Coordinates], 1))
311+
312+
# flip a face to the other side using the give_opposite! function
313+
# Warning: this overwrites the face
314+
function transfer_face!(face::AbstractMatrix)
315+
for i in axes(face, 2)
316+
@views coord = face[:, i]
317+
give_opposite!(dummy, coord)
318+
@views face[:, i] .= dummy
319+
end
320+
return
321+
end
322+
323+
eval_point, set_start = interpolate_on_boundaryfaces(fe_vector, give_opposite!)
324+
325+
# precompute approximate search region for each boundary face in b_from
326+
search_areas = Dict{TiG, Vector{TiG}}()
327+
coords = xgrid[Coordinates]
328+
facenodes = xgrid[FaceNodes]
329+
box_from = zeros(TvG, 2)
330+
for face_from in faces_in_b_from
331+
coords_from = coords[:, facenodes[:, face_from]]
332+
333+
# transfer the coords_from to the other side
334+
transfer_face!(coords_from)
335+
336+
# get the extrama in each component ( = bounding box of the face)
337+
@views box_from = extrema(coords_from, dims = (2))[:]
338+
339+
for face_to in faces_in_b_to
340+
@views coords_to = coords[:, facenodes[:, face_to]]
341+
@views box_to = extrema(coords_to, dims = (2))[:]
342+
343+
if do_boxes_overlap(box_from, box_to)
344+
if !haskey(search_areas, face_from)
345+
search_areas[face_from] = []
346+
end
347+
push!(search_areas[face_from], face_to)
348+
end
349+
end
350+
end
351+
352+
# loop over boundary face indices: we need this index for dofs_on_boundary
288353
for i_boundary_face in 1:n_boundary_faces
289354

290355
# for each boundary face: check if in b_from
@@ -304,11 +369,10 @@ function get_periodic_coupling_matrix(
304369
fe_vector.entries[local_dof] = 1.0
305370

306371
# interpolate on the opposite boundary using x_trafo = give_opposite
307-
interpolate_on_boundaryfaces(
372+
interpolate!(
308373
fe_vector_target[1],
309-
fe_vector,
310-
give_opposite!,
311-
faces_in_b_to
374+
ON_FACES, eval_point,
375+
items = search_areas[face_numbers_of_bfaces[i_boundary_face]],
312376
)
313377

314378
# deactivate entry

0 commit comments

Comments
 (0)