Skip to content

Commit

Permalink
begin working towards local_bdim
Browse files Browse the repository at this point in the history
  • Loading branch information
maltezfaria committed Jun 7, 2024
1 parent 3b2d94a commit e2d2419
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 89 deletions.
10 changes: 5 additions & 5 deletions src/adaptive.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function adaptive_correction(iop::IntegralOperator; tol, maxdist = nothing, maxs
else
maxdist
end
dict_near = near_interaction_list(X, Y; tol = maxdist)
dict_near = elements_to_near_targets(X, Y; tol = maxdist)
T = eltype(iop)
msh = mesh(Y)
correction = (I = Int[], J = Int[], V = T[])
Expand Down Expand Up @@ -166,14 +166,14 @@ function adaptive_integration_singular(f, τ̂::ReferenceLine, x̂ₛ; kwargs...
end
end

function near_interaction_list(QX::Quadrature, QY::Quadrature; tol)
function elements_to_near_targets(QX::Quadrature, QY::Quadrature; tol)
X = [coords(q) for q in QX]
msh = mesh(QY)
return near_interaction_list(X, msh; tol)
return elements_to_near_targets(X, msh; tol)
end
function near_interaction_list(X, QY::Quadrature; tol)
function elements_to_near_targets(X, QY::Quadrature; tol)

Check warning on line 174 in src/adaptive.jl

View check run for this annotation

Codecov / codecov/patch

src/adaptive.jl#L174

Added line #L174 was not covered by tests
msh = mesh(QY)
return near_interaction_list(X, msh; tol)
return elements_to_near_targets(X, msh; tol)

Check warning on line 176 in src/adaptive.jl

View check run for this annotation

Codecov / codecov/patch

src/adaptive.jl#L176

Added line #L176 was not covered by tests
end

"""
Expand Down
30 changes: 15 additions & 15 deletions src/bdim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ function local_bdim_correction(
m, n = length(target), length(source)
msh = source.mesh
qnodes = source.qnodes

Check warning on line 198 in src/bdim.jl

View check run for this annotation

Codecov / codecov/patch

src/bdim.jl#L192-L198

Added lines #L192 - L198 were not covered by tests
neighbors = topological_neighbors(msh)
# neighbors = topological_neighbors(msh)
dict_near = etype_to_nearest_points(target, source; maxdist)

Check warning on line 200 in src/bdim.jl

View check run for this annotation

Codecov / codecov/patch

src/bdim.jl#L200

Added line #L200 was not covered by tests
# find first an appropriate set of source points to center the monopoles
qmax = sum(size(mat, 1) for mat in values(source.etype2qtags)) # max number of qnodes per el
Expand Down Expand Up @@ -268,20 +268,20 @@ function local_bdim_correction(
# quadrature for auxiliary surface. In global dim, this is the same
# as the source quadrature, and independent of element. In local
# dim, this is constructed for each element using its neighbors.
function translate(q::QuadratureNode, x, s)
return QuadratureNode(coords(q) + x, weight(q), s * normal(q))
end
nei = neighbors[(E, n)]
qtags_nei = Int[]
for (E, n) in nei
append!(qtags_nei, source.etype2qtags[E][:, n])
end
qnodes_nei = source.qnodes[qtags_nei]
jac = jacobian(el, 0.5)
ν = _normal(jac)
h = sum(qnodes[i].weight for i in jglob)
qnodes_op = map(q -> translate(q, h * ν, -1), qnodes_nei)
a, b = external_boundary()
# function translate(q::QuadratureNode, x, s)
# return QuadratureNode(coords(q) + x, weight(q), s * normal(q))
# end
# nei = neighbors[(E, n)]
# qtags_nei = Int[]
# for (E, n) in nei
# append!(qtags_nei, source.etype2qtags[E][:, n])
# end
# qnodes_nei = source.qnodes[qtags_nei]
# jac = jacobian(el, 0.5)
# ν = _normal(jac)
# h = sum(qnodes[i].weight for i in jglob)
# qnodes_op = map(q -> translate(q, h * ν, -1), qnodes_nei)
# a, b = external_boundary()
# qnodes_aux = source.qnodes[jglob]
qnodes_aux = source.qnodes # this is the global dim
for i in near_list[n]

Check warning on line 287 in src/bdim.jl

View check run for this annotation

Codecov / codecov/patch

src/bdim.jl#L286-L287

Added lines #L286 - L287 were not covered by tests
Expand Down
103 changes: 34 additions & 69 deletions src/mesh.jl
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ function connectivity(msh::SubMesh, E::DataType)
end

"""
near_interaction_list(X,Y::AbstractMesh; tol)
elements_to_near_targets(X,Y::AbstractMesh; tol)
For each element `el` of type `E` in `Y`, return the indices of the points in
`X` which are closer than `tol` to the `center` of `el`.
Expand All @@ -526,7 +526,7 @@ fifth element of type `E`.
If `tol` is a `Dict`, then `tol[E]` is the tolerance for elements of type `E`.
"""
function near_interaction_list(
function elements_to_near_targets(
X::AbstractVector{<:SVector{N}},
Y::AbstractMesh{N};
tol,
Expand All @@ -538,17 +538,47 @@ function near_interaction_list(
for E in element_types(Y)
els = elements(Y, E)
tol_ = isa(tol, Number) ? tol : tol[E]
idxs = _near_interaction_list(balltree, els, tol_)
idxs = _elements_to_near_targets(balltree, els, tol_)
dict[E] = idxs
end
return dict
end

@noinline function _near_interaction_list(balltree, els, tol)
@noinline function _elements_to_near_targets(balltree, els, tol)
centers = map(center, els)
return inrange(balltree, centers, tol)
end

"""
target_to_near_elements(X::AbstractVector{<:SVector{N}}, Y::AbstractMesh{N};
tol)
For each target `x` in `X`, return a vector of tuples `(E, i)` where `E` is the
type of the element in `Y` and `i` is the index of the element in `Y` such that
`x` is closer than `tol` to the center of the element.
"""
function target_to_near_elements(

Check warning on line 560 in src/mesh.jl

View check run for this annotation

Codecov / codecov/patch

src/mesh.jl#L560

Added line #L560 was not covered by tests
X::AbstractVector{<:SVector{N}},
Y::AbstractMesh{N};
tol,
) where {N}
@assert isa(tol, Number) || isa(tol, Dict) "tol must be a number or a dictionary mapping element types to numbers"
dict = Dict{Int,Vector{Tuple{DataType,Int}}}()
balltree = BallTree(X)
for E in element_types(Y)
els = elements(Y, E)
tol_ = isa(tol, Number) ? tol : tol[E]
idxs = _target_to_near_elements(balltree, els, tol_)
for (i, idx) in enumerate(idxs)
dict[i] = get!(dict, i, Vector{Tuple{DataType,Int}}())
for j in idx
push!(dict[i], (E, j))
end
end
end
return dict

Check warning on line 579 in src/mesh.jl

View check run for this annotation

Codecov / codecov/patch

src/mesh.jl#L565-L579

Added lines #L565 - L579 were not covered by tests
end

"""
topological_neighbors(msh::LagrangeMesh, k=1)
Expand Down Expand Up @@ -586,68 +616,3 @@ function topological_neighbors(msh::LagrangeMesh, k = 1)
#TODO: for k > 1, recursively compute the neighbors from the one-neighbors
return one_neighbors

Check warning on line 617 in src/mesh.jl

View check run for this annotation

Codecov / codecov/patch

src/mesh.jl#L617

Added line #L617 was not covered by tests
end

"""
element_to_near_targets(X,Y::AbstractMesh; tol)
For each element `el` of type `E` in `Y`, return the indices of the points in
`X` which are closer than `tol` to the `center` of `el`.
This function returns a dictionary where e.g. `dict[E][5] --> Vector{Int}` gives
the indices of points in `X` which are closer than `tol` to the center of the
fifth element of type `E`.
If `tol` is a `Dict`, then `tol[E]` is the tolerance for elements of type `E`.
"""
function element_to_near_targets(
X::AbstractVector{<:SVector{N}},
Y::AbstractMesh{N};
tol,
) where {N}
@assert isa(tol, Number) || isa(tol, Dict) "tol must be a number or a dictionary mapping element types to numbers"
# for each element type, build the list of targets close to a given element
dict = Dict{DataType,Vector{Vector{Int}}}()
balltree = BallTree(X)
for E in element_types(Y)
els = elements(Y, E)
tol_ = isa(tol, Number) ? tol : tol[E]
idxs = _element_to_near_targets(balltree, els, tol_)
dict[E] = idxs
end
return dict
end

@noinline function _element_to_near_targets(balltree, els, tol)
centers = map(center, els)
return inrange(balltree, centers, tol)
end

"""
target_to_near_elements(X::AbstractVector{<:SVector{N}}, Y::AbstractMesh{N};
tol)
For each target `x` in `X`, return a vector of tuples `(E, i)` where `E` is the
type of the element in `Y` and `i` is the index of the element in `Y` such that
`x` is closer than `tol` to the center of the element.
"""
function target_to_near_elements(
X::AbstractVector{<:SVector{N}},
Y::AbstractMesh{N};
tol,
) where {N}
@assert isa(tol, Number) || isa(tol, Dict) "tol must be a number or a dictionary mapping element types to numbers"
dict = Dict{Int,Vector{Tuple{DataType,Int}}}()
balltree = BallTree(X)
for E in element_types(Y)
els = elements(Y, E)
tol_ = isa(tol, Number) ? tol : tol[E]
idxs = _target_to_near_elements(balltree, els, tol_)
for (i, idx) in enumerate(idxs)
dict[i] = get!(dict, i, Vector{Tuple{DataType,Int}}())
for j in idx
push!(dict[i], (E, j))
end
end
end
return dict
end
52 changes: 52 additions & 0 deletions test/ldim_test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Test
using LinearAlgebra
using Inti
using Random

include("test_utils.jl")

Random.seed!(1)

atol = 5e-2

N = 2
t = :interior
pde = Inti.Laplace(; dim = N)
Inti.clear_entities!()
Ω, msh = gmsh_disk(; center = [0.0, 0.0], rx = 1.0, ry = 1.0, meshsize = 0.2)
Γ = Inti.external_boundary(Ω)
quad = Inti.Quadrature(view(msh, Γ); qorder = 3)
σ = t == :interior ? 1 / 2 : -1 / 2
xs = t == :interior ? ntuple(i -> 3, N) : ntuple(i -> 0.1, N)
T = Inti.default_density_eltype(pde)
c = rand(T)
u = (qnode) -> Inti.SingleLayerKernel(pde)(qnode, xs) * c
dudn = (qnode) -> Inti.AdjointDoubleLayerKernel(pde)(qnode, xs) * c
γ₀u = map(u, quad)
γ₁u = map(dudn, quad)
γ₀u_norm = norm(norm.(γ₀u, Inf), Inf)
γ₁u_norm = norm(norm.(γ₁u, Inf), Inf)
# single and double layer
G = Inti.SingleLayerKernel(pde)
S = Inti.IntegralOperator(G, quad)
Smat = Inti.assemble_matrix(S)
dG = Inti.DoubleLayerKernel(pde)
D = Inti.IntegralOperator(dG, quad)
Dmat = Inti.assemble_matrix(D)
e0 = norm(Smat * γ₁u - Dmat * γ₀u - σ * γ₀u, Inf) / γ₀u_norm

green_multiplier = fill(-0.5, length(quad))
# δS, δD = Inti.bdim_correction(pde, quad, quad, Smat, Dmat; green_multiplier)
δS, δD = Inti.local_bdim_correction(pde, quad, quad, Smat, Dmat; green_multiplier)
Sdim = Smat + δS
Ddim = Dmat + δD
# Sdim, Ddim = Inti.single_double_layer(;
# pde,
# target = quad,
# source = quad,
# compression = (method = :none,),
# correction = (method = :ldim,),
# )
e1 = norm(Sdim * γ₁u - Ddim * γ₀u - σ * γ₀u, Inf) / γ₀u_norm
@show norm(e0, Inf)
@show norm(e1, Inf)

0 comments on commit e2d2419

Please sign in to comment.