【问题标题】:How to create 'billiard ball' reflection boundary condition in python?如何在 python 中创建“台球”反射边界条件?
【发布时间】:2019-03-06 18:01:39
【问题描述】:

根据 Erwin Schrodinger(在什么是生命?)中,扩散可以完全用粒子的随机运动来解释。我想通过创建一个程序来测试这一点,该程序创建一个封闭容器中“气体分子”扩散的时间步长可视化。初始条件将有两个分区,一个具有低浓度,一个具有高浓度。在 t0 之后,隔板被移除,气体被允许扩散。我想使用的唯一机制是向每个分子添加位移随机向量。初始条件如下所示。

我不知道的部分问题是如何在分子撞击边界表面时创建简单的台球类型反射。我假设简单的对称反射(角度输入=边界处的角度)。我根本没有开始编写代码,因为我不知道如何处理这部分,而我知道如何完成其​​余部分。我知道这更像是一个数学问题,但是如何在 python 中创建这些边界条件?理想情况下,我希望自己编写这个功能以便我能理解它,而不是使用可以做到这一点的预构建包。对于任何给定的分子,这就是我正在寻找的东西。

最终,我真正需要的是:给定初始位置 (x1,y2)、向量幅度 v、角度 theta 以及盒子大小和位置,分子的最终静止位置是什么 (x2, y2)。

【问题讨论】:

  • 如果对你来说都是一样的,那么做一个“正确”的角度实际上要容易得多。例如,请参阅here
  • 对我来说都一样!谢谢!这只是表明我对这个问题知之甚少。
  • 尽管如此,我还是不能放弃。我希望位移的向量长度是连续的,而不是整数,并且我需要知道每个时间步长的点数组中每个点的新位置。不过谢谢你的回复。它肯定让我更接近。

标签: python numpy physics billiards


【解决方案1】:

您不需要计算反射角,只需将问题分解为两种:一种用于x,一种用于y。在这两种情况下,您都需要粒子在超出边界时“返回”。

这一次我已经完成了一项研究流体中粒子密度的练习。最简单的事情是考虑两个方向的 (0, 1) 边界。下面的代码应该做到这一点(提示:正确使用abs 将创建等效的反射):

x0 = [.1, .9]
delta = [-0.2, 0.3]
x1 = [(1-abs(abs(xi + di)-1)) for xi, di in zip(x0, delta)]
print(x1)
# 0.1, 0.8
#or using numpy:
x1 = 1-np.abs(np.abs(np.asarray(x0) + np.asarray(delta))-1)
print(x1)
>> [0.09999999999999998, 0.8]
   array([0.1, 0.8])

我从您的问题中假设您忽略了粒子-粒子碰撞和粒子-粒子“非叠加”

【讨论】:

  • 是的,我一开始会尽量保持简单。无摩擦、无碰撞的球体,以随机的初始速度和方向开始,并保持其方向。稍后添加碰撞和摩擦可能会很有趣,但我真的只想制作一个模拟扩散的可视化,但只处理粒子运动。当然,其他效果会产生很大的不同,但我认为视觉效果仍然可以。
  • 这段代码需要一些递归来进行多次反射,对吧?
  • Hrmmm,或者我想你可以保持时间步长非常小,这样每一步都不会发生太多的运动。然后你只需更新粒子在每个时间步的行进方向,这将在反弹时发生变化。
  • 关注小空间“增量”而不是时间步长。如果您的 delta 小于 1(应该如此),则您不能获得超过一次的反射。使用类似np.clip(np.random.normal(mu, sigma), -0.99, 0.99)) 的东西。在每一步计算 x 和 y 中的平均位置,并绘制它与步数的关系:您应该看到它移动到 (0.5, 0.5)。
  • 谢谢!这就是我的想法。我可能会使用更小的时间增量,因为您可能会在拐角处获得一些双重反射,您的一些台球可能会逃逸。
【解决方案2】:

这是一个简单的实现。我只每十步更改一次运动矢量,这样就可以直观地检查边界反射。更新运动矢量时,粒子会闪烁红色。

ħere 描述的技巧是“展开”边界框。相反,我们让粒子不受约束地移动,然后将空间折叠到边界框内。

import numpy as np
import pylab
from matplotlib.animation import FuncAnimation

xy = np.random.uniform(-1, 1, (2, 200))
xy[0, :160] = np.abs(xy[0, :160])
xy[0, 160:] = -np.abs(xy[0, 160:])
xy += 1

f, a = pylab.subplots()
pxy, = pylab.plot(*xy, 'o')

def init():
    a.set_xlim(0, 2)
    a.set_ylim(0, 2)
    return pxy,

def update(frame):
    global inc, xy
    if frame % 1 < 0.01:
        inc = np.random.normal(0, 0.01, xy.shape)
        pxy.set_markerfacecolor('red')
    elif frame % 1 < 0.11:
        pxy.set_markerfacecolor('blue')        
    xy += inc
    fxy = np.abs((xy+2)%4-2)
    pxy.set_data(*fxy)
    return pxy,

anim = FuncAnimation(f, update, frames=np.arange(1200) / 10,
                     init_func=init, blit=True)

pylab.show()

【讨论】:

  • 这似乎很好地理解了主要思想。再次给粒子每十步随机运动的想法是什么?这正是我想要创建的视觉效果,只是我想象粒子继续沿着它们的轨迹运行,直到它们撞到墙上。我可以将增量设置为固定吗?
  • 我不是物理学家,但我认为公认的方法实际上是在每个时间步生成一个新的位移向量。一种思考方式是粒子碰撞太多,以至于位移本质上是随机的,位移的统计数据是温度的函数。
  • 谢谢。他的回答非常有帮助,并解决了我正在研究的整个想法,但对我来说,整个想法是通过从头开始构建模型来了解物理学。 @Mstaino 的回答给了我一个简短的可用 sn-p 代码,我可以用它开始构建其余的功能。但我也非常感谢您的回复,因为我可能会在最终产品中使用它的许多组件。
【解决方案3】:

所以要记住几件事:

  1. 您需要一个摩擦组件,否则粒子将永远保持移动(能量守恒)。在这种情况下,摩擦力是速度的函数,反弹时也会发生摩擦力。

  2. 如果它只是一个粒子,你可以通过定义边界框来计算它,比如 x 介于 0 和 5 之间,y 介于 0 和 3 之间。然后,您可以通过插入 x = 5 值,然后在直线方程中求解 y 来计算与墙的截距。

对于一个粒子,您不必以 t_0 为增量进行参数化处理,您可以计算截距并将其放大到那里。对于多个,您必须计算分子间的扩散力和碰撞力……这是一个更难的问题,应该以参数方式完成。

您必须计算碰撞,即两个分子的中心彼此相距 2* 半径时,然后进行 conserves momentum 的碰撞。

【讨论】:

  • 这些考虑都很好,我稍后会考虑,但我只是想创建一个简单的可视化,以过于简单的方式解释扩散现象,看看是否真的有效,因为薛定谔在他的书中声称它就是这么简单。它不会是一个很好的模型来说明会发生什么或时间表是什么样的,但我认为它会作为一种教学电影给出正确的基本概念。
猜你喜欢
  • 2013-11-23
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 2013-09-02
  • 2018-12-20
  • 1970-01-01
  • 2020-11-02
  • 2023-03-10
相关资源
最近更新 更多