在Julia中为DifferentialEquations循环生成函数

时间:2017-12-22 07:26:35

标签: julia differentialequations.jl

以Lorenz为例(JuliaDiffEq github

function lorenz(t,u,du)
    du[1] = 10.0*(u[2]-u[1])
    du[2] = u[1]*(28.0-u[3]) - u[2]
    du[3] = u[1]*u[2] - (8/3)*u[3]
end

如果我必须在循环中生成方程式,我会尝试在循环中连接字符串,然后将它们转换为函数。使用Matlab可以实现(str2func)。朱莉娅,我迷路了(这实际上是我在朱莉娅尝试的第一件事)。 我的第一次尝试是:

function lorenz(t,u,du)
    Ex = :(du[1] = 10.0*(u[2]-u[1]))
    eval(ex)
    du[2] = u[1]*(28.0-u[3]) - u[2]
    du[3] = u[1]*u[2] - (8/3)*u[3]
end

不起作用(未定义;后面跟着可能来自prob = ODEProblem(lorenz,u0,tspan)中使用此函数的错误行 有人可以指出我正确的方向。 第一个问题是我无法找到函数进入ODEProblem时会发生什么。有人请指导我到哪里可以找到朱莉娅的功能。

<小时/>

EDIT1

我刚试过

ex = quote
function lorenz(t,u,du)
    du[1] = 10.0*(u[2]-u[1])
    du[2] = u[1]*(28.0-u[3]) - u[2]
    du[3] = u[1]*u[2] - (8/3)*u[3]
end
end
eval(ex)

这很有效。所以我知道这种方法有效。但是我担心我可能偶然发现了'某种方式';不是首选的方式。如果有人更熟悉Julia,请发表评论。

<小时/>

EDIT2

需要解决的方程组的一个例子:

du[1] = u[1] + v[1] + U
dv[1] = v[1] + U

du[2] = u[2] + v[2] + U
dv[2] = v[2] + U

...

此处Uu[i]的总和(我从1到M;应该可以在变量中设置M的值。)

1 个答案:

答案 0 :(得分:0)

在MATLAB中,你应该尽量避免循环。在Julia中,优化了这种环境中的循环,因此没有理由避免它。编写此函数的简便方法是:

function f(t,u,du)
  U = sum(u)
  for i in eachindex(u)
    du[i] = u[i] + v[i] + U
    dv[i] = v[i] + U
  end
end

请注意,这甚至不需要对长度的引用,因此它适用于任何大小udu。因此,创建ODEProblem(f,u0,tspan),其中u0是您的大小M数组,并且您将会很好。

我们可以使用一些性能宏来进一步优化这一点。 @inbounds关闭边界检查,所以做起来很不错

function f(t,u,du)
  U = sum(u)
  @inbounds for i in eachindex(u)
    du[i] = u[i] + v[i] + U
    dv[i] = v[i] + U
  end
end

在某些情况下,如果循环足够长,我们可能需要强制@simd

function f(t,u,du)
  U = sum(u)
  @simd for i in eachindex(u)
    @inbounds du[i] = u[i] + v[i] + U
    @inbounds dv[i] = v[i] + U
  end
end

或者如果真的很长,多线程:

function f(t,u,du)
  U = sum(u)
  Threads.@threads for i in eachindex(u)
    @inbounds du[i] = u[i] + v[i] + U
    @inbounds dv[i] = v[i] + U
  end
end

(当然,请确保enable threading)。