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