I have a 3D numpy array of voxels, i.e. where the indices of each point correspond to its position in 3D space.
There are a number of calculations I wish to perform that involve knowing whether the points satisfy various geometric conditions. This means converting the indices into vectors by multiplying by the basis, and then calculating dot and cross products, norms etc.. I am looking for a reasonably fast way to do this, as my efforts so far seem very slow.
If I have an arbitrary basis a, b, c:
basis = np.array([[a1, a2, a3],
[b1, b2, b3],
[c1, c2, c3]])
where a1, a2, a3 are the x, y and z components of a, and likewise for b and c. I can calculate the Cartesian coordinate p = (x, y, z) of each voxel in the following way:
for i in range(vox.shape[0]):
for j in range(vox.shape[1]):
for k in range(vox.shape[2]):
p = np.dot(basis, np.array([i, j, k]))
where "vox" is the 3D array of voxels. If, for example, I wish to calculate the dot product of each of these vectors with a single other (Cartesian) vector (e.g. q = np.array([qx, qy, qz])
) and store that index if the result meets a given condition (here greater than 0.0), I could do something like this (within the same loop as above):
if np.dot(p, q) > 0.0:
desired_vox_indices.append([i, j, k])
The problem is that this is very slow. Can I do this in a more pythonic way, or by using more numpy tools? I realise I am not even accessing the values of the vox array at this stage either.
EDIT: attempt at cross product based on answer by Divakar
# Get q_x (matrix multiplication version of cross product)
q_x = np.array([[0.0, -q[2], q[1]],
[q[2], 0.0, -q[0]],
[-q[1], q[0], 0.0]])
# transpose (as per cross product definition) and matrix multiply with basis
u = np.matmul(q_x.T, basis)
# Get open range arrays
m,n,r = vox.shape
I,J,K = np.ogrid[:m,:n,:r]
# writing everything explicitly, since I am unsure how ogrid objects behave
pxq = np.empty(3)
pxq[0] = u[0,0]*I + u[0,1]*J + u[0,2]*K
pxq[1] = u[1,0]*I + u[1,1]*J + u[1,2]*K
pxq[2] = u[2,0]*I + u[2,1]*J + u[2,2]*K
which might be the same as just:
pxq = np.dot(u, np.array([I, J, K]))
but I am not sure...