-
-
Notifications
You must be signed in to change notification settings - Fork 210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot evaluate spline parameter directly in an ODESystem #2823
Comments
I think a few of these are effectively the same issue that we need to make |
Roadmap for supporting this is in #2910 |
Thanks! For future reference, after #2995, evaluating the spline directly works great: using Test
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D
using DifferentialEquations
using DataInterpolations
ts = 0.0:0.1:1.0
Fspline_t² = CubicSpline(ts .^ 2, ts) # spline for F(t) = t²
@parameters (Fspline::CubicSpline)(..)
@variables F(t) F′(t)
@named sys = ODESystem([
F ~ Fspline(t)
#F′ ~ D(F) # TODO: want to evaluate spline derivative
#F′ ~ ModelingToolkit.derivative(Fspline, t) # TODO: want to evaluate spline derivative
], t)
ssys = structural_simplify(sys)
prob = ODEProblem(ssys, [], (0.0, 1.0), [Fspline => Fspline_t²])
sol = solve(prob)
@test sol(0.5, idxs=F) ≈ 0.5^2
#@test sol(0.5, idxs=F′) ≈ 2 * 0.5 # TODO: want to evaluate spline derivative Is there also a way to evaluate the derivative of the spline, perhaps in a way that resembles any of the 3 commented lines? |
|
Not quite, unfortunately. Doing using Test, ModelingToolkit, DifferentialEquations, DataInterpolations
using ModelingToolkit: t_nounits as t, D_nounits as D
ts = 0.0:0.1:1.0
Fspline_t² = CubicSpline(ts .^ 2, ts) # spline for F(t) = t²
@parameters (Fspline::CubicSpline)(..)
@variables F(t) F′(t)
@named sys = ODESystem([
F ~ Fspline(t)
F′ ~ DataInterpolations.derivative(Fspline, t)
], t)
ssys = structural_simplify(sys)
prob = ODEProblem(ssys, [], (0.0, 1.0), [Fspline => Fspline_t²])
sol = solve(prob)
@test sol(0.5, idxs=F) ≈ 0.5^2
@test sol(0.5, idxs=F′) ≈ 2 * 0.5 fails with
It seems to call the wrong derivative function instead of the desired Symbolics derivative extension? |
Actually, this works 100%: using Test, ModelingToolkit, DifferentialEquations, DataInterpolations
using ModelingToolkit: t_nounits as t, D_nounits as D
ts = 0.0:0.1:1.0
Fspline_t² = CubicSpline(ts .^ 2, ts) # spline for F(t) = t²
value(s, t) = s(t)
derivative(s, t) = DataInterpolations.derivative(s, t)
@register_symbolic value(s::CubicSpline, t)
@register_symbolic derivative(s::CubicSpline, t)
@parameters Fspline::CubicSpline
@variables F(t) F′(t)
@named sys = ODESystem([
F ~ value(Fspline, t)
F′ ~ derivative(Fspline, t)
], t)
ssys = structural_simplify(sys)
prob = ODEProblem(ssys, [], (0.0, 1.0), [Fspline => Fspline_t²])
sol = solve(prob)
@test sol(0.5, idxs=F) ≈ 0.5^2
@test sol(0.5, idxs=F′) ≈ 2*0.5 It feels like a workaround, though. I lose the callable spline, but register two proxy functions for evaluating its value and derivative. The latter must also be typed; just |
Yes, julia> Fspline_t²(t)
CubicSpline{Vector{Float64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Float64}([0.0, 0.010000000000000002, 0.04000000000000001, 0.09, 0.16000000000000003, 0.25, 0.36, 0.48999999999999994, 0.6400000000000001, 0.81, 1.0], 0.0:0.1:1.0, Float64[], DataInterpolations.CubicSplineParameterCache{Vector{Float64}}(Float64[], Float64[]), [0.0, 0.1, 0.1, 0.09999999999999998, 0.10000000000000003, 0.09999999999999998, 0.09999999999999998, 0.09999999999999998, 0.10000000000000009, 0.09999999999999998, 0.09999999999999998], [0.0, 2.5359116022099464, 1.8563535911602187, 2.038674033149176, 1.9889502762430864, 2.0055248618784605, 1.988950276243084, 2.03867403314919, 1.856353591160198, 2.535911602209954, 0.0], false, FindFirstFunctions.Guesser{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}(0.0:0.1:1.0, Base.RefValue{Int64}(1), true), false, false)(t)
julia> D(Fspline_t²(t))
Differential(t)(CubicSpline{Vector{Float64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Float64}([0.0, 0.010000000000000002, 0.04000000000000001, 0.09, 0.16000000000000003, 0.25, 0.36, 0.48999999999999994, 0.6400000000000001, 0.81, 1.0], 0.0:0.1:1.0, Float64[], DataInterpolations.CubicSplineParameterCache{Vector{Float64}}(Float64[], Float64[]), [0.0, 0.1, 0.1, 0.09999999999999998, 0.10000000000000003, 0.09999999999999998, 0.09999999999999998, 0.09999999999999998, 0.10000000000000009, 0.09999999999999998, 0.09999999999999998], [0.0, 2.5359116022099464, 1.8563535911602187, 2.038674033149176, 1.9889502762430864, 2.0055248618784605, 1.988950276243084, 2.03867403314919, 1.856353591160198, 2.535911602209954, 0.0], false, FindFirstFunctions.Guesser{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}(0.0:0.1:1.0, Base.RefValue{Int64}(1), true), false, false)(t))
julia> D(Fspline_t²(t)) |> expand_derivatives
DataInterpolations.derivative(CubicSpline{Vector{Float64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Float64}([0.0, 0.010000000000000002, 0.04000000000000001, 0.09, 0.16000000000000003, 0.25, 0.36, 0.48999999999999994, 0.6400000000000001, 0.81, 1.0], 0.0:0.1:1.0, Float64[], DataInterpolations.CubicSplineParameterCache{Vector{Float64}}(Float64[], Float64[]), [0.0, 0.1, 0.1, 0.09999999999999998, 0.10000000000000003, 0.09999999999999998, 0.09999999999999998, 0.09999999999999998, 0.10000000000000009, 0.09999999999999998, 0.09999999999999998], [0.0, 2.5359116022099464, 1.8563535911602187, 2.038674033149176, 1.9889502762430864, 2.0055248618784605, 1.988950276243084, 2.03867403314919, 1.856353591160198, 2.535911602209954, 0.0], false, FindFirstFunctions.Guesser{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}(0.0:0.1:1.0, Base.RefValue{Int64}(1), true), false, false), t, 1) But codegen doesn't understand that |
It's also a little annoying that this doesn't work: julia> @register_symbolic DataInterpolations.derivative(interp::DataInterpolations.AbstractInterpolation, t)
julia> DataInterpolations.derivative(Fspline, t)
ERROR: type CallWithMetadata has no field t Because the registered function expects a @ChrisRackauckas should we add a method to F′ ~ DataInterpolations.derivative(Fspline, t) |
Yeah seems like we're missing a dispatch here. |
Should all nonnumeric arguments to the registered function have an additional method where they're callable, or do we want an opt-in ( |
The first would potentially cause an explosion in the number of methods, the second is a little weird API imo. I like the third but don't have a desirable syntax off the top of my head. |
I want to evaluate a spline and its derivative(s) through an
ODESystem
. This works beautifully:However, to pass different splines, I want to make it a parameter:
This fails with
ERROR: LoadError: Sym Fspline is not callable. Use @syms Fspline(var1, var2,...) to create it as a callable.
Accordingly, I tried to declare@parameters Fspline(t)::CubicSpline = Fspline_t²
instead, but it does not help. Is there a bug here?I have worked around half the problem by evaluating the spline like
F ~ spleval(x, Fspline)
through a proxy functionThis works for
F
. But it does not work forF′
, which then evaluates to e.g.Differential(t)(1.0)
. Also, it feels unnecessarily complicated, because I believe these derivative rules are already defined in DataInterpolations.jl.I really wish that the second example worked like the first, without the complicating workarounds. Is that possible?
Thanks!
The text was updated successfully, but these errors were encountered: