-
-
Notifications
You must be signed in to change notification settings - Fork 228
Open
Description
There should be official support for the concept of "inputs" to a model. I have hacked together the following code to provide a start for the following features/requirements:
- provide a way to define model inputs so they are distinguishable from normal "unknowns". For example,
inputs(sys::System)
should list the inputs. Also an@inputs
macro should be available to define model inputs. Input variables should be set directly and shouldn't change with time unless directed to, i.e. an inputx
has the equationD(x) ~ 0
- provide an API so that inputs are separate from a problem, such that one can call
solve(prob, inputs)
. This way, if inputs change, theODEProblem
can remain the same. - provide an API so that inputs can be set in an indeterminate form with
set_input(integrator, var::Num, value::Number)
In the below example is a start to this feature request, the solve(prob, inputs)
and set_input(integrator, var, value)
are demonstrated. What's missing is the ability to influence initialization of the inputs from data. As can be seen, this provides the ability to run the same model in determinate and indeterminate forms and get the same result.
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D
using OrdinaryDiffEq
using Plots
using DiffEqBase: reeval_internals_due_to_modification!, savevalues!
using Test
struct Input
var::Num
data::Vector{Float64}
time::Vector{Float64}
end
function DiffEqBase.solve(prob::SciMLBase.AbstractDEProblem, inputs::Union{Input, Vector{Input}}, args...; kwargs...)
tstops = Float64[]
callbacks = DiscreteCallback[]
if !isa(inputs, Vector)
inputs = [inputs]
end
for input::Input in inputs
tstops = union(tstops, input.time)
condition(u,t,integrator) = any(t .== input.time)
function affect!(integrator)
i = findfirst(integrator.t .== input.time)
integrator[input.var] = input.data[i]
end
callback = DiscreteCallback(condition, affect!)
push!(callbacks, callback)
end
return solve(prob, args...; tstops, callback=CallbackSet(callbacks...), kwargs...)
end
function set_input!(integrator, var, value)
savevalues!(integrator)
integrator[var] = value
reeval_internals_due_to_modification!(integrator, false)
savevalues!(integrator, true)
end
# -----------------------------------------
# ----- example ---------------------------
# -----------------------------------------
vars = @variables begin
# inputs
x(t) = 1
# states
y(t) = 0
end
eqs = [
# inputs
D(x) ~ 0
# equations
D(y) ~ x
]
@mtkcompile sys = System(eqs, t, vars, [])
prob = ODEProblem(sys, [], (0, 4))
input = Input(sys.x, [2,3,4], [1,2,3])
sol = solve(prob, input)
plot(sol; idxs=[sys.x, sys.y])
integrator = init(prob)
for i=1:4
# set inputs
set_input!(integrator, sys.x, i)
# step
step!(integrator, 1.0, true)
# outputs
integrator[sys.y] # |> f
end
p1= plot(integrator.sol; idxs=sys.x, label="indeterminate (x)")
plot!(sol; idxs=sys.x, label="determinate (x)")
p2 = plot(integrator.sol; idxs=sys.y, label="indeterminate (y)")
plot!(sol; idxs=sys.y, label="determinate (y)")
plot(p1, p2; layout=(2,1))

Metadata
Metadata
Assignees
Labels
No labels