Hello, I have viewed the sample gas.py code that comes with Vpython and am trying to replicate "particles in a box colliding with one another" as my foray into Vpython. However, my code is telling some of the particles to stick together after colliding. I cannot figure out why. I think I am missing some basic concept rather than there being an issue with my code. Below is my code, anyhow. Looking forward to any advice!
from visual import *
import numpy
frame = box(pos=(0,0,0), size=(10,10,1), color=color.cyan, opacity=.5)
rad=.25
numParticles=10
deltat=.005
maxSpeed=10
minSpeed=0
particles=[]
vel=[]
pos=[]
i=0
count=0
#randomly choose starting locations of particles
while i < numParticles:
coord=True
tempX = random.uniform(-frame.size.x/2. + rad, frame.size.x/2. - rad)
tempY = random.uniform(-frame.size.y/2. + rad, frame.size.y/2. - rad)
tempZ = 0#random.uniform(-frame.size.z/2. + rad, frame.size.z/2. - rad)
for j in range(len(particles)):
if pow(tempX-particles[j].pos.x, 2) + pow(tempY-particles[j].pos.y, 2) + pow(tempZ-particles[j].pos.z, 2) < pow(2*rad, 2):
coord=False
break
if coord==True:
i=i+1
particles.append(sphere(pos=(tempX,tempY,tempZ), radius=rad, color=color.magenta))
pos.append((tempX, tempY, tempZ))
count=count+1
if count==1000:
print (str(i) + " balls produced. No room for any more.")
break
#randomly choose starting velocities of particles
for i in range(len(particles)):
velX=random.uniform(minSpeed, maxSpeed)
velY=random.uniform(minSpeed, maxSpeed)
velZ=0#random.uniform(minSpeed, maxSpeed)
particles[i].velocity=vector(velX, velY, velZ)
vel.append((velX, velY, velZ))
posArray=numpy.array(pos)
velArray=numpy.array(vel)
while True:
rate (100)
#update position of every particle by v*dt
posArray=posArray+(velArray*deltat)
#determine if a particle collides with another particle
diff=posArray.reshape(numParticles,1,3)-posArray #difference between every particle and every other particle
D = (diff**2).sum(2) #square the distances and sum xyz dimensions for each particle
index=numpy.arange(numParticles)
D[index, index]=numpy.inf #set the diagonal = infinity to remove distance between each particle and itself (obviously zero and not a collision)
collision=numpy.less_equal(D, (2*rad)**2) #collison is a boolean array of True if a particle is colliding with another particle and False if it is not
collisionList = numpy.transpose(numpy.nonzero(collision)) #collisionList is a list of all indices of all particles colliding
duplicate=[]
for i in range(len(collisionList)):
j=collisionList[i][0]
k=collisionList[i][1]
if [j, k] not in duplicate:
duplicate.append([k, j])
finalVx1=0
finalVy1=0
finalVz1=0
finalVx2=0
finalVy2=0
finalVz2=0
Vx1=velArray[j][0]
Vy1=velArray[j][1]
Vz1=velArray[j][2]
Vx2=velArray[k][0]
Vy2=velArray[k][1]
Vz2=velArray[k][2]
xcoeff=[1, -1*(Vx1+Vx2), Vx1*Vx2]
ycoeff=[1, -1*(Vy1+Vy2), Vy1*Vy2]
zcoeff=[1, -1*(Vz1+Vz2), Vz1*Vz2]
xroots=numpy.roots(xcoeff)
yroots=numpy.roots(ycoeff)
zroots=numpy.roots(zcoeff)
if xroots[0]!=Vx2:
finalVx2=xroots[0]
else:
finalVx2=xroots[1]
if yroots[0]!=Vy2:
finalVy2=yroots[0]
else:
finalVy2=yroots[1]
if zroots[0]!=Vz2:
finalVz2=zroots[0]
else:
finalVz2=zroots[1]
finalVx1 = Vx1 + Vx2 - finalVx2
finalVy1 = Vy1 + Vy2 - finalVy2
finalVz1 = Vz1 + Vz2 - finalVz2
velArray[j] = [finalVx1, finalVy1, 0]#finalVz1]
velArray[k] = [finalVx2, finalVy2, 0]#finalVz2]
#determine if a particle hits a wall
wallHit=numpy.less_equal(frame.size.y/2., rad+abs(posArray)) #wallHit is a boolean array of True if a particle's position is outside frame and False if inside frame
V=velArray*wallHit #V is velArray with only velocities of particles that are outside the frame
V=V*-1 #this reverses all the velocities to make them "bounce" off the wall
velArray=velArray*numpy.less_equal(rad+abs(posArray), frame.size.y/2.) #this makes velArray only have values for particles within the frame. Particles outside the frame get vel of zero
velArray=velArray+V #add the arrays to update velArray
for i in range(numParticles):
particles[i].pos = posArray[i]
particles[i].velocity=vector(velArray[i])