如何在python中创建'billiard ball'反射边界条件?

How to create 'billiard ball' reflection boundary condition in python?

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

我没有弄清楚的部分问题是当分子撞击边界表面时如何创建简单的台球型反射。我假设简单的对称反射(入角=边界出角)。我根本没有开始编写代码,因为我不知道如何处理这部分,而我知道如何处理其余部分。我知道这更像是一道数学题,但我如何在 python 中创建这些边界条件?理想情况下,我希望自己编写此功能以便我能够理解它,而不是使用可以执行此操作的预构建包。对于任何给定的分子,这就是我要寻找的。

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

请记住以下几点:

  1. 你需要一个摩擦组件,否则粒子将永远运动(能量守恒)。在这种情况下,摩擦是速度的函数,摩擦也会发生在弹跳上。

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

对于一个粒子,您不必以 t_0 的增量进行参数化处理,您可以计算截距并基本上将其放大到那里。对于多个,你将不得不计算分子间扩散和碰撞力......这是一个更难的问题,应该通过参数化来完成。

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

的碰撞

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

这次我做了一个研究流体中粒子密度的练习。最简单的事情是在两个方向上考虑一个 (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])

根据你的问题,我假设你忽略了粒子-粒子碰撞和粒子-粒子"non-superposition"

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

ħere 中描述的技巧是 "unroll" 边界框。相反,我们让粒子不受约束地移动,然后将 space 折叠到边界框内。

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()