# Perturb lattice positions for non-overlapping particles

Using the below commands, a simple lattice configuration can be generated:

Cube = Normal@LatticeData["SimpleCubic", "Basis"];
LatPos = Flatten[Table[i Cube[] + j Cube[] + k Cube[], {i, 0, 100,
5}, {j, 0, 100, 5}, {k, 0, 10, 5}], 2];
Graphics3D[Map[Sphere[#, parsize] &, #], Boxed -> True, Axes -> True] & /@ {LatPos}


for particle size (parsize) equals to one, one can have: At the next step, I need to move these particles in the random directions (starting with small movement) in the condition that particles do not overlap. I used the below code to generate the movements and check if they have intersections or not. However, it took forever to run when the number of particles is large.

maxRanNum = 0.5;
LatPos2 = {}; Do[Label[ran]; r = RandomReal[{-maxRanNum, maxRanNum}, 3];If[0 <= r[] + LatPos[[i]][] <= 100 && 0 <= r[] + LatPos[[i]][] <= 100 && 0 <= r[] + LatPos[[i]][] <= 10,LatPos2 = AppendTo[LatPos2, LatPos[[i]] + r],Goto[ran]], {i, Length[LatPos]}];
Graphics3D[Map[Sphere[#, parsize] &, #], Boxed -> True, Axes -> True] & /@ {LatPos2} and to check the itersections:

Do[If[i == j, Continue[]]; intersection = RegionMeasure[RegionIntersection[Sphere[LatPos2[[i]], parsize],Sphere[LatPos2[[j]], parsize]]];
If[intersection != 0, Print[false];
Break[], Continue[]], {i, Length[LatPos2]}, {j, Length[LatPos2]}]


so I suppose that creating the movement of the lattice particles need to be coded together with the overlapping check. But I do not know how it can be done. I appreciate your help in this matter.

• @kglr Since I used your good suggestion before, regarding the same problem, I supposed maybe you can help me in this regard too. Thank you. – Bahar Feb 14 '18 at 3:16
• Bahar, this is much tougher than your previous question:) I will post an answer if I come up with something. It looks like you need to generate a RandomPoint in each of the 3D VoronoiMesh cells. But, unfortunately, VoronoiMesh works only for 1D and 2D. This q/a may be useful. See also TriangulateMesh and Insphere. – kglr Feb 14 '18 at 8:26
• Thank you. I will take a look at them. – Bahar Feb 14 '18 at 19:33

This should be much more efficient for counting the number of sphere intersections:

intersections[LatPos_] :=
Total[
Length /@ Nearest[LatPos -> Automatic, LatPos, {∞, 2 parsize}]
] - Length[LatPos]


We use that two spheres intersect if and only if the distance of the center points is less or equal to the sum of radii. Moreover, we use Nearest to find for each point in LatPos the list of the indices of all points (this is why ∞ appears) that have distance less or equal to 2 parsize. Afterwards, we count the total number of indices and subtract Length[LatPos] since every point has distance 0 to itself.

Edit

Should it be impossible to feed Nearest with a second argument which is a list of points, you can also use the following function (with a certain loss of performance)

intersections2[LatPos_] := With[{nf = Nearest[LatPos -> Automatic]},
Total[Length[nf[#, {∞, 2 parsize}]] & /@ LatPos] - Length[LatPos]
]

• Thanks for your help. I understand your explanations, but it gives me the following error when I run the code: – Bahar Feb 14 '18 at 17:43
• In:= intersections[LatPos] During evaluation of In:= Nearest::dmtch: The dimension of {{0.,0.,0.},{0.,74.822,0.},{74.822,0.,0.},{74.822,74.822,0.}}->Automatic and {{0.,0.,0.},{0.,74.822,0.},{74.822,0.,0.},{74.822,74.822,0.}} does not match. >> During evaluation of In:= Nearest::near1: 2 is neither a list of real points nor a valid list of rules. >> Out= 4 – Bahar Feb 14 '18 at 17:49
• You have to give a numerical value to parsize. – Henrik Schumacher Feb 14 '18 at 18:00
• Yes, I did. parsize=1. – Bahar Feb 14 '18 at 18:07
• If it still won't work, try to remove -> Automatic. Which version of Mathematica do you use? – Henrik Schumacher Feb 14 '18 at 18:10