Julia 奇型构造行为
使用MD模拟,我需要在粒子位置上强制执行周期性边界条件。最简单的方法是使用Julia 奇型构造行为,julia,Julia,使用MD模拟,我需要在粒子位置上强制执行周期性边界条件。最简单的方法是使用mod(粒子位置,长方体尺寸)。因为我在3D空间工作,所以我制作了一个3D向量类型: immutable Vec3 x::Float32 y::Float32 z::Float32 end 和mod函数: f1(a::Vec3, b::Vec3) = Vec3(mod(a.x, b.x), mod(a.y, b.y), mod(a.z, b.z)) 但是,当使用此功能时,它会出现可怕的失败: julia> a =
mod(粒子位置,长方体尺寸)
。因为我在3D空间工作,所以我制作了一个3D向量类型:
immutable Vec3
x::Float32
y::Float32
z::Float32
end
和mod函数:
f1(a::Vec3, b::Vec3) = Vec3(mod(a.x, b.x), mod(a.y, b.y), mod(a.z, b.z))
但是,当使用此功能时,它会出现可怕的失败:
julia> a = Vec3(11,-2,5)
Vec3(11.0f0,-2.0f0,5.0f0)
julia> b = Vec3(10,10,10)
Vec3(10.0f0,10.0f0,10.0f0)
julia> f1(a,b)
Vec3(5.0f0,10.0f0,NaN32)
如果我只返回一个元组,它就可以正常工作:
f2(a::Vec3, b::Vec3) = mod(a.x,b.x), mod(a.y,b.y), mod(a.z,b.z)
julia> f2(a,b)
(1.0f0,8.0f0,5.0f0)
为了测试它是否不喜欢类型构造函数中的mod,我尝试了一种更详细的方法:
function f3(a::Vec3, b::Vec3)
x = mod(a.x,b.x)
y = mod(a.y,b.y)
z = mod(a.z,b.z)
return Vec3(x,y,z)
end
julia> f3(a,b)
Vec3(5.0f0,10.0f0,NaN32)
然后,打印中间产物的版本:
function f4(a::Vec3, b::Vec3)
x = mod(a.x,b.x)
y = mod(a.y,b.y)
z = mod(a.z,b.z)
println(x, " ", y, " ", z)
return Vec3(x,y,z)
end
julia> f4(a,b)
1.0 8.0 5.0
Vec3(1.0f0,8.0f0,5.0f0)
出于某种原因,它现在起作用了。我已经在多台计算机上尝试过了,每台都有相同的结果。如果有人能解释这一点,我将非常感激。Julia版本是:版本0.3.2(2014-10-21 20:18 UTC)
什么有效,什么无效
我认为这可能是一个bug,甚至可能是一个LLVM bug。我能够在0.3.0版上重现您的错误,但在0.4版上无法重现。像你一样,我也在中间插入了一个打印语句,得到了正确的结果。p>
此外,我发现两者都比较简单
f1(a::Vec3, b::Vec3) = Vec3(mod(a.x,b.x),mod(a.y,b.y),1)
julia> f1(a,b)
Vec3(1.0f0,8.0f0,1.0f0)
和越复杂
julia> f1(a::Vec3, b::Vec3) = Vec3(mod(a.x,b.x),mod(a.y,b.y),mod(a.z,b.z) + 1)
f1 (generic function with 1 method)
julia> f1(a,b)
Vec3(1.0f0,8.0f0,6.0f0)
这两种方法都有效,但下面的方法不行
julia> f1(a::Vec3, b::Vec3) = Vec3(mod(a.x,b.x),mod(a.y,b.y),mod(a.z,b.z))
f1 (generic function with 1 method)
julia> f1(a,b)
Vec3(5.0f0,10.0f0,NaN32)
到LLVM
LLVM源代码看起来也正确。加载每个输入Vec3参数的各个部分mod使用(fadd、frem、fadd)获取参数,然后将结果存储在结果中
julia> code_llvm(f1,(Vec3,Vec3))
define %Vec3 @"julia_f1;20242"(%Vec3, %Vec3) {
top:
%2 = extractvalue %Vec3 %1, 0, !dbg !1733
%3 = extractvalue %Vec3 %1, 1, !dbg !1733
%4 = extractvalue %Vec3 %1, 2, !dbg !1733
%5 = extractvalue %Vec3 %0, 0, !dbg !1733
%6 = frem float %5, %2, !dbg !1733
%7 = fadd float %2, %6, !dbg !1733
%8 = frem float %7, %2, !dbg !1733
%9 = insertvalue %Vec3 undef, float %8, 0, !dbg !1733
%10 = extractvalue %Vec3 %0, 1, !dbg !1733
%11 = frem float %10, %3, !dbg !1733
%12 = fadd float %3, %11, !dbg !1733
%13 = frem float %12, %3, !dbg !1733
%14 = insertvalue %Vec3 %9, float %13, 1, !dbg !1733
%15 = extractvalue %Vec3 %0, 2, !dbg !1733
%16 = frem float %15, %4, !dbg !1733
%17 = fadd float %4, %16, !dbg !1733
%18 = frem float %17, %4, !dbg !1733
%19 = insertvalue %Vec3 %14, float %18, 2, !dbg !1733, !julia_type !1734
ret %Vec3 %19, !dbg !1733
本机代码错误?
但是本机指令看起来不正确,XMM2被移动到XMM0,之后XMM0被用作addss的操作数,但是XMM2似乎没有初始化
julia> code_native(f1,(Vec3,Vec3))
.section __TEXT,__text,regular,pure_instructions
Filename: none
Source line: 1
push RBP
mov RBP, RSP
sub RSP, 16
movss DWORD PTR [RBP - 4], XMM5
Source line: 1
movaps XMM0, XMM2
movaps XMM1, XMM5
movabs RAX, 140735600044048
call RAX
movss XMM1, DWORD PTR [RBP - 4]
addss XMM0, XMM1
movabs RAX, 140735600044048
add RSP, 16
pop RBP
jmp RAX
更新:
由于可能出现LLVM错误而提交。这在主分支(32位Fedora 19)上正常工作。还有,奇怪的是,在模位置约束下,能量守恒是如何保持的?@rickhg12hs RE能量守恒:速度在边界交叉处是守恒的,所以动能是守恒的。势能是守恒的,每个粒子与该粒子最近的“图像”相互作用-假设我们有两个粒子,靠近盒子的相对面。它们的相互作用就好像在边界的另一边有一个粒子,而不是在盒子的另一边。这样,本地环境在移动时不会发生变化。这个盒子可以让我们模拟一个系统的中间,而不需要涉及到表面条件的问题。啊,好的。有点像游戏《小行星》中的太空船,对吧?8-)