Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster Dual Mesh Generation #71

Merged
merged 30 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c38c664
Played around with dual mesh generation
GeorgeR227 Feb 23, 2024
6d1ee68
Further improvements to subdivision code
GeorgeR227 Feb 23, 2024
625fe44
Using MVector to save memory costs
GeorgeR227 Feb 24, 2024
5a92870
Started work on make_dual_simplices_1d!
GeorgeR227 Feb 26, 2024
9f5664a
Further tweaks to 1D
GeorgeR227 Feb 27, 2024
dcce18f
Improvements to dual simplices 2D
GeorgeR227 Feb 28, 2024
c66bd64
Added faster dual mesh generation to tests
GeorgeR227 Feb 29, 2024
60640a6
Some final changes
GeorgeR227 Mar 1, 2024
7ae7b8d
Merge branch 'main' into gr/fast-mesh
GeorgeR227 Mar 1, 2024
0dd4a97
Remove personal testing file
GeorgeR227 Mar 1, 2024
59e86f3
Cleaned up the point_wrapper
GeorgeR227 Mar 4, 2024
06c5f05
Replaced copy_parts!
GeorgeR227 Mar 5, 2024
42dabec
Added primal_triangle test mesh
GeorgeR227 May 14, 2024
e267b10
Added fin mesh
GeorgeR227 May 14, 2024
ab1ea66
Revert "Added fin mesh"
GeorgeR227 May 14, 2024
4772a25
Clean up new tests
GeorgeR227 May 15, 2024
e55db29
Added initial dual mesh benchmarks
GeorgeR227 May 15, 2024
7dd038b
Moved FastMesh into seperate file
GeorgeR227 May 15, 2024
3a9467e
Added @inbounds to for loops
GeorgeR227 May 15, 2024
ca0d52d
Set dual volumes with SVector
lukem12345 May 23, 2024
a981727
Update subdivisions to use ACSets interface
GeorgeR227 May 23, 2024
9759b7e
Moved point inference higher
GeorgeR227 May 23, 2024
98786da
Integrated fast code into original
GeorgeR227 May 23, 2024
22496e7
Merge branch 'main' into gr/fast-mesh
GeorgeR227 May 23, 2024
b2b368e
Replace copy_parts!
GeorgeR227 May 24, 2024
8a79927
Remove FastMesh code
GeorgeR227 May 24, 2024
cb28c99
Updated to use built-in functionality
GeorgeR227 May 24, 2024
e6a9a63
Removed mesh array
GeorgeR227 May 28, 2024
09ff6d6
Revert "Removed mesh array"
GeorgeR227 May 28, 2024
8e480ea
Cleaned benchmarks some more
GeorgeR227 May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 178 additions & 39 deletions src/DiscreteExteriorCalculus.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Base: *
import LinearAlgebra: mul!
using LinearAlgebra: Diagonal, dot, norm, cross, pinv, qr, ColumnNorm
using SparseArrays
using StaticArrays: @SVector, SVector, SMatrix, MMatrix
using StaticArrays: @SVector, SVector, SMatrix, MVector, MMatrix
using GeometryBasics: Point2, Point3

const Point2D = SVector{2,Float64}
Expand Down Expand Up @@ -233,11 +233,37 @@ negatenz((I, V)) = (I, negate.(V))

""" Construct 1D dual complex from 1D delta set.
"""
function (::Type{S})(t::AbstractDeltaSet1D) where S <: AbstractDeltaDualComplex1D
s = S()
copy_parts!(s, t)
make_dual_simplices_1d!(s)
return s
function (::Type{S})(s::AbstractDeltaSet1D) where S <: AbstractDeltaDualComplex1D
t = S()
copy_primal_1D!(t, s) # TODO: Revert to copy_parts! when performance is improved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an issue to ACSets.jl that you are having to circumvent copy_parts!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll get one out once I've looked into the issue some more. I'm guessing this again stems from vectorized getting/setting plus other underlying issues.

make_dual_simplices_1d!(t)
return t
end

function copy_primal_1D!(t::HasDeltaSet1D, s::HasDeltaSet1D)

@assert nv(t) == 0
@assert ne(t) == 0

v_range = add_parts!(t, :V, nv(s))
e_range = add_parts!(t, :E, ne(s))

if has_subpart(s, :point)
@inbounds for v in v_range
t[v, :point] = s[v, :point]
end
end

@inbounds for e in e_range
t[e, :∂v0] = s[e, :∂v0]
t[e, :∂v1] = s[e, :∂v1]
end

if has_subpart(s, :edge_orientation)
@inbounds for e in e_range
t[e, :edge_orientation] = s[e, :edge_orientation]
end
end
end

make_dual_simplices_1d!(s::AbstractDeltaDualComplex1D) = make_dual_simplices_1d!(s, E)
Expand Down Expand Up @@ -364,30 +390,71 @@ Supports different methods of subdivision through the choice of geometric
center, as defined by [`geometric_center`](@ref). In particular, barycentric
subdivision and circumcentric subdivision are supported.
"""
function subdivide_duals!(s::EmbeddedDeltaDualComplex1D, args...)
subdivide_duals_1d!(s, args...)
precompute_volumes_1d!(s)
function subdivide_duals!(sd::EmbeddedDeltaDualComplex1D{_o, _l, point_type} where {_o, _l}, alg) where point_type
subdivide_duals_1d!(sd, point_type, alg)
precompute_volumes_1d!(sd, point_type)
end

function subdivide_duals_1d!(s::HasDeltaSet1D, alg)
for v in vertices(s)
s[vertex_center(s,v), :dual_point] = point(s, v)
# TODO: Write helpers for getting the correct mesh data
GeorgeR227 marked this conversation as resolved.
Show resolved Hide resolved
function subdivide_duals_1d!(sd::HasDeltaSet1D, ::Type{point_type}, alg) where point_type

point_arr = MVector{2, point_type}(undef)

@inbounds for v in vertices(sd)
sd[v, :dual_point] = sd[v, :point]
end
for e in edges(s)
s[edge_center(s,e), :dual_point] = geometric_center(
point(s, edge_vertices(s, e)), alg)

@inbounds for e in edges(sd)
point_arr[1] = sd[sd[e, :∂v0], :point]
GeorgeR227 marked this conversation as resolved.
Show resolved Hide resolved
point_arr[2] = sd[sd[e, :∂v1], :point]

sd[sd[e, :edge_center], :dual_point] = geometric_center(point_arr, alg)
end
end

function precompute_volumes_1d!(s::HasDeltaSet1D)
for e in edges(s)
s[e, :length] = volume(1,s,e,CayleyMengerDet())
function precompute_volumes_1d!(sd::HasDeltaSet1D, ::Type{point_type}) where point_type

point_arr = MVector{2, point_type}(undef)

@inbounds for e in edges(sd)
point_arr[1] = sd[sd[e, :∂v0], :point]
point_arr[2] = sd[sd[e, :∂v1], :point]

sd[e, :length] = volume(point_arr)
end
for e in parts(s, :DualE)
s[e, :dual_length] = dual_volume(1,s,e,CayleyMengerDet())

@inbounds for e in parts(sd, :DualE)
point_arr[1] = sd[sd[e, :D_∂v0], :dual_point]
point_arr[2] = sd[sd[e, :D_∂v1], :dual_point]

sd[e, :dual_length] = volume(point_arr)
end
end

# function subdivide_duals!(s::EmbeddedDeltaDualComplex1D, args...)
GeorgeR227 marked this conversation as resolved.
Show resolved Hide resolved
# subdivide_duals_1d!(s, args...)
# precompute_volumes_1d!(s)
# end

# function subdivide_duals_1d!(s::HasDeltaSet1D, alg)
# for v in vertices(s)
# s[vertex_center(s,v), :dual_point] = point(s, v)
# end
# for e in edges(s)
# s[edge_center(s,e), :dual_point] = geometric_center(
# point(s, edge_vertices(s, e)), alg)
# end
# end

# function precompute_volumes_1d!(s::HasDeltaSet1D)
# for e in edges(s)
# s[e, :length] = volume(1,s,e,CayleyMengerDet())
# end
# for e in parts(s, :DualE)
# s[e, :dual_length] = dual_volume(1,s,e,CayleyMengerDet())
# end
# end

# TODO: When Catlab PR #823 "Data migrations with Julia functions on attributes"
# is merged, encode subdivision like so:
#function subdivide(s::EmbeddedDeltaSet1D{T,U}, alg::V) where {T,U,V <: SimplexCenter}
Expand Down Expand Up @@ -481,11 +548,31 @@ dual_derivative_nz(::Type{Val{1}}, s::AbstractDeltaDualComplex2D, x::Int) =

""" Construct 2D dual complex from 2D delta set.
"""
function (::Type{S})(t::AbstractDeltaSet2D) where S <: AbstractDeltaDualComplex2D
s = S()
copy_parts!(s, t)
make_dual_simplices_2d!(s)
return s
function (::Type{S})(s::AbstractDeltaSet2D) where S <: AbstractDeltaDualComplex2D
t = S()
copy_primal_2D!(t, s) # TODO: Revert to copy_parts! when performance is improved
make_dual_simplices_2d!(t)
return t
end

function copy_primal_2D!(t::HasDeltaSet2D, s::HasDeltaSet2D)

@assert ntriangles(t) == 0

copy_primal_1D!(t, s)
tri_range = add_parts!(t, :Tri, ntriangles(s))

@inbounds for tri in tri_range
t[tri, :∂e0] = s[tri, :∂e0]
t[tri, :∂e1] = s[tri, :∂e1]
t[tri, :∂e2] = s[tri, :∂e2]
end

if has_subpart(s, :tri_orientation)
@inbounds for tri in tri_range
t[tri, :tri_orientation] = s[tri, :tri_orientation]
end
end
end

make_dual_simplices_1d!(s::AbstractDeltaDualComplex2D) = make_dual_simplices_1d!(s, Tri)
Expand Down Expand Up @@ -832,29 +919,81 @@ function ∧(::Type{Tuple{1,1}}, s::HasDeltaSet2D, α, β, x::Int)
α[e1] * β[e0] - α[e0] * β[e1])) / 2
end

function subdivide_duals!(s::EmbeddedDeltaDualComplex2D, args...)
subdivide_duals_2d!(s, args...)
precompute_volumes_2d!(s)
# TODO: Write helpers for getting the correct mesh data
function subdivide_duals!(sd::EmbeddedDeltaDualComplex2D{_o, _l, point_type} where {_o, _l}, alg) where point_type
subdivide_duals_2d!(sd, point_type, alg)
precompute_volumes_2d!(sd, point_type)
end

function subdivide_duals_2d!(s::HasDeltaSet2D, alg)
subdivide_duals_1d!(s, alg)
for t in triangles(s)
s[triangle_center(s,t), :dual_point] = geometric_center(
point(s, triangle_vertices(s, t)), alg)
function subdivide_duals_2d!(sd::HasDeltaSet2D, ::Type{point_type}, alg) where point_type
subdivide_duals_1d!(sd, point_type, alg)

point_arr = MVector{3, point_type}(undef)

@inbounds for t in triangles(sd)
point_arr[1] = sd[sd[sd[t, :∂e1], :∂v1], :point]
point_arr[2] = sd[sd[sd[t, :∂e2], :∂v0], :point]
point_arr[3] = sd[sd[sd[t, :∂e1], :∂v0], :point]

sd[sd[t, :tri_center], :dual_point] = geometric_center(point_arr, alg)
end
end

function precompute_volumes_2d!(s::HasDeltaSet2D)
precompute_volumes_1d!(s)
for t in triangles(s)
s[t, :area] = volume(2,s,t,CayleyMengerDet())
function precompute_volumes_2d!(sd::HasDeltaSet2D, p::Type{point_type}) where point_type
precompute_volumes_1d!(sd, point_type)
set_volumes_2d!(Val{2}, sd, p)
set_dual_volumes_2d!(Val{2}, sd, p)
end

function set_volumes_2d!(::Type{Val{2}}, sd::HasDeltaSet2D, ::Type{point_type}) where point_type

point_arr = MVector{3, point_type}(undef)

@inbounds for t in triangles(sd)
point_arr[1] = sd[sd[sd[t, :∂e1], :∂v1], :point]
point_arr[2] = sd[sd[sd[t, :∂e2], :∂v0], :point]
point_arr[3] = sd[sd[sd[t, :∂e1], :∂v0], :point]

sd[t, :area] = volume(point_arr)
end
for t in parts(s, :DualTri)
s[t, :dual_area] = dual_volume(2,s,t,CayleyMengerDet())
end

function set_dual_volumes_2d!(::Type{Val{2}}, sd::HasDeltaSet2D, ::Type{point_type}) where point_type

point_arr = MVector{3, point_type}(undef)

@inbounds for t in parts(sd, :DualTri)
point_arr[1] = sd[sd[sd[t, :D_∂e1], :D_∂v1], :dual_point]
point_arr[2] = sd[sd[sd[t, :D_∂e2], :D_∂v0], :dual_point]
point_arr[3] = sd[sd[sd[t, :D_∂e0], :D_∂v0], :dual_point]

sd[t, :dual_area] = volume(point_arr)
end
end

# function subdivide_duals!(s::EmbeddedDeltaDualComplex2D, args...)
GeorgeR227 marked this conversation as resolved.
Show resolved Hide resolved
# subdivide_duals_2d!(s, args...)
# precompute_volumes_2d!(s)
# end

# function subdivide_duals_2d!(s::HasDeltaSet2D, alg)
# subdivide_duals_1d!(s, alg)
# for t in triangles(s)
# s[triangle_center(s,t), :dual_point] = geometric_center(
# point(s, triangle_vertices(s, t)), alg)
# end
# end

# function precompute_volumes_2d!(s::HasDeltaSet2D)
# precompute_volumes_1d!(s)
# for t in triangles(s)
# s[t, :area] = volume(2,s,t,CayleyMengerDet())
# end
# for t in parts(s, :DualTri)
# s[t, :dual_area] = dual_volume(2,s,t,CayleyMengerDet())
# end
# end

# General operators
###################

Expand Down
Loading
Loading