首页 > 解决方案 > 随机坐标生成器

问题描述

我想为盒子几何中的球体生成随机坐标。我正在使用 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()

标签: pythonnumpyrandomcoordinates

解决方案


您可以在这里做很多事情来提高您的表现。请参阅下面我修改后的代码,并附有解释

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 循环

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 很快地运行它。


推荐阅读