【问题标题】:Random coordinates generator随机坐标生成器
【发布时间】:2021-10-03 16:25:38
【问题描述】:

我想为盒子几何中的球体生成随机坐标。我正在使用 while 循环,我有 2 个条件。第一个是坐标的距离。使用通用距离公式,以便坐标不重叠。第二个是孔隙率。当孔隙率小于 0.45 时,应停止生成。我的代码工作正常,但是当我将孔隙率条件降低到小于 0.80 时,算法会卡住。即使在数小时后,它也无法达到那种孔隙率。如何改进它以更快地生成坐标?任何建议表示赞赏。

#dist = math.sqrt(((x2-x1)**2) + ((y2-y1)**2) + ((z2-z1)**2))
import math
import random
import numpy as np
import matplotlib.pyplot as plt

A = 0.04       # x border.
B = 0.04       # y border.
C = 0.125      # z border.
V_total = A*B*C # volume
r = 0.006       # min distance of spheres.
radius = 0.003  # radius of spheres.
wall_distance = 0.003

Porosity = 1.0
coordinates = np.array([])
while Porosity >= 0.90:
    # coordinates
    x = random.uniform(wall_distance, A-wall_distance)
    y = random.uniform(wall_distance, B-wall_distance)
    z = random.uniform(wall_distance, C-wall_distance)
    coord1 = (x,y,z)
    if coordinates.shape[0] == 0: # add first one without condition
        coordinates = np.array([coord1])
    else:
        coordinates = np.vstack((coordinates, coord1))
    # seperate x,y,z and convert list for control
    d_x = coordinates[:,0]
    x = d_x.tolist()
    d_y = coordinates[:,1]
    y = d_y.tolist()
    d_z = coordinates[:,2]
    z = d_z.tolist()
    for j in range(len(y)):
        for k in range(j+1, len(z)):
            dist = math.sqrt(((x[j]-x[k])**2) + ((y[j]-y[k])**2) + ((z[j]-z[k])**2))
            if dist <= r:
                coordinates = coordinates[:-1, :] # if distance is less than r, remove last coordinate
    # check porosity
    V_spheres = (4/3) * (np.pi) * (radius**3) * len(coordinates)
    V_void = V_total - V_spheres
    Porosity = V_void / V_total

print("Porosity: {}".format(Porosity))
print("Number of spheres: {}".format(len(coordinates)))
    
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.set_xlim([0, A])
ax.set_ylim([0, B])
ax.set_zlim([0, C])
ax.set_title('Coordinates for spheres')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
p = ax.scatter(coordinates[:,0], coordinates[:,1], coordinates[:,2])
fig.colorbar(p)
plt.show()

【问题讨论】:

  • 首先,为什么不将 V_spheres 计算的(4/3) * (np.pi) * (radius**3) 部分移到循环之外呢?它的价值总是一样的。
  • 您确定删除了正确的坐标吗?您在扫描中间坐标时删除最后一个。这看起来很奇怪。
  • 低垂的果实:不要将距离与 r 进行比较,只需将距离的平方与 r2=r*r 进行比较。比较的结果相同,这将为您节省计算所有这些平方根的成本。

标签: python numpy random coordinates


【解决方案1】:

您可以采取多种措施来提高您的表现。请参阅下面我修改后的代码,并附上说明

import math
import random
import numpy as np
import matplotlib.pyplot as plt

A = 0.04       # x border.
B = 0.04       # y border.
C = 0.125      # z border.
V_total = A*B*C # volume
r = 0.006    # min distance of spheres.
radius = 0.003  # radius of spheres.
wall_distance = 0.003

Porosity = 1.0
coordinates = np.empty((0,3)) # initialize array with correct shape
while Porosity >= 0.70:
    # coordinates
    x = random.uniform(wall_distance, A-wall_distance)
    y = random.uniform(wall_distance, B-wall_distance)
    z = random.uniform(wall_distance, C-wall_distance)
    is_invalid = (True in [
                            math.sqrt(((x - coordinates[i_coor,0])**2) + 
                                      ((y - coordinates[i_coor,1])**2) + 
                                      ((z - coordinates[i_coor,2])**2)) <= r
                            for i_coor in range(coordinates.shape[0]) ])
    if not is_invalid:
        coordinates = np.append(coordinates,[[x,y,z]], axis = 0)
    else:
        continue
    V_spheres = (4/3) * (np.pi) * (radius**3) * len(coordinates)
    V_void = V_total - V_spheres
    Porosity = V_void / V_total
    print(f"placed coord {len(coordinates)}, por = {Porosity}")

print("Porosity: {}".format(Porosity))
print("Number of spheres: {}".format(len(coordinates)))
    
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.set_xlim([0, A])
ax.set_ylim([0, B])
ax.set_zlim([0, C])
ax.set_title('Coordinates for spheres')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
p = ax.scatter(coordinates[:,0], coordinates[:,1], coordinates[:,2])
np.savetxt('out.csv', coordinates)
fig.colorbar(p)
plt.show()

我改变的主要是这个双循环

for j in range(len(y)):
    for k in range(j+1, len(z)):
        dist = math.sqrt(((x[j]-x[k])**2) + ((y[j]-y[k])**2) + ((z[j]-z[k])**2))

这是在您每次添加一个点时检查每一对点是否重叠。这花了不必要的时间。通过仅检查新点是否与旧点相交,可以将运行时间从 O(n^3) 减少到 O(n^2)。我能够以 0.5 perosity 很快地运行它。

【讨论】:

  • 感谢您的帮助和友好的回复。 link 是我的代码,孔隙率为 0.90,正如您所见,球体只是相互接触,而 link 是您的校正,孔隙率为 0.90,与其他代码相同,但球体在其他球体内。有什么建议吗?
  • 那是我的错。我有一个错字:不是检查distance &gt; r 是否是distance &gt; radius。查看修复的更新代码。
  • 我已经修好了,但结果还是一样。
  • 当,真的吗?您如何生成该图像?
  • 该死,我对我的括号过于热心了,这造成了一个错误,使它看起来比原来快得多。请参阅更新的代码。它会比你原来的更快,但仍然很慢。我会考虑一下,看看是否可以找到任何其他速度改进。
猜你喜欢
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 2023-01-07
  • 1970-01-01
  • 2020-12-09
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
相关资源
最近更新 更多