# 准备初始相空间坐标
zvec = randn(10000)*0.12
δvec = randn(10000)*1.06e-3
const restenergy = 0.511e6 # [eV]
nturns = 10001 # 圈数
struct Par
v1::Float64
r::Float64
ϕs::Float64
ϕ2s::Float64
h1::Int64
h::Int64
circum::Float64
centerenergy::Float64
αc::Float64
end
Base.broadcastable(x::Par) = Ref(x)
function revolution(z, δ, p::Par)::Tuple{Float64,Float64}
δ = δ + p.v1 / p.centerenergy * (sin(p.ϕs - 2 * p.h1 * π / p.circum * z ) - sin(p.ϕs) + p.r * sin(p.ϕ2s - 2 * p.h1 * p.h * π / p.circum * z) - p.r * sin(p.ϕ2s))
η = p.αc - 1 / (p.centerenergy * (1 + δ) / restenergy)^2
z = z - η * δ * p.circum
z, δ
end
function revolution(z, δ, k1, k2, c1, c2, c3, p)::Tuple{Float64,Float64}
δ = δ + c1 * (sin(p.ϕs - k1 * z ) + p.r * sin(p.ϕ2s - k2 * z) - c2)
η = p.αc - c3 / (1+δ)^2
z = z - η * δ * p.circum
z, δ
end
function main!(zvec::Vector{Float64}, δvec::Vector{Float64}, nturns, p::Par)
k1 = 2 * p.h1 * π / p.circum
k2 = 2 * p.h1 * p.h * π / p.circum
γ = p.centerenergy/restenergy
c1 = p.v1 / p.centerenergy
c2 = sin(p.ϕs) + p.r * sin(p.ϕ2s)
c3 = 1/γ^2
@inbounds for i = 1:size(zvec, 1)
z, δ = zvec[i], δvec[i]
@inbounds for j = 1:nturns
z, δ = revolution(z, δ, k1, k2, c1, c2, c3, p) # 这个减少了参数的重复计算
# z, δ = revolution(z, δ, p) # 这个参数重复计算很费时间
end
zvec[i], δvec[i] = z, δ
end
end
p = Par(3.6395053705870048e+06, 0.1801760487622639, 2.1575815005097385, 6.0620746573056303, 756, 3, 1360.4, 6e9, 0.0000156)
@btime main!(zvec, δvec, nturns, p)
我按照物理公式,定义了函数:
revolution(z, δ, p)
运行时间:
8.505 s (0 allocations: 0 bytes)
8.486 s (0 allocations: 0 bytes)
8.603 s (0 allocations: 0 bytes)
离MATLAB的最快3.7s
差了很多,甚至比矢量化的3.973/3.991
Julia写法慢很多。
我猜测主要是“标量优先”写法中,重复的参数计算太多。于是定义了
revolution(z, δ, k1, k2, c1, c2, c3, p)
这个函数,主要是把能先算的都算好了。然而时间为
4.777 s (0 allocations: 0 bytes)
4.880 s (0 allocations: 0 bytes)
4.889 s (0 allocations: 0 bytes)
4.887 s (0 allocations: 0 bytes)
可以看到,重复的参数计算确实影响很大,但是离矢量化写法还是有不小的差距。
感觉,在写标量函数的时候,“参数的重复计算”和“内存的调用”之间存在一种取舍。部分情况下,你“标量优先”做出的无用重复计算开销,会大于“加载内存”开销。
有没有开发者大佬能把Julia这个问题给解决一下的……
另一个问题,我用@code_warntype
看到
julia> @code_warntype main!(zvec, δvec, nturns, p)
Variables
#self#::Core.Const(main!)
zvec::Vector{Float64}
δvec::Vector{Float64}
nturns::Int64
p::Par
@_6::Union{Nothing, Tuple{Int64, Int64}} # 看这儿
ηvec::Vector{Float64}
i::Int64
Body::Nothing
# 以下忽略
上面出现了类似警告的颜色,其中有个Nothing
是为什么呢?如何消除呢?