Julia中微分方程的循环生成函数
以洛伦兹为例() 如果我必须在循环中生成方程,我会尝试在循环中串联字符串,然后将它们转换为函数。在Matlab中,这是可行的()。有了朱莉娅,我迷路了(这实际上是我在朱莉娅身上尝试的第一件事)。 我的第一次尝试是:Julia中微分方程的循环生成函数,julia,differentialequations.jl,Julia,Differentialequations.jl,以洛伦兹为例() 如果我必须在循环中生成方程,我会尝试在循环中串联字符串,然后将它们转换为函数。在Matlab中,这是可行的()。有了朱莉娅,我迷路了(这实际上是我在朱莉娅身上尝试的第一件事)。 我的第一次尝试是: 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[
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
不工作(u未定义;后面是可能由于在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
...
这里的
U
是U[i]
的和(我从1到M
;应该可以在变量中设置M
的值)。在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
请注意,这甚至不需要对长度的引用,因此它将适用于任何大小的u
和du
。因此创建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
(当然也要确保你自己)。如果不需要,你真的应该避免使用
eval
。你这里的问题是:(A)eval在全球范围内,(B)你不能将变量转义到表达式中。但这绝对不是解决问题的正确方法。你能解释一下你想做什么,这样我们才能给出一个更合适的解决方案吗?我猜你可以这样做,但你只考虑这样做,因为有一个MATLAB大脑,有一个更简单的方法你没有尝试过的方法。我正在求解一个2N个方程组的系统,每个方程组都有很长的表达式,但结构相似,可以通过for循环得到……N可能会根据需要的精度而改变。使用for循环,我不必重写方程组。为什么不在函数中循环?方程组的数量应该ld具有2N=长度(u)
所以你可以在函数中使用它。对,每个方程中都有一个求和项,需要我在u上循环。这一点也不错。Julia中的循环在性能上类似于C。除了一些编译器优化(如果你展开整个方程,理论上可能会发生)之外,循环会给你full性能(事实上,编译器也会对循环进行许多优化)。你不应该不必要地避免这种情况。但是如果你真的想避免这种情况,那么在Val{N}上调度的生成函数上使用闭包
可以,但我强烈建议先编写循环。避免在MATLAB中使用循环,但不要在Julia中使用循环!
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