You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
hash_grid_query fails to find valid neighbors when query bounds or point coordinates are negative. The root cause is float-to-int conversion using C++ int() cast (truncation toward zero) instead of floor() (toward negative infinity) in the native HashGrid implementation.
Affected code
warp/native/hashgrid.h â three locations:
Point cell assignment (line 86): When building the grid, points with negative fractional cell coordinates are binned into the wrong cell.
Query lower bounds (lines 150-152): The start of the cell search range is computed incorrectly when it falls in negative space.
Query upper bounds (lines 155-157): Same issue for the end of the search range.
Root cause
C++ int() truncates toward zero, while floor() rounds toward negative infinity. They agree for positive values but diverge for negative fractions:
Value
int(value)
floor(value)
0.7
0
0
-0.3
0
-1
-1.5
-1
-2
For example, with cell_width = 1.0, a point at position -0.3 should be assigned to cell -1 but int(-0.3) = 0 places it in cell 0. Similarly, a query centered at +0.2 with radius 0.6 has a lower bound of -0.4, which should search cell -1 but int(-0.4) = 0 skips it entirely.
The downstream hash_grid_index(grid, x, y, z) function correctly handles negative integer cell indices via a large offset and modulo wrapping â the bug is purely in the upstream float-to-int conversion that feeds it.
Impact
Neighbor queries that cross the zero boundary in any axis silently miss valid neighbors (false negatives).
Points with negative fractional coordinates are assigned to the wrong grid cell during build(), making them invisible to queries searching the correct cell.
Affects any simulation using negative coordinate space or relying on HashGrid's toroidal wrapping (e.g., periodic boundary conditions in example_particle_repulsion.py).
All precision types (fp16, fp32, fp64) are affected.
Fix
Replace int(expr) with int(floor(Type(expr))) at all three locations. This matches the pattern used by other Warp native code (noise.h, volume.h, texture.h) which correctly applies floor() before integer conversion.
Clarification on when this bug causes missed neighbors:
The issue correctly identifies the root cause (int() truncating toward zero instead of floor() rounding toward negative infinity), but the impact is more nuanced than described.
Because both point insertion (hash_grid_index) and query range computation (hash_grid_query) use the same int() truncation, there is a cancellation effect: points are stored in the "wrong" cell, but queries also search the "wrong" cells in the same way. For large grids, this means neighbors are still found despite incorrect cell assignment.
The cancellation breaks down when grid wrapping is involved. The int() truncation shifts negative fractional cell indices by +1 toward zero, but positive indices are unaffected. After the grid's modulo operation (% dim), this asymmetric shift can map to a completely different physical bucket. For example, with grid_dim=4 and cell_width=1.0:
Point at -0.3: int(-0.3) = 0 â physical cell 0. But floor(-0.3) = -1 â physical cell 3.
Point at 3.9: cell 3 in both cases (positive, no disagreement).
These two points are periodic neighbors (distance 0.2 in a domain of size 4), but the bug places them in different physical cells (0 vs 3). The query from -0.3 only searches cell 0 and misses the point at 3.9.
In practice, this primarily affects:
Simulations with periodic boundary conditions and small grid dimensions relative to the coordinate range
Any scenario where the +1 cell shift from int() wraps to a different physical bucket than floor() would produce
Purely positive coordinates are unaffected since int() and floor() agree for non-negative values.
Activity
Fix HashGrid truncation error with negative coordinates
shi-eric commentedon Mar 11, 2026
Clarification on when this bug causes missed neighbors:
The issue correctly identifies the root cause (
int()truncating toward zero instead offloor()rounding toward negative infinity), but the impact is more nuanced than described.Because both point insertion (
hash_grid_index) and query range computation (hash_grid_query) use the sameint()truncation, there is a cancellation effect: points are stored in the "wrong" cell, but queries also search the "wrong" cells in the same way. For large grids, this means neighbors are still found despite incorrect cell assignment.The cancellation breaks down when grid wrapping is involved. The
int()truncation shifts negative fractional cell indices by +1 toward zero, but positive indices are unaffected. After the grid's modulo operation (% dim), this asymmetric shift can map to a completely different physical bucket. For example, withgrid_dim=4andcell_width=1.0:int(-0.3) = 0â physical cell 0. Butfloor(-0.3) = -1â physical cell 3.These two points are periodic neighbors (distance 0.2 in a domain of size 4), but the bug places them in different physical cells (0 vs 3). The query from -0.3 only searches cell 0 and misses the point at 3.9.
In practice, this primarily affects:
int()wraps to a different physical bucket thanfloor()would producePurely positive coordinates are unaffected since
int()andfloor()agree for non-negative values.Fix HashGrid truncation for negative coordinates (NVIDIAGH-1256)
Merge branch 'zcorse/hashgrid_truncation_fix' into 'main'
Fix HashGrid truncation error with negative coordinates
shi-eric commentedon Mar 16, 2026
This was addressed in e0ec2d0