Sorting vectors into a 3-D grid efficently

3 views (last 30 days)
I have a very large number of particles, numbered 1 to m, with a 3-D position and diameter d that live on the unit torus (i.e. [0,1)^3 mod 1). I would like to create a k x k x k cell arrray, where the entires of the i,j,k cell are the particle numbers of the corresponding particles that intesect the i,j,k cube of grid of the unit torus. The point of this is to reduce the complexity of collision detection for a very large number of particles. My currrent grid function is very slow and it was suggested to me that I vectorise my code to increase its speed.
additionally there will be a few particles whose position is [0;0;0]. I wish these particles to be ingored and not placed in the grid.
Here is my current grid function;
function [G] = grid(u,d,k)
%u is a 3 x m matrix where each coloumn is a particle postion, d is diameter and k is how many partitions
% of [0,1) we want.
m = length(u); %number of particles
K = zeros(3,15,length(u));
X = transpose(unique([(dec2bin(0:2^3-1)-'0');-(dec2bin(0:2^3-1)-'0')],'rows')) ;
%all possible combinations of standard basis multiplied by either 1 or -1
Gi = cell(k,k,k);
h = zeros(m,1);
Z = cell(1,m);
for j = 1:m %Nested foor loop ignores particles at orgin and gives which boxes a
%ball of diameter d intersects
if any(u(:,j) ~=0)
for i = 1:15
K(:,i,j) = floor(k.*mod((u(:,j) + (d./2).*X(:,i)),1));
end
end
end
for l = 1:m %cell i contians a vector whose entries are determined by
%the boxes particle i intersects, without repertitions
Z{l} = [unique(K(:,:,l).','rows','stable')].';
end
for t = 1:m
h(t) = size(Z{t},2); %number of boxes particle t intersects
for n = 1:h(t)
if any(u(:,t) ~= 0) %checking u is not the zero vector, zero
% are to be ignored in the grid.
Gi{Z{t}(1,n)+1,Z{t}(2,n)+1,Z{t}(3,n)+1} = cat(2,Gi{Z{t}(1,n)+1,Z{t}(2,n)+1,Z{t}(3,n)+1},t);
end
end
end
G = Gi;
end
The first for loop can be vectorised and take the from,
for i = 1:15
K(:,i,:) = ceil(k*mod((u + (d/2)*X(:,i)),1));
% jth page states which box particle j's centre lives when it is perturbed by d/2 in direction X(:,i)
end
However, now that I know which grids each particle intersects I am really struggling to assign the particle numbers to a correct position in the cell array in an effiecnt and computationally quick way. If people have different suggestion to a cell array I would love to hear any suggestions. I have tried looking at the histogram functions but they seem to tell me how many particles live in each grid cube (or bin as the hist websie calls them) where I'd like to know what particles fall exatly in what bin.
EDIT example added
I have simplified my problem for the sake of an example, so for this example the only objects of intrest are the discetised positions and the number of bins in each direction
V = [1,1,3,4,0,5;1,1,1,1,0,4;1,1,1,5,0,1] %the discretised particle positions
% the data for particle i is
% given by V(:,i)
G = grid(V,k) %G each entry of G should tell me
%which particles live in the
%corresponding cube
G{[1;1;1]} = {[1,2]}
G{[3;1;1]} = {[3]}
G{[4;5;1]} = {[4]}
G{[5;4;1]} = {[6]}
%since particle 5 has data [0;0;0] it is ignored furthermore all other cells of G are empty
note first code achieves this succesfully but it is too slow to be useful for large quanitites of particles.
Many Thanks
  3 Comments
Milos
Milos on 7 Mar 2023
Thank you for your help. Discretize is a great start to what I want to do. I have had a look at the 3rd output of histcounts an I think I didn't explain my problem well enough. I'd like the converse to the 3rd output of histcounts. That is to say if i look at bin j, say, I'd like to get a list which contians all the particles wiich lie in said bin. I have added an example to clarify my question

Sign in to comment.

Accepted Answer

Stephen23
Stephen23 on 7 Mar 2023
Perhaps something like this. The elements of M need to be valid indices, which you can achieve using basic arithmetic operations on your data (i.e. scaling, adding offset, rounding), else zeros which will be ignored.
format compact
M = [1,1,3,4,0,5;1,1,1,1,0,4;1,1,1,5,0,1] % in columns would be better
M = 3×6
1 1 3 4 0 5 1 1 1 1 0 4 1 1 1 5 0 1
Z = find(all(M,1));
[U,~,X] = unique(M(:,Z).','rows','stable');
G = accumarray(U(X,:),Z(:),[5,5,5],@(v){v})
G = 5×5×5 cell array
G(:,:,1) = {2×1 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {[ 3]} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {[ 6]} {0×0 double} G(:,:,2) = {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} G(:,:,3) = {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} G(:,:,4) = {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} G(:,:,5) = {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {[ 4]} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double}
The content of G is:
G{1,1,1}
ans = 2×1
1 2
G{3,1,1}
ans = 3
G{4,1,5}
ans = 4
G{5,4,1}
ans = 6
  1 Comment
Milos
Milos on 7 Mar 2023
Thank you so much for this! This is exactly what I want! You have taught me a lot with this solution there are so many additional properties of the used function that I didn't know existed, sorry I'm only just starting out with matlab. One thing I would like to say though is maybe we define Z via
Z = find(any(M,1));
as oppesed to using all since I want to omit Non-zero positions. I now see this was ambiguous, what I mean by zero vector, is that every entry in said coloumn is zero.
Once again many thanks for this answer!

Sign in to comment.

More Answers (0)

Categories

Find more on Creating and Concatenating Matrices in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!