使用python中的pivot算法自我避免在3d点阵中随机游走

时间:2016-05-25 16:56:35

标签: python computational-geometry

我正在研究过去几天的问题,这与使用数据算法创建自我避免随机游走然后实现另一个将球形包含物放置在三维点阵中的代码有关。我编写了两个代码,一个代码通过使用Self self random walk算法生成球体的坐标,然后另一个代码使用第一个程序生成的坐标,然后在abaqus中创建一个带有球形包含的3d格子。

运行代码后生成的结果: Result which i got

现在放大部分(以红色边界标记) enter image description here

问题:生成的球体彼此合并,如何避免这种情况,我的想法用尽了。我只需要一些方向或算法来处理

我写的代码如下: 代码1:生成球体的坐标

# Functions of the code: 1) This code generates the coordinates for the spherical fillers using self avoiding random walk which was implemented by pivot algorithm
# Algorithm of the code: 1)Prepare an initial configuration of a N steps walk on lattice(equivalent N monomer chain)
#                        2)Randomly pick a site along the chain as pivot site
#                        3)Randomly pick a side(right to the pivot site or left to it), the chain on this side is used for the next step.
#                        4)Randomly apply a rotate operation on the part of the chain we choose at the above step.
#                        5)After the rotation, check the overlap between the rotated part of the chain and the rest part of the chain. 
#                        6)Accept the new configuration if there is no overlap and restart from 2th step. 
#                        7)Reject the configuration and repeat from 2th step if there are overlaps.
################################################################################################################################################################
# Modules to be imported are below
import numpy as np
import timeit
from scipy.spatial.distance import cdist
import math
import random
import sys
import ast

# define a dot product function used for the rotate operation
def v_dot(a):return lambda b: np.dot(a,b)

def distance(x, y): #The Euclidean Distance to Spread the spheres initiallly
    if len(x) != len(y):
        raise ValueError, "vectors must be same length"
    sum = 0
    for i in range(len(x)):
        sum += (x[i]-y[i])**2
    return math.sqrt(sum)

x=1/math.sqrt(2)
class lattice_SAW: # This is the class which creates the self avoiding random walk coordinates
    def __init__(self,N,l0):
        self.N = N #No of spheres
        self.l0 = l0 #distance between spheres
        # initial configuration. Usually we just use a straight chain as inital configuration
        self.init_state = np.dstack((np.arange(N),np.zeros(N),np.zeros(N)))[0] #initially set all the coordinates to zeros
        self.state = self.init_state.copy()

        # define a rotation matrix
        # 9 possible rotations: 3 axes * 3 possible rotate angles(45,90,135,180,225,270,315)
        self.rotate_matrix = np.array([[[1,0,0],[0,0,-1],[0,1,0]],[[1,0,0],[0,-1,0],[0,0,-1]]
                                     ,[[1,0,0],[0,0,1],[0,-1,0]],[[0,0,1],[0,1,0],[-1,0,0]]
                                     ,[[-1,0,0],[0,1,0],[0,0,-1]],[[0,0,-1],[0,1,0],[-1,0,0]]
                                     ,[[0,-1,0],[1,0,0],[0,0,1]],[[-1,0,0],[0,-1,0],[0,0,1]]
                                     ,[[0,1,0],[-1,0,0],[0,0,1]],[[x,-x,0],[x,x,0],[0,0,1]]
                                     ,[[1,0,0],[0,x,-x],[0,x,x]]
                                     ,[[x,0,x],[0,1,0],[-x,0,x]],[[-x,-x,0],[x,-x,0],[0,0,1]]
                                     ,[[1,0,0],[0,-x,-x],[0,x,-x]],[[-x,0,x],[0,1,0],[-x,0,-x]]
                                     ,[[-x,x,0],[-x,-x,0],[0,0,1]],[[1,0,0],[0,-x,x],[0,-x,-x]]
                                     ,[[-x,0,-x],[0,1,0],[x,0,-x]],[[x,x,0],[-x,x,0],[0,0,1]]
                                     ,[[1,0,0],[0,x,x],[0,-x,x]],[[x,0,-x],[0,1,0],[x,0,x]]])

    # define pivot algorithm process where t is the number of successful steps
    def walk(self,t): #this definitions helps to start walking in 3d
        acpt = 0
        # while loop until the number of successful step up to t
        while acpt <= t:
            pick_pivot = np.random.randint(1,self.N-1)     # pick a pivot site
            pick_side = np.random.choice([-1,1])           # pick a side
            if pick_side == 1:
                old_chain = self.state[0:pick_pivot+1]
                temp_chain = self.state[pick_pivot+1:]
            else:
                old_chain = self.state[pick_pivot:] # variable to store the coordinates of the old chain
                temp_chain = self.state[0:pick_pivot]# for the temp chain
            # pick a symmetry operator
            symtry_oprtr = self.rotate_matrix[np.random.randint(len(self.rotate_matrix))]     
            # new chain after symmetry operator
            new_chain = np.apply_along_axis(v_dot(symtry_oprtr),1,temp_chain - self.state[pick_pivot]) + self.state[pick_pivot] 
            # use cdist function of scipy package to calculate the pair-pair distance between old_chain and new_chain
            overlap = cdist(new_chain,old_chain) #compare the old chain and the new chain to check if the new chain overlaps on any previous postion

            overlap = overlap.flatten() # just to combine the coordinates in a list which will help to check the overlap

            # determinte whether the new state is accepted or rejected
            if len(np.nonzero(overlap)[0]) != len(overlap):
                continue
            else:
                if pick_side == 1:
                    self.state = np.concatenate((old_chain,new_chain),axis=0)
                elif pick_side == -1:
                    self.state = np.concatenate((new_chain,old_chain),axis=0)
                acpt += 1

        # place the center of mass of the chain on the origin, so then we can translate these coordinates to the initial spread spheres
        self.state = self.l0*(self.state - np.int_(np.mean(self.state,axis=0)))
#now write the coordinates of the spheres in a file
sys.stdout = open("C:\Users\haris\Desktop\CAME_MINE\HIWI\Codes\Temp\Sphere_Positions.txt", "w")
n = 30
#text_file.write("Number of Spheres: " + str(n) + "\n")

#Radius of one sphere: is calculated based on the volume fraction here it 2 percent
r = (3*0.40)/(4*math.pi*n)
#print r
r = r**(1.0/3.0)
#print "Sphere Radius is " + str(r)
sphereList = [] # list to maintain track of the Spheres using their positions
sphereInstancesList = [] # to maintain track of the instances which will be used to cut and or translate the spheres
sphere_pos=[]

#Create n instances of the sphere
#After creating n instances of the sphere we trie to form cluster around each instance of the sphere
for i in range(1, n+1):
    InstanceName = 'Sphere_' + str(i) # creating a name for the instance of the sphere
    #print InstanceName
    #text_file.write(InstanceName)

    #Maximum tries to distribute sphere
    maxTries = 10000000

    while len(sphereList) < i:
        maxTries -= 1
        if maxTries < 1:
            print "Maximum Distribution tries exceded. Error! Restart the Script!"
            break;

        # Make sure Spheres dont cut cube sides: this will place the spheres well inside the cube so that they does'nt touch the sides of the cube 
        # This is done to avoid the periodic boundary condition: later in the next versions it will be used
        vecPosition = [(2*r)+(random.random()*(10.0-r-r-r)),(2*r)+(random.random()*(10.0-r-r-r)),(2*r)+(random.random()*(10.0-r-r-r))]

        sphere_pos.append(vecPosition)
        for pos in sphereList:
            if distance(pos, vecPosition) < 2*r: # checking whether the spheres collide or not
                break
        else:
            sphereList.append(vecPosition)
            print vecPosition
            #text_file.write(str(vecPosition) + "\n")

cluster_Size=[10,12,14,16,18,20,22,24,26,28,30] #list to give the random number of spheres which forms a cluster
for i in range(1,n+1):
    Number_of_Spheres_Clustered=random.choice(cluster_Size) #selecting randomly from the list cluster_Size
    radius_sphr=2*r #Distance between centers of the spheres
    pivot_steps=1000 # for walking the max number of steps
    chain = lattice_SAW(Number_of_Spheres_Clustered,radius_sphr) #initializing the object
    chain.walk(pivot_steps) # calling the walk function to walk in the 3d space
    co_ordinates=chain.state # copying the coordinates into a new variable for processing and converting the coordinates into lists
    for c in range(len(co_ordinates)):
        temp_cds=co_ordinates[c]
        temp_cds=list(temp_cds)        
        for k in range(len(temp_cds)):
            temp_cds[k]=temp_cds[k]+sphere_pos[i-1][k]
        #text_file.write(str(temp_cds) + "\n")
        print temp_cds #sys.stdout redirected into the file which stores the coordinates as lists
sys.stdout.flush()

f2=open("C:\Users\haris\Desktop\CAME_MINE\HIWI\Codes\Temp\Sphere_Positions.txt", "r")
remove_check=[]
for line in f2:
    temp_check=ast.literal_eval(line)
    if (temp_check[0]>10 or temp_check[0]<-r or temp_check[1]>10 or temp_check[1]<-r or temp_check[2]>10 or temp_check[2]<-r):
        remove_check.append(str(temp_check))
f2.close()
flag=0
f2=open("C:\Users\haris\Desktop\CAME_MINE\HIWI\Codes\Temp\Sphere_Positions.txt", "r")
f3=open("C:\Users\haris\Desktop\CAME_MINE\HIWI\Codes\Temp\Sphere_Positions_corrected.txt", "w")
for line in f2:
    line=line.strip()
    if any(line in s for s in remove_check):
        flag=flag+1
    else:
        f3.write(line+'\n')
f3.close()
f2.close()

不需要其他代码,因为第二个代码中没有几何计算。任何帮助或如何避免球体碰撞的方向都非常有帮助,谢谢大家

1 个答案:

答案 0 :(得分:2)

为了容纳45,135,225,315(实际上只有45和315是问题)的非交叉球体,你只需要让你的球体稍微小一些。取3个连续的球心,中间有45度转弯。在包含3个点的平面中,形成等腰三角形,中心角为45度:

overlapping spheres

请注意底部圆圈(球体)重叠。要避免这种情况,可以通过乘以系数0.76来缩小半径:

smaller spheres