我无法重现运行,因为您尚未发布完整代码;我是通过目视检查来做到这一点的。
除此之外,您还没有定义变量 k, T, m,所以我不知道速度的大小。上限是否足以让粒子完全跳过碰撞?如果 v*dt 可以 > tol*2,则您完全可以错过碰撞。当我编写这样的代码时,我确保 tol 以最大变化为界。
除此之外,您的位置更新是正确的。
当你用单个粒子运行它时会发生什么?你能让它从所有三堵墙上反弹吗?当你手动编码两个粒子沿一个维度直线相向时会发生什么?我想您在加载 10000 个粒子之前测试了这些基本功能。
我不确定您的代码中的 L 是什么;我唯一合理的想法是它是盒子尺寸的上限,我在你的情节上读为 1.2^10-6。
我看到的最大问题是您的 only 碰撞检查针对的是框的 x+ 侧。你没有检查其他维度或下限(0?),也没有一个粒子与另一个粒子的比较。因此,您将获得的唯一变化是让大约一半的粒子撞击右壁 (x+) 并反转方向。除此之外,一切都会永远漂移,x 值会不断减小。
处理弹跳
首先,让您的速度和位置表达式彼此同步:它们中的每一个都应该是一个三元组(元组或列表),因此您可以将它们索引在一起。您目前将它们作为粒子列表的第二个索引(好主意),但在其他地方有三个单独的变量(坏主意)。相反,让 newVel 成为一个列表,这样您就可以简单地遍历粒子并更新:
for dim in range(3):
if r[i, dim] < tol or # hit the lower wall
r[i, dim] > b - tol: # hit the upper wall
v[i, dim] = -v[i, dim]
另外,请适当更新职位;无需涉及本地临时变量:
for dim in range(3):
r[i, dim] += v[i, dim] * dt
编写一些服务函数
编写一些通用函数通常会有所帮助,只是为了在编写主代码时将它们排除在外。目前,您正在处理很多细节,而您一次只应该担心一种技术。例如,由于您要处理粒子碰撞,因此您需要计算距离。不要将其保留在活动代码的中间;只需编写一个函数即可。例如:
def dist(a, b): # a, b are positions: triples of coordinates
return math.sqrt(sum([(a[dim] - b[dim])**2 for dim in range(3)]))
我不会评论如何实现粒子碰撞,因为你还没有表现出任何解决问题的努力,而且你还没有到攻击那个扩展的地步。首先,让这部分工作:一个粒子弹跳,然后两个粒子弹跳,然后可能是 4 个粒子,以表明您可以对任意数量的粒子进行此操作。
一旦你有了它,你就可以担心粒子碰撞了。 当你到了那个地步,好好尝试一下;如果您遇到困难,请发布一个新问题。