I am trying to create a simple self-avoiding freely-jointed chain. The chain part is already completed, it starts at a given point in 3D space (e.g. [0,0,0]). I then generate a new point by randomizing two spherical coordinates θ, φ (the radius is given). Giving me a new point.
Since the points are randomly placed (as opposed to integers a normal 3D walk on a 3D grid), I cannot check if the exact point has been visited before (i.e., iterate over an array of visited points). Instead I have to check if the point lies within a certain radius of previously visited points (small spheres created by every visited point).
I have tried extracting the part of my code I need help with, and adjusted it so it runs by itself. This is with step length 1, and the "avoid radius" = 0.5 (chosen arbitrarily)
import numpy as np
import random
# Generating new point in spherical coordinates, convert to cartesian coordinates
steps = 10
visited = np.zeros([steps,3],dtype=float) # "array of all visited points"
steplength= 1
costheta = random.uniform(-1,1)
theta = np.arccos(costheta)
phi = random.random() * 2 * np.pi
newpos = numpy.copy(visited[-1]) # copy of "previous point"
newpos[0] += steplength* np.cos(phi) * np.sin(theta)
newpos[1] += steplength* np.sin(phi) * np.sin(theta)
newpos[2] += steplength* np.cos(theta)
# Self-avoid condition (part I need help with)
tooclose = False
for i in range(steps): #For every visited position, check if newpos is too close
diff = np.subtract(pos, self.visited[i])
dist = np.sqrt(diff.dot(diff))
if dist < avoidradius ** 2:
tooclose = True
break
As shown in the code, I simply check the distance from every point and check if it's smaller than the allowed radius. This approach works to make it "self-avoiding", but it is slow. Is there a better way to do it? Perhaps using a different coordinate system, different numpy code (I am not very good at numpy), a different library or a different setup altogether?