Python 3.x 粒子碰撞模拟Python
我试图创建一个相对简单的粒子模拟,它应该考虑重力、阻力、与其他粒子的碰撞(非弹性碰撞)以及与墙的碰撞(完全弹性)。我用velocity Verlet算法得到了重力和阻力部分,但目前还不能将粒子设置为平衡状态。此外,如果我加上多个粒子,它们有时会相互攀爬,这是由于(我相信)它们仍然有非常小的速度分量,这些分量逐渐变为零。如果粒子的能量足够小,我试图切断粒子的速度,但是看起来不现实。也许有人能提出一些解决这些问题的建议。我得到了一个粒子对象:Python 3.x 粒子碰撞模拟Python,python-3.x,simulation,collision,verlet-integration,Python 3.x,Simulation,Collision,Verlet Integration,我试图创建一个相对简单的粒子模拟,它应该考虑重力、阻力、与其他粒子的碰撞(非弹性碰撞)以及与墙的碰撞(完全弹性)。我用velocity Verlet算法得到了重力和阻力部分,但目前还不能将粒子设置为平衡状态。此外,如果我加上多个粒子,它们有时会相互攀爬,这是由于(我相信)它们仍然有非常小的速度分量,这些分量逐渐变为零。如果粒子的能量足够小,我试图切断粒子的速度,但是看起来不现实。也许有人能提出一些解决这些问题的建议。我得到了一个粒子对象: import pygame import random
import pygame
import random
import numpy as np
import operator
from itertools import combinations
class Particle:
def __init__(self):
self.mass = 10
self.radius = random.randint(10, 50)
self.width, self.height = 700, 500
self.pos = np.array((self.width/2, self.height/2))
self.v = np.array((0.0, 0.0))
self.acc = np.array((0.0, 0.0))
self.bounce = 0.95
我使用Verlet积分来解释重力和阻力:
def update(self, ball, dt):
new_pos = np.array((ball.pos[0] + ball.v[0]*dt + ball.acc[0]*(dt*dt*0.5), ball.pos[1] + ball.v[1]*dt + ball.acc[1]*(dt*dt*0.5)))
new_acc = np.array((self.apply_forces(ball))) # only needed if acceleration is not constant
new_v = np.array((ball.v[0] + (ball.acc[0]+new_acc[0])*(dt*0.5), ball.v[1] + (ball.acc[1]+new_acc[1])*(dt*0.5)))
ball.pos = new_pos;
ball.v = new_v;
ball.acc = new_acc;
def apply_forces(self, ball):
grav_acc = [0.0, 9.81]
drag_force = [0.5 * self.drag * (ball.v[0] * abs(ball.v[0])), 0.5 * self.drag * (ball.v[1] * abs(ball.v[1]))] #D = 0.5 * (rho * C * Area * vel^2)
drag_acc = [drag_force[0] / ball.mass, drag_force[1] / ball.mass] # a = F/m
return (-drag_acc[0]),(grav_acc[1] - drag_acc[1])
这里我计算碰撞部分:
def collision(self):
pairs = combinations(range(len(self.ball_list)), 2)
for i,j in pairs:
part1 = self.ball_list[i]
part2 = self.ball_list[j]
distance = list(map(operator.sub, self.ball_list[i].pos, self.ball_list[j].pos))
if np.hypot(*distance) < self.ball_list[i].radius + self.ball_list[j].radius:
distance = part1.pos - part2.pos
rad = part1.radius + part2.radius
slength = (part1.pos[0] - part2.pos[0])**2 + (part1.pos[1] - part2.pos[1])**2
length = np.hypot(*distance)
factor = (length-rad)/length;
x = part1.pos[0] - part2.pos[0]
y = part1.pos[1] - part2.pos[1]
part1.pos[0] -= x*factor*0.5
part1.pos[1] -= y*factor*0.5
part2.pos[0] += x*factor*0.5
part2.pos[1] += y*factor*0.5
u1 = (part1.bounce*(x*part1.v[0]+y*part1.v[1]))/slength
u2 = (part2.bounce*(x*part2.v[0]+y*part2.v[1]))/slength
part1.v[0] = u2*x-u1*x
part1.v[1] = u1*x-u2*x
part2.v[0] = u2*y-u1*y
part2.v[1] = u1*y-u2*y
def check_boundaries(self, ball):
if ball.pos[0] + ball.radius > self.width:
ball.v[0] *= -ball.bounce
ball.pos[0] = self.width - ball.radius
if ball.pos[0] < ball.radius:
ball.v[0] *= -ball.bounce
ball.pos[0] = ball.radius
if ball.pos[1] + ball.radius > self.height:
self.friction = True
ball.v[1] *= -ball.bounce
ball.pos[1] = self.height - ball.radius
elif ball.pos[1] < ball.radius:
ball.v[1] *= -ball.bounce
ball.pos[1] = ball.radius
def冲突(自):
成对=组合(范围(len(self.ball_列表)),2)
对于成对的i,j:
第1部分=自球列表[i]
第2部分=自球列表[j]
距离=列表(映射(operator.sub,self.ball\u列表[i].pos,self.ball\u列表[j].pos))
如果np.hypot(*距离)自身宽度:
ball.v[0]*=-ball.bounce
ball.pos[0]=自身宽度-ball.radius
如果球位置[0]<球半径:
ball.v[0]*=-ball.bounce
ball.pos[0]=ball.radius
如果球位置[1]+球半径>自身高度:
自摩擦=真
ball.v[1]*=-ball.bounce
ball.pos[1]=自身高度-ball.radius
elif球位置[1]<球半径:
ball.v[1]*=-ball.bounce
球位置[1]=球半径
由于问题的根源是粒子动力学而不是可视化显示,请考虑将代码简化为动态部分作为一部分,这样我们可以更好地帮助你。希望改变有帮助。