I am trying to create a control function from a ModelingToolkit.jl model:
f(x, u, p) → x_next
I want to do that by re-initializing the integrator with the current state x and input u, and then stepping the integrator:
function f!(xnext, x, u, _, p) # inplace version of f(x, u, p)
(integrator, set_x, set_u, _) = p
set_x(integrator, x)
set_u(integrator, u)
step!(integrator)
xnext .= integrator.u # integrator.u is the integrator state, called x in the function
nothing
end
How can I reinitialize the integrator in a non-allocating way? I am using setu
and setp
now, but there seems to be some caches in the integrator that are not being reset, as xnext
is not consistent when calling the control function multiple times with the same inputs:
xnext = [1.000003514961648, 0.9999867038583831]
xnext = [1.0000016858995648, 0.9999936227203033]
xnext = [1.0000168585118323, 0.9999362274452563]
xnext = [1.0001685367381081, 0.999362298719702]
xnext = [1.0016805307279277, 0.9936254586572106]
And using reinit!(integrator)
works, but that uses over 1000 allocations, and performance is critical for this function.
Here is the MWE I created:
using ModelingToolkit, OrdinaryDiffEq
using ModelingToolkit: D_nounits as D, t_nounits as t, setu, setp, getu
Ts = 0.1
@mtkmodel Pendulum begin
@parameters begin
g = 9.8
L = 0.4
K = 1.2
m = 0.3
τ = 0.0 # input
end
@variables begin
θ(t) = 0.0 # state
ω(t) = 0.0 # state
y(t) # output
end
@equations begin
D(θ) ~ ω
D(ω) ~ -g/L*sin(θ) - K/m*ω + τ/m/L^2
y ~ θ * 180 / π
end
end
@mtkbuild mtk_model = Pendulum()
prob = ODEProblem(mtk_model, nothing, (0.0, Ts))
integrator = OrdinaryDiffEq.init(prob, Tsit5(); dt=Ts, abstol=1e-8, reltol=1e-8, save_on=false, save_everystep=false)
set_x = setu(mtk_model, unknowns(mtk_model))
set_u = setp(mtk_model, [mtk_model.τ])
get_h = getu(mtk_model, [mtk_model.y])
p = (integrator, set_x, set_u, get_h)
function f!(xnext, x, u, _, p)
(integrator, set_x, set_u, _) = p
set_x(integrator, x)
set_u(integrator, u)
step!(integrator)
xnext .= integrator.u # integrator.u is the integrator state, called x in the function
nothing
end
for i in 1:10
local xnext = zeros(2)
f!(xnext, ones(2), 1.0, nothing, p)
@show xnext
end
for i in 1:10
local xnext = zeros(2)
f!(xnext, zeros(2), 1.0, nothing, p)
@show xnext
end