Help with atomic/reduction problem

0 views
Skip to first unread message

Chris Uchytil

unread,
May 20, 2017, 3:04:10 AM5/20/17
to Numba Public Discussion - Public
I am writing a kernel that can take a grid of data and generate a smaller grid to better encapsulate said data. The grid contains signed distance field information, where negative values indicate being within an object and positive values indicate being outside the object. The naive approach to this is to search the function space in the x, y, and z directions to find the min/max value in each dimension as the bounds for the cube. This would amount to checking every grid value and taking the min/max thread values that evaluate to a negative number in your signed distance grid. The problem with this is that the data can be interpolated and the boundary of the object (when the function evaluates to 0) might not lay exactly on the given grid. Because of this, not only are the min/max values needed for each dimension but the function values are needed at each of these min/max points as well. An example might be that a 128 cubed grid of data can shrink to 64 cubed but the actual boundary values evaluate to -0.3 (and the values on the next space over would be 0.7 because the gradient is 1 in a signed distance field) so the actual distance is 0.3 further out then you calculated thus cutting of the surface. I currently have a kernel where each block of shared memory can go through and find the local min/max x,y,z coordinates (so 6 xyz coords in total) but the issue arises when I need to reduce this to a global min/max xyz value in each direction. With atomic min/max I can find the global min/max values but atomic min/max only lets you compare a single number so I loose the other to dimension values associated with this min/max value preventing me from evaluating the signed distance grid value. When I try to find, as an example, the global x min/max I don't know which block contains the lowest/largest x value so I don't know how to extract the associated y and z values along with the min/max x value.

Another way of saying this is if I find the min in the x direction I loose the associated y and z value that lets me evaluate the grid: gridData[minX, someY, someZ] (I loose someY and someZ).

Snip-it of code:
x = 0
y = 1
z = 2
#Populates shared array with x, y, and z position where a portion of the object resides
if objArray[n] <= 0.0:
s_a[s_ix,s_iy,s_iz] = (thrdIdxX, thrdIdxY, thrdIdxZ)
nbcuda.syncthreads()

if s_ix == 0 and s_iy == 0 and s_iz == 0:
#Generate a 3x3 array to store the max values in each dim and their associated other 2 dimensions for use later
s_max = nbcuda.local.array((3,3), dtype = uint32)
for a in range(3):
for b in range(3):
s_max[a][b] = 0

s_min = nbcuda.local.array((3,3), dtype = uint32)
for a in range(3):
for b in range(3):
#When setting the initial min values a constant is added to the objDims so that the initial min is larger than the each of the dimensions of the object.
s_min[a][b] = objDims[x] + 2

for a in range(8):
for b in range(8):
for c in range(8):
for i in range(3):
if s_max[i][i] < s_a[a,b,c,i]:
s_max[i][x] = s_a[a,b,c,x]
s_max[i][y] = s_a[a,b,c,y]
s_max[i][z] = s_a[a,b,c,z]
#Prevents picking 0, after the shared array is zeroed
if s_a[a,b,c,i] > 0:
if s_min[i][i] > s_a[a,b,c,i]:
s_min[i][x] = s_a[a,b,c,x]
s_min[i][y] = s_a[a,b,c,y]
s_min[i][z] = s_a[a,b,c,z]

for i in range(3):
nbcuda.atomic.min(minmaxDimArray[i], 0, s_min[i][i])
nbcuda.atomic.max(minmaxDimArray[i], 1, s_max[i][i])

Each block is finding its local min/max in the x, y, and z directions along with their associated 2 other dimensional values. I then compare each min/max atomically. What I want to do is take each atomic min value ALONG with the other 2 dimensional values and evaluate this position on the grid of data. Is there a way I can rewrite this or incorporate/add another kernel to fix this problem?
Reply all
Reply to author
Forward
0 new messages