I am looking to be able to generate a random uniform sample of particle locations that fall within a spherical volume.
The image below (courtesy of http://nojhan.fre
Normed gaussian 3d vector is uniformly distributed on sphere, see http://mathworld.wolfram.com/SpherePointPicking.html
For example:
N = 1000
v = numpy.random.uniform(size=(3,N))
vn = v / numpy.sqrt(numpy.sum(v**2, 0))
Generate a set of points uniformly distributed within a cube, then discard the ones whose distance from the center exceeds the radius of the desired sphere.
Would this be uniform enough for your purposes?
In []: p= 2* rand(3, 1e4)- 1
In []: p= p[:, sum(p* p, 0)** .5<= 1]
In []: p.shape
Out[]: (3, 5216)
A slice of it
In []: plot(p[0], p[2], '.')
looks like:
import random
R = 2
def sample_circle(center):
a = random.random() * 2 * np.pi
r = R * np.sqrt(random.random())
x = center[0]+ (r * np.cos(a))
y = center[1] + (r * np.sin(a))
return x,y
ps = np.array([sample_circle((0,0)) for i in range(100)])
plt.plot(ps[:,0],ps[:,1],'.')
plt.xlim(-3,3)
plt.ylim(-3,3)
plt.show()
You can just generate random points in spherical coordinates (assuming that you are working in 3D): S(r, θ, φ ), where r ∈ [0, R), θ ∈ [0, π ], φ ∈ [0, 2π ), where R is the radius of your sphere. This would also allow you directly control how many points are generated (i.e. you don't need to discard any points).
To compensate for the loss of density with the radius, you would generate the radial coordinate following a power law distribution (see dmckee's answer for an explanation on how to do this).
If your code needs (x,y,z) (i.e. cartesian) coordinates, you would then just convert the randomly generated points in spherical to cartesian coordinates as explained here.
While I prefer the discarding method for spheres, for completeness I offer the exact solution.
In spherical coordinates, taking advantage of the sampling rule:
phi = random(0,2pi)
costheta = random(-1,1)
u = random(0,1)
theta = arccos( costheta )
r = R * cuberoot( u )
now you have a (r, theta, phi)
group which can be transformed to (x, y, z)
in the usual way
x = r * sin( theta) * cos( phi )
y = r * sin( theta) * sin( phi )
z = r * cos( theta )