Skip to content

Commit a0a1b30

Browse files
juliohmeliascarv
andauthored
Optimize topological relations (#1006)
* Refactor refinement algorithms to support tuples * Return tuples in Boundary relation * Optimize Adjacency * More adjustments * Return tuple in Adjacency relation * Optimize Coboundary * Return tuple in Coboundary --------- Co-authored-by: Elias Carvalho <[email protected]>
1 parent 0758827 commit a0a1b30

File tree

11 files changed

+520
-501
lines changed

11 files changed

+520
-501
lines changed

ext/mesh.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ function vizmesh!(plot, ::Type{<:𝔼}, ::Val{2}, ::Val)
163163
# interleaved with a sentinel index
164164
inds = Int[]
165165
for i in 1:nfacets(t)
166-
append!(inds, (i))
166+
for j in (i)
167+
push!(inds, j)
168+
end
167169
push!(inds, nvert + 1)
168170
end
169171

src/matrices.jl

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ Optionally, specify the `kind` of discretization.
1717
1818
## Available discretizations
1919
20-
* `:uniform` - `Lᵢⱼ = 1 / |𝒩(i)|, ∀j ∈ 𝒩(i)`
21-
* `:cotangent` - `Lᵢⱼ = cot(αᵢⱼ) + cot(βᵢⱼ), ∀j ∈ 𝒩(i)`
20+
* `:uniform` - `Lᵢⱼ = 1 / |𝒜(i)|, ∀j ∈ 𝒜(i)`
21+
* `:cotangent` - `Lᵢⱼ = cot(αᵢⱼ) + cot(βᵢⱼ), ∀j ∈ 𝒜(i)`
22+
23+
where `𝒜(i)` is the adjacency relation at vertex `i`.
2224
2325
## References
2426
@@ -38,46 +40,49 @@ function laplacematrix(mesh; kind=nothing)
3840
𝒯 = adjusttopo(topology(mesh))
3941

4042
# retrieve adjacency relation
41-
𝒩 = Adjacency{0}(𝒯)
43+
𝒜 = Adjacency{0}(𝒯)
4244

4345
# initialize matrix
4446
n = nvertices(mesh)
4547
L = spzeros(n, n)
4648

4749
# fill matrix
4850
if 𝒦 == :uniform
49-
uniformlaplacian!(L, 𝒩)
51+
uniformlaplacian!(L, 𝒜)
5052
elseif 𝒦 == :cotangent
51-
cotangentlaplacian!(L, 𝒩, vertices(mesh))
53+
cotangentlaplacian!(L, 𝒜, vertices(mesh))
5254
end
5355

5456
L
5557
end
5658

57-
function uniformlaplacian!(L, 𝒩)
59+
function uniformlaplacian!(L, 𝒜)
5860
n = size(L, 1)
5961
for i in 1:n
60-
js = 𝒩(i)
62+
js = 𝒜(i)
6163
for j in js
6264
L[i, j] = 1 / length(js)
6365
end
6466
L[i, i] = -1
6567
end
6668
end
6769

68-
function cotangentlaplacian!(L, 𝒩, v)
70+
function cotangentlaplacian!(L, 𝒜, v)
6971
n = size(L, 1)
7072
for i in 1:n
71-
js = CircularVector(𝒩(i))
72-
for k in 1:length(js)
73-
j₋, j, j₊ = js[k - 1], js[k], js[k + 1]
73+
js = 𝒜(i)
74+
m = length(js)
75+
for k in 1:m
76+
j₋ = js[mod1(k - 1, m)]
77+
j = js[mod1(k, m)]
78+
j₊ = js[mod1(k + 1, m)]
7479
vᵢ, vⱼ = v[i], v[j]
7580
v₋, v₊ = v[j₋], v[j₊]
7681
αᵢⱼ = (vⱼ, v₋, vᵢ)
7782
βᵢⱼ = (vᵢ, v₊, vⱼ)
7883
L[i, j] = cot(αᵢⱼ) + cot(βᵢⱼ)
7984
end
80-
L[i, i] = -sum(L[i, js])
85+
L[i, i] = -sum(j -> L[i, j], js)
8186
end
8287
end
8388

@@ -100,7 +105,7 @@ function measurematrix(mesh)
100105
D = paramdim(mesh)
101106

102107
# retrieve coboundary relation
103-
= Coboundary{0,D}(𝒯)
108+
𝒞 = Coboundary{0,D}(𝒯)
104109

105110
# pre-compute all measures
106111
A = measure.(mesh)
@@ -111,7 +116,8 @@ function measurematrix(mesh)
111116

112117
# fill matrix
113118
for i in 1:n
114-
Aᵢ = sum(A[(i)]) / 3
119+
js = 𝒞(i)
120+
Aᵢ = sum(j -> A[j], js) / 3
115121
M[i, i] = 2Aᵢ
116122
end
117123

src/refinement/catmullclark.jl

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,20 @@ function refine(mesh, ::CatmullClark)
3232
# add centroids of elements
3333
∂₂₀ = Boundary{2,0}(t)
3434
epts = map(1:nelements(t)) do elem
35-
ps = view(points, ∂₂₀(elem))
36-
cₒ = sum(to, ps) / length(ps)
35+
is = ∂₂₀(elem)
36+
cₒ = sum(j -> to(points[j]), is) / length(is)
3737
withcrs(mesh, cₒ)
3838
end
3939

4040
# add midpoints of edges
4141
∂₁₂ = Coboundary{1,2}(t)
4242
∂₁₀ = Boundary{1,0}(t)
4343
fpts = map(1:nfacets(t)) do edge
44-
ps = view(epts, ∂₁₂(edge))
45-
qs = view(points, ∂₁₀(edge))
46-
∑p = sum(to, ps)
47-
∑q = sum(to, qs)
48-
M = length(ps) + length(qs)
44+
is = ∂₁₂(edge)
45+
js = ∂₁₀(edge)
46+
∑p = sum(i -> to(epts[i]), is)
47+
∑q = sum(j -> to(points[j]), js)
48+
M = length(is) + length(js)
4949
withcrs(mesh, (∑p + ∑q) / M)
5050
end
5151

@@ -57,16 +57,13 @@ function refine(mesh, ::CatmullClark)
5757
P = to(points[u])
5858

5959
# average of centroids
60-
ps = view(epts, ∂₀₂(u))
61-
F = sum(to, ps) / length(ps)
60+
is = ∂₀₂(u)
61+
F = sum(i -> to(epts[i]), is) / length(is)
6262

6363
# average of midpoints
6464
vs = ∂₀₀(u)
6565
n = length(vs)
66-
R = sum(vs) do v
67-
uv = view(points, [u, v])
68-
sum(to, uv) / 2
69-
end / n
66+
R = sum(v -> to(points[u]) + to(points[v]), vs) / 2n
7067

7168
withcrs(mesh, (F + 2R + (n - 3)P) / n)
7269
end
@@ -81,13 +78,15 @@ function refine(mesh, ::CatmullClark)
8178
∂₂₁ = Boundary{2,1}(t)
8279
newconnec = Connectivity{Quadrangle,4}[]
8380
for elem in 1:nelements(t)
84-
verts = CircularVector(∂₂₀(elem))
85-
edges = CircularVector(∂₂₁(elem))
86-
for i in 1:length(edges)
81+
verts = ∂₂₀(elem)
82+
edges = ∂₂₁(elem)
83+
nv = length(verts)
84+
ne = length(edges)
85+
for i in 1:ne
8786
u = elem + offset₁
88-
v = edges[i] + offset₂
89-
w = verts[i + 1]
90-
z = edges[i + 1] + offset₂
87+
v = edges[mod1(i, ne)] + offset₂
88+
w = verts[mod1(i + 1, nv)]
89+
z = edges[mod1(i + 1, ne)] + offset₂
9190
quad = connect((u, v, w, z))
9291
push!(newconnec, quad)
9392
end

src/refinement/quad.jl

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ function refine(mesh, ::QuadRefinement)
2121
# add centroids of elements
2222
∂₂₀ = Boundary{2,0}(t)
2323
epts = map(1:nelements(t)) do elem
24-
ps = view(points, ∂₂₀(elem))
25-
cₒ = sum(to, ps) / length(ps)
24+
is = ∂₂₀(elem)
25+
cₒ = sum(j -> to(points[j]), is) / length(is)
2626
withcrs(mesh, cₒ)
2727
end
2828

2929
# add midpoints of edges
3030
∂₁₀ = Boundary{1,0}(t)
3131
fpts = map(1:nfacets(t)) do edge
32-
ps = view(points, ∂₁₀(edge))
33-
cₒ = sum(to, ps) / length(ps)
32+
is = ∂₁₀(edge)
33+
cₒ = sum(i -> to(points[i]), is) / length(is)
3434
withcrs(mesh, cₒ)
3535
end
3636

@@ -47,13 +47,15 @@ function refine(mesh, ::QuadRefinement)
4747
∂₂₁ = Boundary{2,1}(t)
4848
newconnec = Connectivity{Quadrangle,4}[]
4949
for elem in 1:nelements(t)
50-
verts = CircularVector(∂₂₀(elem))
51-
edges = CircularVector(∂₂₁(elem))
52-
for i in 1:length(edges)
50+
verts = ∂₂₀(elem)
51+
edges = ∂₂₁(elem)
52+
nv = length(verts)
53+
ne = length(edges)
54+
for i in 1:ne
5355
u = elem + offset₁
54-
v = edges[i] + offset₂
55-
w = verts[i + 1]
56-
z = edges[i + 1] + offset₂
56+
v = edges[mod1(i, ne)] + offset₂
57+
w = verts[mod1(i + 1, nv)]
58+
z = edges[mod1(i + 1, ne)] + offset₂
5759
quad = connect((u, v, w, z))
5860
push!(newconnec, quad)
5961
end

src/refinement/tri.jl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ function refine(mesh, ::TriRefinement)
2424
# add centroids of elements
2525
∂₂₀ = Boundary{2,0}(t)
2626
epts = map(1:nelements(t)) do elem
27-
ps = view(points, ∂₂₀(elem))
28-
cₒ = sum(to, ps) / length(ps)
27+
is = ∂₂₀(elem)
28+
cₒ = sum(i -> to(points[i]), is) / length(is)
2929
withcrs(mesh, cₒ)
3030
end
3131

@@ -40,11 +40,12 @@ function refine(mesh, ::TriRefinement)
4040
# connect vertices into new triangles
4141
newconnec = Connectivity{Triangle,3}[]
4242
for elem in 1:nelements(t)
43-
verts = CircularVector(∂₂₀(elem))
44-
for i in 1:length(verts)
43+
verts = ∂₂₀(elem)
44+
nv = length(verts)
45+
for i in 1:nv
4546
u = elem + offset
46-
v = verts[i]
47-
w = verts[i + 1]
47+
v = verts[mod1(i, nv)]
48+
w = verts[mod1(i + 1, nv)]
4849
tri = connect((u, v, w))
4950
push!(newconnec, tri)
5051
end

src/refinement/trisubdivision.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ function refine(mesh, ::TriSubdivision)
3636
midpoints = Dict{Tuple{Int,Int},Int}()
3737
∂₁₀ = Boundary{1,0}(t)
3838
for eind in 1:nfacets(t)
39-
i, j = sort(∂₁₀(eind))
39+
i, j = ∂₁₀(eind)
4040
edge = Segment(points[i], points[j])
4141
push!(points, centroid(edge))
42-
midpoints[(i, j)] = (np += 1)
42+
midpoints[_ordered(i, j)] = (np += 1)
4343
end
4444

4545
# construct subtriangles of faces

src/topologies/grid.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,15 @@ nvertices(t::GridTopology) = prod(t.dims .+ t.open)
120120
function element(t::GridTopology{D}, ind) where {D}
121121
= Boundary{D,0}(t)
122122
T = elementtype(t)
123-
connect(Tuple((ind)), T)
123+
connect((ind), T)
124124
end
125125

126126
nelements(t::GridTopology) = prod(t.dims)
127127

128128
function facet(t::GridTopology{D}, ind) where {D}
129129
= Boundary{D - 1,0}(t)
130130
T = facettype(t)
131-
connect(Tuple((ind)), T)
131+
connect((ind), T)
132132
end
133133

134134
nfacets(t::GridTopology{1}) = t.dims[1] + t.open[1]

src/toporelations/adjacency.jl

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ function (𝒜::Adjacency{0,D,T})(ind::Integer) where {D,T<:GridTopology}
3434
# construct topology for vertices
3535
vtopo = GridTopology(dims .+ 1, cycl)
3636
𝒜vert = Adjacency{D}(vtopo)
37+
3738
𝒜vert(ind)
3839
end
3940

@@ -44,25 +45,25 @@ function (𝒜::Adjacency{D,D,T})(ind::Integer) where {D,T<:GridTopology}
4445
cycl = isperiodic(topo)
4546
cind = elem2cart(topo, ind)
4647

47-
# offsets along each dimension
48-
offsets = [ntuple(i -> i == d ? s : 0, D) for d in 1:D for s in (-1, 1)]
48+
inds = Int[]
49+
for d in 1:D, s in (-1, 1)
50+
# offset along each dimension
51+
offset = ntuple(i -> i == d ? s : 0, D)
4952

50-
ninds = NTuple{D,Int}[]
51-
for offset in offsets
5253
# apply offset to center index
5354
sind = cind .+ offset
5455

5556
# wrap indices in case of periodic dimension
56-
wrap(i) = mod1(sind[i], dims[i])
57-
wind = ntuple(i -> cycl[i] ? wrap(i) : sind[i], D)
57+
wind = ntuple(D) do i
58+
cycl[i] ? mod1(sind[i], dims[i]) : sind[i]
59+
end
5860

5961
# discard invalid indices
6062
valid(i) = 1 wind[i] dims[i]
61-
all(valid, 1:D) && push!(ninds, wind)
63+
all(valid, 1:D) && push!(inds, cart2elem(topo, wind...))
6264
end
6365

64-
# return linear index of element
65-
[cart2elem(topo, ind...) for ind in ninds]
66+
ntuple(i -> inds[i], length(inds))
6667
end
6768

6869
# -------------------
@@ -74,32 +75,32 @@ function (𝒜::Adjacency{0,2,T})(vert::Integer) where {T<:HalfEdgeTopology}
7475
e = half4vert(𝒜.topology, vert)
7576

7677
# initialize result
77-
vertices = [e.half.head]
78+
inds = [e.half.head]
7879

7980
# search in CCW orientation
8081
p = e.prev
8182
h = p.half
8283
while !isnothing(h.elem) && h != e
83-
push!(vertices, p.head)
84+
push!(inds, p.head)
8485
p = h.prev
8586
h = p.half
8687
end
8788

8889
# if border edge is hit
8990
if isnothing(h.elem)
9091
# add last arm manually
91-
push!(vertices, p.head)
92+
push!(inds, p.head)
9293

9394
# search in CW orientation
9495
h = e.half
9596
while !isnothing(h.elem)
9697
n = h.next
9798
h = n.half
98-
pushfirst!(vertices, h.head)
99+
pushfirst!(inds, h.head)
99100
end
100101
end
101102

102-
vertices
103+
ntuple(i -> inds[i], length(inds))
103104
end
104105

105106
# adjacent elements in a 2D half-edge topology
@@ -117,5 +118,5 @@ function (𝒜::Adjacency{2,2,T})(ind::Integer) where {T<:HalfEdgeTopology}
117118
n = n.next
118119
end
119120

120-
inds
121+
ntuple(i -> inds[i], length(inds))
121122
end

0 commit comments

Comments
 (0)