Julia 从常微分方程问题中提取导数(du/dt)

Julia 从常微分方程问题中提取导数(du/dt),julia,differential-equations,differentialequations.jl,Julia,Differential Equations,Differentialequations.jl,我正在解决多个ODE问题。这里我需要解(u)和解的导数(du)。对于较小的颂歌,我可以做以下几点 using DifferentialEquations function SB(du,u,p,t) du[1]=@. u[2] du[2]=@. ((-0.5*u[2]^2)*(3-u[2]/(p[4]))+(1+(1-3*p[7])*u[2]/p[4])*((p[6]-p[5])/p[2]+2*p[1]/(p[2]*p[9]))*(p[9]/u[1])^(3*p[7])-2*p

我正在解决多个ODE问题。这里我需要解(u)和解的导数(du)。对于较小的颂歌,我可以做以下几点

using DifferentialEquations


function SB(du,u,p,t)
    du[1]=@. u[2]
    du[2]=@. ((-0.5*u[2]^2)*(3-u[2]/(p[4]))+(1+(1-3*p[7])*u[2]/p[4])*((p[6]-p[5])/p[2]+2*p[1]/(p[2]*p[9]))*(p[9]/u[1])^(3*p[7])-2*p[1]/(p[2]*u[1])-4*p[3]*u[2]/(p[2]*u[1])-(1+u[2]/p[4])*(p[6]-p[5]+p[10]*sin(2*pi*p[8]*t))/p[2]-p[10]*u[1]*cos(2*pi*p[8]*t)*2*pi*p[8]/(p[2]*p[4]))/((1-u[2]/p[4])*u[1]+4*p[3]/(p[2]*p[4]))
end

R0=2e-6
ps=250e3
f=2e6


u0=([R0 0])
tspan=(0,100/f)

p=[0.0725, 998, 1e-3,1481, 0, 1.01e5,7/5,f, R0, ps]

prob = ODEProblem(SB,u0,tspan,p)


@time u = solve(prob,Tsit5(),alg_hints=[:stiff],saveat=0.01/f,reltol=1e-8,abstol=1e-8)
t=u.t
u2=@. ((-0.5*u[2,:]^2)*(3-u[2,:]/(p[4]))+(1+(1-3*p[7])*u[2,:]/p[4])*((p[6]-p[5])/p[2]+2*p[1]/(p[2]*p[9]))*(p[9]/u[1,:])^(3*p[7])-2*p[1]/(p[2]*u[1,:])-4*p[3]*u[2,:]/(p[2]*u[1,:])-(1+u[2,:]/p[4])*(p[6]-p[5]+p[10]*sin(2*pi*p[8]*t))/p[2]-p[10]*u[1,:]*cos(2*pi*p[8]*t)*2*pi*p[8]/(p[2]*p[4]))/((1-u[2,:]/p[4])*u[1,:]+4*p[3]/(p[2]*p[4]))

其中u2在SB函数中基本上是du[2]。这很快变得不切实际,因为我的ODE的大小在增长(>500个耦合ODE,矩阵>500X500)。有没有办法要求Differentialsequations.jl软件包(或任何其他方式)在求解ODE时导出du[i]s?我了解到DifferencesSensitity.jl软件包能够提供du/dps来检查模型对p的敏感性。是否有类似于提取du/dts的内容?

我将同时使用两种不同的组件。首先,当您使用非常大的ODE时,您只需要保存解决方案的特定部分,或者简化部分。为此,
SavingCallback
非常有用

例如,以下内容解决了一个ODE,并仅在每个步骤保存解决方案的跟踪和范数:

using DiffEqCallbacks, OrdinaryDiffEq, LinearAlgebra
prob = ODEProblem((du,u,p,t) -> du .= u, rand(4,4), (0.0,1.0))
saved_values = SavedValues(Float64, Tuple{Float64,Float64})
cb = SavingCallback((u,t,integrator)->(tr(u),norm(u)), saved_values)
sol = solve(prob, Tsit5(), callback=cb)
现在你可以用它来保存你需要的东西。第二部分是使用
积分器
获得导数。你可以看到
get_du可用于提取当前(已计算)导数:

此外,还可以利用积分器上的插值
integrator(t,Val{1})
将给出当前
t

@ChrisRackauckas时溶液的一阶导数 我确实需要定义要求解的解算器的每个时间步骤

抓住你!(out,integrator)给了我一个数组,其中所有的点都有相同的值。 我在做一个梦吗 哪里出错了

prob=ODEProblem(SB,u0,tspan,p)
Rdot=零(50001,2)
u=init(prob,SSPRK22(),dt=1e-9,reltol=1e-8,absol=1e-8)
解决(u)
抓住你!(奥尔多,美国)
U=U.sol

基本上,第二个输出(du[2])的导数必须等于我在上一篇文章中定义的u2。为什么不调用
SB
函数并从返回向量中提取所需的分量呢?这也是可能的。然而,我不想在这个过程中重复同样的操作两次。我假设ODE解算器在解决问题时确实计算du[I]s。我希望避免重复相同的过程,并要求解算器将du[I]s与u[I]s一起导出。不,您并不是在真正重复计算,因为内部步骤与输出值无关,输出是从步骤数据中插值的。但是,将导数计算为插值多项式的导数通常更便宜。为了继续讨论,请使用or连接(首选,DiffEq通道是#DiffEq桥接的)