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

POC: NHS only include intersecting faces #699

Draft
wants to merge 363 commits into
base: main
Choose a base branch
from

Conversation

LasNikas
Copy link
Collaborator

As discussed with @efaulhaber, there's no real improvement in checking whether a face intersects a cell in the face-embedding cell grid. However, this PR is used to store the methods.

To show that it doesn't really improve performance, here's a quick showcase. In both cases, 2D and 3D, all the faces are almost the same size.

3D (geometry with ca. 25k faces)

julia> analyze_face_surplus_in_nhs(geometry, ratios)
10.51 % when face is ca. 4.0 times the search radius
mean_face_size  0.211, search_radius  0.05

3.14 % when face is ca. 2.0 times the search radius
mean_face_size  0.211, search_radius  0.11

0.73 % when face is ca. 1.0 times the search radius
mean_face_size  0.211, search_radius  0.21

0.28 % when face is ca. 0.67 times the search radius
mean_face_size  0.211, search_radius  0.32

0.12 % when face is ca. 0.5 times the search radius
mean_face_size  0.211, search_radius  0.42

0.05 % when face is ca. 0.33 times the search radius
mean_face_size  0.211, search_radius  0.63

2D (geometry with ca. 63 edges)

julia> analyze_face_surplus_in_nhs(geometry, ratios)
17.7 % when face is ca. 4.0 times the search radius
mean_face_size  0.1, search_radius  0.02

7.67 % when face is ca. 2.0 times the search radius
mean_face_size  0.1, search_radius  0.05

2.96 % when face is ca. 1.0 times the search radius
mean_face_size  0.1, search_radius  0.1

1.09 % when face is ca. 0.67 times the search radius
mean_face_size  0.1, search_radius  0.15

1.27 % when face is ca. 0.5 times the search radius
mean_face_size  0.1, search_radius  0.2

0.0 % when face is ca. 0.33 times the search radius
mean_face_size  0.1, search_radius  0.3
julia> particle_spacing = 0.01
0.01

julia> @benchmark SignedDistanceField($geometry, $particle_spacing; always_true=$true)
BenchmarkTools.Trial: 4602 samples with 1 evaluation.
 Range (min  max):  790.334 μs    7.876 ms  ┊ GC (min  max):  0.00%  86.66%
 Time  (median):     979.104 μs               ┊ GC (median):     0.00%
 Time  (mean ± σ):     1.086 ms ± 639.109 μs  ┊ GC (mean ± σ):  10.07% ± 13.43%

   ▄██▂                                                         ▁
  █████▆▆▃▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▁▃▃▄▃▃▃▃▄▄▅▃▆▆▅▄▅▄▆▅▅▁▃▆▄▅▅▆▃▅▅ █
  790 μs        Histogram: log(frequency) by time       4.77 ms <

 Memory estimate: 2.68 MiB, allocs estimate: 2892.

julia> @benchmark SignedDistanceField($geometry, $particle_spacing; always_true=$false)
BenchmarkTools.Trial: 5184 samples with 1 evaluation.
 Range (min  max):  702.583 μs    9.633 ms  ┊ GC (min  max):  0.00%  89.30%
 Time  (median):     863.395 μs               ┊ GC (median):     0.00%
 Time  (mean ± σ):   963.647 μs ± 615.840 μs  ┊ GC (mean ± σ):  10.48% ± 13.39%

  ▁▄█▆▁                                                         ▁
  █████▆▆▅▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃▁▁▁▁▃▅▁▄▄▅▄▄▄▃▄▅▄▅▅▅▅▄▄▅▅▄▅▄▅▄▄▁▄▅▅ █
  703 μs        Histogram: log(frequency) by time       4.43 ms <

 Memory estimate: 2.60 MiB, allocs estimate: 2457.

function bbox_size(face, geometry::TrixiParticles.TriangleMesh)
    min_corner = minimum(stack(geometry.face_vertices[face]), dims=2)
    max_corner = maximum(stack(geometry.face_vertices[face]), dims=2)

    return max_corner .- min_corner
end

function bbox_size(edge, geometry::TrixiParticles.Polygon)
    min_corner = minimum(stack(geometry.edge_vertices[edge]), dims=2)
    max_corner = maximum(stack(geometry.edge_vertices[edge]), dims=2)

    return max_corner .- min_corner
end


function analyze_face_surplus_in_nhs(geometry, ratios)
    mean_face_size = 0.0
    for face in TrixiParticles.eachface(geometry)
        face_size = bbox_size(face, geometry)
        mean_face_size += TrixiParticles.norm(face_size)
    end

    mean_face_size /= TrixiParticles.nfaces(geometry)

    for search_radius_to_face_size in ratios

        particle_spacing = mean_face_size * search_radius_to_face_size
        search_radius = mean_face_size * search_radius_to_face_size

        nhs = TrixiParticles.FaceNeighborhoodSearch{ndims(geometry)}(; search_radius)
        TrixiParticles.initialize!(nhs, geometry; always_true=true)

        nfaces_always_true = sum(keys(nhs.neighbors.hashtable)) do key
            length(nhs.neighbors[key])
        end


        nhs = TrixiParticles.FaceNeighborhoodSearch{ndims(geometry)}(; search_radius)
        TrixiParticles.initialize!(nhs, geometry; always_true=false)

        nfaces_not_always_true = sum(keys(nhs.neighbors.hashtable)) do key
            length(nhs.neighbors[key])
        end

        ratio = (nfaces_always_true - nfaces_not_always_true) / nfaces_always_true * 100

        println("$(round(ratio, digits=2)) % when face is ca. $(round(1/search_radius_to_face_size, digits=2)) times the search radius")
        println("mean_face_size ≈ $(round(mean_face_size, digits=3)), search_radius ≈ $(round(search_radius, digits=2))")
        println("")

    end
end

@LasNikas LasNikas mentioned this pull request Jan 14, 2025
Comment on lines +41 to +49
# Check if any face intersects a cell in the face-embedding cell grid
for cell in bounding_box(face, geometry, neighborhood_search)
cond = always_true ? true : face_intersects_cell(face, geometry, Tuple(cell), neighborhood_search)

if cond
PointNeighbors.push_cell!(cell_list, Tuple(cell), face)
end
end
end
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the relevant part in this PR

Copy link
Member

Choose a reason for hiding this comment

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

You can rebase on main once #529 is merged to clean up this PR and reduce it to this relevant part.

@efaulhaber
Copy link
Member

In our discussion, we also noted that plane_intersects_cell only checks if the plane of the triangle intersects the cell, not if the cell lies inside the triangle or outside, so there are always some unnecessary extra cells that are not filtered out correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants