在 Julia 中模拟粒子碰撞

simulating the collision of particles in Julia

我想模拟盒子内粒子的碰撞。
更具体地说,我想创建一个函数(我们称之为 collision!),它会在每次交互后更新粒子速度,如图所示。

我定义的粒子(半径等于1)如下:

mutable struct Particle
    pos :: Vector{Float64}
    vel :: Vector{Float64}
end
p = Particle( rand(2) , rand(2) )
# example for the position
p.pos
> 2-element Vector{Float64}:
  0.49339012018408135
  0.11441734325871078

以及碰撞

function collision!(p1::Particle, p2::Particle)
     
    # ... #
    
    return nothing
end

主要思想是当两个粒子碰撞时,它们“交换”平行于粒子中心的速度矢量(矢量 n 帽)。
为此,需要将速度矢量转换为碰撞法线 (n hat) 的正交基。

然后交换平行分量,在原来的基础上旋转回来

我想我的数学是正确的,但我不确定如何在代码中实现它

请注意,我根本没有检查数学 ,您提供的 2d 案例的一种实现可能是:

struct Particle
    pos :: Vector{Float64}
    vel :: Vector{Float64}
end

p1 = Particle( rand(2) , rand(2) )
p2 = Particle( rand(2) , rand(2) )

function collision!(p1::Particle, p2::Particle)
    # Find collision vector
    n = p1.pos - p2.pos
    # Normalize it, since you want an orthonormal basis
    n ./= sqrt(n[1]^2 + n[2]^2)
    # Construct M
    M = [n[1] n[2]; -n[2] n[1]]
    # Find transformed velocity vectors
    v1ₙ = M*p1.vel
    v2ₙ = M*p2.vel
    # Swap first component (or should it be second? Depends on how M was constructed)
    v1ₙ[1], v2ₙ[1] = v2ₙ[1], v1ₙ[1]
    # Calculate and store new velocity vectors
    p1.vel .= M'*v1ₙ
    p2.vel .= M'*v2ₙ
    return nothing
end

几点:

  1. 你不需要mutable struct;只是一个普通的 struct 就可以正常工作,因为 Vector 本身是可变的
  2. 此实现有 很多 多余的分配,如果您可以就地工作或在堆栈上工作可能更可行(例如,使用一些 StaticArrays sort 而不是基本数组作为位置和速度向量的基础)。如果您只是制作另一个结构(比如“CollisionEvent”),它为 M、n、v1n 和 v2n 保存预分配的缓冲区,并将其也传递给 collision! 函数,就地实际上可能也不会太难。
  3. 虽然我没有深入研究,但也许可以在 https://github.com/JuliaMolSim/Molly.jl
  4. 这样的分子动力学包中找到对此类碰撞有用的参考实现