我正在尝试生成一个有效的代码来生成一些随机位置向量,然后我用它来计算一对相关函数。我想知道是否有直接的方法来设置我的盒子中任意两点之间允许的最小距离约束。
我的代码目前如下:
def pointRun(number, dr):
"""
Compute the 3D pair correlation function
for a random distribution of 'number' particles
placed into a 1.0x1.0x1.0 box.
"""
## Create array of distances over which to calculate.
r = np.arange(0., 1.0+dr, dr)
## Generate list of arrays to define the positions of all points,
## and calculate number density.
a = np.random.rand(number, 3)
numberDensity = len(a)/1.0**3
## Find reference points within desired region to avoid edge effects.
b = [s for s in a if all(s > 0.4) and all(s < 0.6) ]
## Compute pairwise correlation for each reference particle
dist = scipy.spatial.distance.cdist(a, b, 'euclidean')
allDists = dist[(dist < np.sqrt(3))]
## Create histogram to generate radial distribution function, (RDF) or R(r)
Rr, bins = np.histogram(allDists, bins=r, density=False)
## Make empty containers to hold radii and pair density values.
radii = []
rhor = []
## Normalize RDF values by distance and shell volume to get pair density.
for i in range(len(Rr)):
y = (r[i] + r[i+1])/2.
radii.append(y)
x = np.average(Rr[i])/(4./3.*np.pi*(r[i+1]**3 - r[i]**3))
rhor.append(x)
## Generate normalized pair density function, by total number density
gr = np.divide(rhor, numberDensity)
return radii, gr
我之前尝试过使用循环计算每个点的所有距离,然后接受或拒绝。如果我使用很多点,这种方法非常慢。
答案 0 :(得分:1)
据我所知,你正在寻找一种算法来在一个盒子里创建许多随机点,这样两个点就不会比一些最小距离更近。如果这是你的问题,那么你可以利用统计物理学,并使用分子动力学软件解决它。此外,您确实需要分子动力学或蒙特卡罗来获得该问题的精确解。
你将N个原子放在一个矩形框中,在它们之间产生一个固定半径的排斥相互作用(例如移动的Lennard-Jones相互作用),并运行模拟一段时间(直到你看到这些点在整个过程中均匀分布)框)。根据统计物理定律,您可以显示点的位置将最大随机给定点不能接近某个距离的约束。 如果您使用迭代算法,例如逐个放置点,如果它们重叠则拒绝它们
我估计10000点的运行时间为几秒,而100k的运行时间为几分钟。我使用OpenMM进行所有的动力学模拟。
答案 1 :(得分:0)
这是使用numpy
的可扩展O(n)解决方案。它的工作方式是首先指定一个等距的点网格,然后对点进行一定程度的扰动,使点之间的距离最大为min_dist
。
您需要调整点数,盒子形状和微扰灵敏度,以获得所需的min_dist
。
注意:如果您固定了框的大小并指定了每个点之间的最小距离,那么可以满足最小距离的点数将受到限制
import numpy as np
import matplotlib.pyplot as plt
# specify params
n = 500
shape = np.array([64, 64])
sensitivity = 0.8 # 0 means no movement, 1 means max distance is init_dist
# compute grid shape based on number of points
width_ratio = shape[1] / shape[0]
num_y = np.int32(np.sqrt(n / width_ratio)) + 1
num_x = np.int32(n / num_y) + 1
# create regularly spaced neurons
x = np.linspace(0., shape[1]-1, num_x, dtype=np.float32)
y = np.linspace(0., shape[0]-1, num_y, dtype=np.float32)
coords = np.stack(np.meshgrid(x, y), -1).reshape(-1,2)
# compute spacing
init_dist = np.min((x[1]-x[0], y[1]-y[0]))
min_dist = init_dist * (1 - sensitivity)
assert init_dist >= min_dist
print(min_dist)
# perturb points
max_movement = (init_dist - min_dist)/2
noise = np.random.uniform(
low=-max_movement,
high=max_movement,
size=(len(coords), 2))
coords += noise
# plot
plt.figure(figsize=(10*width_ratio,10))
plt.scatter(coords[:,0], coords[:,1], s=3)
plt.show()
答案 2 :(得分:0)
基于@Samir的答案,并使其成为可调用的函数:)
import numpy as np
import matplotlib.pyplot as plt
def generate_points_with_min_distance(n, shape, min_dist):
# compute grid shape based on number of points
width_ratio = shape[1] / shape[0]
num_y = np.int32(np.sqrt(n / width_ratio)) + 1
num_x = np.int32(n / num_y) + 1
# create regularly spaced neurons
x = np.linspace(0., shape[1]-1, num_x, dtype=np.float32)
y = np.linspace(0., shape[0]-1, num_y, dtype=np.float32)
coords = np.stack(np.meshgrid(x, y), -1).reshape(-1,2)
# compute spacing
init_dist = np.min((x[1]-x[0], y[1]-y[0]))
# perturb points
max_movement = (init_dist - min_dist)/2
noise = np.random.uniform(low=-max_movement,
high=max_movement,
size=(len(coords), 2))
coords += noise
return coords
coords = generate_points_with_min_distance(n=8, shape=(2448,2448), min_dist=256)
# plot
plt.figure(figsize=(10,10))
plt.scatter(coords[:,0], coords[:,1], s=3)
plt.show()
答案 3 :(得分:0)
{{1}}