-
Notifications
You must be signed in to change notification settings - Fork 9
Spatial Hashing #101
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
Merged
efaulhaber
merged 34 commits into
trixi-framework:main
from
RubberLanding:SpatialHashing
May 15, 2025
Merged
Spatial Hashing #101
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
e0c9719
Added test file for Spatial Hashing.
RubberLanding 2258679
Minor changes.
RubberLanding 4b57a71
Spatial Hashing works with initialize!() and empty!().
RubberLanding ac4d23f
Minor changes.
RubberLanding c238407
Working version for collision handling.
RubberLanding c798f6f
Simple test for collisions with spatial hashing and foreach_neighbor().
RubberLanding 614e68e
Add update!() for neighborhood_search tests.
RubberLanding f6b2b12
Running version for collision handling. Implement changes in spatial_…
RubberLanding 0088c8a
Merge branch 'main' into SpatialHashing
RubberLanding c53ca75
Fixed collision handling with empty cells. Clean up the code.
RubberLanding f4fa219
Merge different tests for spatial hashing together.
RubberLanding 58ae772
Merge branch 'SpatialHashing' of https://github.com/RubberLanding/Poi…
RubberLanding ca1054b
Clean up.
RubberLanding 260850c
Add documentation.
RubberLanding d79dc25
Clean up.
RubberLanding 4b96172
Update test for spatial hashing, add test for empty list.
RubberLanding ed74323
Add copy_cell_list() for spatial hashing.
RubberLanding 41bb871
Update check_collision(), the tests are succeeding.
RubberLanding 00822eb
Clean up.
RubberLanding 81c640c
Clean up.
RubberLanding 7005b85
Merge branch 'main' into SpatialHashing
RubberLanding 48f9651
Fix code in foreach_neighbor after merge.
RubberLanding 0b2d723
Resolve requested changes:
RubberLanding ec91efa
Merge branch 'main' into SpatialHashing
RubberLanding 9d15adb
Resolve requested changes:
RubberLanding 3a481f5
Minor changes.
RubberLanding 33f44cf
Resolve requested changes.
RubberLanding 81be3fc
Merge branch 'main' into SpatialHashing
RubberLanding f9f0ebb
Merge branch 'main' into SpatialHashing
svchb 44fab7f
Resolve requested change for docs for SpatialHashingCellList.
RubberLanding a3f622d
Change citation of Ihmsen in doc for SpatialHashingCellList.
RubberLanding f718f2b
Merge branch 'main' into SpatialHashing
RubberLanding 8036f47
Fix formatting.
RubberLanding 7ce370c
Fix formatting.
RubberLanding File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,4 +22,4 @@ LinearAlgebra = "1" | |
| Polyester = "0.7.5" | ||
| Reexport = "1" | ||
| StaticArrays = "1" | ||
| julia = "1.10" | ||
| julia = "1.10" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,3 +6,4 @@ abstract type AbstractCellList end | |
|
|
||
| include("dictionary.jl") | ||
| include("full_grid.jl") | ||
| include("spatial_hashing.jl") | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| """ | ||
| SpatialHashingCellList{NDIMS}(; list_size) | ||
|
|
||
| A basic spatial hashing implementation. Similar to [`DictionaryCellList`](@ref), the domain is discretized into cells, | ||
| and the particles in each cell are stored in a hash map. The hash is computed using the spatial location of each cell, | ||
| as described by Ihmsen et al. (2011)(@cite Ihmsen2011). By using a hash map that stores entries only for non-empty cells, | ||
| the domain is effectively infinite. The size of the hash map is recommended to be approximately twice the number of particles | ||
| to balance memory consumption against the likelihood of hash collisions. | ||
|
|
||
| # Arguments | ||
| - `NDIMS::Int`: Number of spatial dimensions (e.g., `2` or `3`). | ||
| - `list_size::Int`: Size of the hash map (e.g., `2 * n_points`) . | ||
| """ | ||
|
|
||
| struct SpatialHashingCellList{NDIMS, CL, CI, CF} <: AbstractCellList | ||
| points :: CL | ||
| coords :: CI | ||
| collisions :: CF | ||
| list_size :: Int | ||
| end | ||
|
|
||
| @inline index_type(::SpatialHashingCellList) = Int32 | ||
|
|
||
| @inline Base.ndims(::SpatialHashingCellList{NDIMS}) where {NDIMS} = NDIMS | ||
|
|
||
| function supported_update_strategies(::SpatialHashingCellList) | ||
| return (SerialUpdate,) | ||
| end | ||
|
|
||
| function SpatialHashingCellList{NDIMS}(list_size) where {NDIMS} | ||
| points = [Int[] for _ in 1:list_size] | ||
| collisions = [false for _ in 1:list_size] | ||
| coords = [ntuple(_ -> typemin(Int), NDIMS) for _ in 1:list_size] | ||
| return SpatialHashingCellList{NDIMS, typeof(points), typeof(coords), | ||
| typeof(collisions)}(points, coords, collisions, list_size) | ||
| end | ||
|
|
||
| function Base.empty!(cell_list::SpatialHashingCellList) | ||
| (; list_size) = cell_list | ||
| NDIMS = ndims(cell_list) | ||
|
|
||
| Base.empty!.(cell_list.points) | ||
| cell_list.coords .= [ntuple(_ -> typemin(Int), NDIMS) for _ in 1:list_size] | ||
| cell_list.collisions .= false | ||
| return cell_list | ||
| end | ||
|
|
||
| # For each entry in the hash table, store the coordinates of the cell of the first point being inserted at this entry. | ||
| # If a point with a different cell coordinate is being added, we have found a collision. | ||
| function push_cell!(cell_list::SpatialHashingCellList, cell, point) | ||
| (; points, coords, collisions, list_size) = cell_list | ||
| NDIMS = ndims(cell_list) | ||
| hash_key = spatial_hash(cell, list_size) | ||
| push!(points[hash_key], point) | ||
|
|
||
| cell_coord = coords[hash_key] | ||
| if cell_coord == ntuple(_ -> typemin(Int), NDIMS) | ||
| # If this cell is not used yet, set cell coordinates | ||
| coords[hash_key] = cell | ||
| elseif cell_coord != cell | ||
| # If it is already used by a different cell, mark as collision | ||
| collisions[hash_key] = true | ||
| end | ||
| end | ||
|
|
||
| function deleteat_cell!(cell_list::SpatialHashingCellList, cell, i) | ||
| deleteat!(cell_list[cell], i) | ||
| end | ||
|
|
||
| @inline each_cell_index(cell_list::SpatialHashingCellList) = eachindex(cell_list.points) | ||
|
|
||
| function copy_cell_list(cell_list::SpatialHashingCellList, search_radius, | ||
| periodic_box) | ||
| (; list_size) = cell_list | ||
| NDIMS = ndims(cell_list) | ||
|
|
||
| return SpatialHashingCellList{NDIMS}(list_size) | ||
| end | ||
|
|
||
| @inline function Base.getindex(cell_list::SpatialHashingCellList, cell::Tuple) | ||
| return cell_list.points[spatial_hash(cell, length(cell_list.points))] | ||
| end | ||
|
|
||
| @inline function Base.getindex(cell_list::SpatialHashingCellList, i::Integer) | ||
| return cell_list.points[i] | ||
| end | ||
|
|
||
| @inline function is_correct_cell(cell_list::SpatialHashingCellList{<:Any, Nothing}, | ||
| coords, cell_index::Array) | ||
| return coords == cell_index | ||
| end | ||
|
|
||
| # Hash functions according to Ihmsen et al. (2001) | ||
| function spatial_hash(cell::NTuple{1, Real}, list_size) | ||
|
RubberLanding marked this conversation as resolved.
|
||
| return mod(cell[1] * 73856093, list_size) + 1 | ||
| end | ||
|
|
||
| function spatial_hash(cell::NTuple{2, Real}, list_size) | ||
| i, j = cell | ||
|
|
||
| return mod(xor(i * 73856093, j * 19349663), list_size) + 1 | ||
| end | ||
|
|
||
| function spatial_hash(cell::NTuple{3, Real}, list_size) | ||
| i, j, k = cell | ||
|
|
||
| return mod(xor(i * 73856093, j * 19349663, k * 83492791), list_size) + 1 | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| @testset verbose=true "SpatialHashingCellList" begin | ||
| @testset "Collision Handling With Empty Cells" begin | ||
| # The point is in cell (-1, 0) which has a hash collision with cell (-2, -1) | ||
| coordinates = [-0.05; 0.05;;] | ||
| NDIMS = size(coordinates, 1) | ||
| n_points = size(coordinates, 2) | ||
| search_radius = 0.1 + 10 * eps() | ||
| point_index = 1 | ||
|
|
||
| nhs = GridNeighborhoodSearch{2}(; search_radius, n_points, | ||
| cell_list = SpatialHashingCellList{NDIMS}(n_points)) | ||
| initialize_grid!(nhs, coordinates) | ||
|
|
||
| @testset "Test For Collision" begin | ||
| cell1 = (-1, 0) | ||
| cell2 = (-2, -1) | ||
| cell1_hash = PointNeighbors.spatial_hash(cell1, n_points) | ||
| cell2_hash = PointNeighbors.spatial_hash(cell2, n_points) | ||
|
RubberLanding marked this conversation as resolved.
|
||
| points1 = nhs.cell_list[cell1] | ||
| points2 = nhs.cell_list[cell2] | ||
|
|
||
| @test points1 == points2 == [1] | ||
| @test cell1_hash == cell2_hash | ||
| end | ||
|
|
||
| neighbors = Int[] | ||
| foreach_neighbor(coordinates, coordinates, nhs, | ||
| point_index) do point, neighbor, pos_diff, distance | ||
| push!(neighbors, neighbor) | ||
| end | ||
|
|
||
| @test neighbors == [1] | ||
| end | ||
|
|
||
| @testset "Collision Handling With Non-Empty Cells" begin | ||
| # Cell (-1, 0) with point 1 has a hash collision with cell (-2, -1) with point 2 | ||
| coordinates = [[-0.05 -0.15]; [0.05 -0.05]] | ||
| NDIMS = size(coordinates, 1) | ||
| n_points = size(coordinates, 2) | ||
| search_radius = 0.1 + 10 * eps() | ||
| point_index = 1 | ||
|
|
||
| nhs = GridNeighborhoodSearch{2}(; search_radius, n_points, | ||
| cell_list = SpatialHashingCellList{NDIMS}(n_points)) | ||
| initialize_grid!(nhs, coordinates) | ||
|
|
||
|
RubberLanding marked this conversation as resolved.
|
||
| @testset "Test For Collision" begin | ||
| cell1 = (-1, 0) | ||
| cell2 = (-2, -1) | ||
| cell1_hash = PointNeighbors.spatial_hash(cell1, n_points) | ||
| cell2_hash = PointNeighbors.spatial_hash(cell2, n_points) | ||
|
RubberLanding marked this conversation as resolved.
|
||
| points1 = nhs.cell_list[cell1] | ||
| points2 = nhs.cell_list[cell2] | ||
|
|
||
| @test points1 == points2 == [1, 2] | ||
| @test cell1_hash == cell2_hash | ||
| end | ||
|
|
||
| neighbors = [Int[] for _ in axes(coordinates, 2)] | ||
| foreach_point_neighbor(coordinates, coordinates, nhs, | ||
| points = axes(coordinates, 2)) do point, neighbor, pos_diff, | ||
| distance | ||
| push!(neighbors[point], neighbor) | ||
| end | ||
|
|
||
| @test neighbors[1] == [1] | ||
| @test neighbors[2] == [2] | ||
| end | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.