Closed ayadlin closed 5 years ago
Sorry, i left the # and know this looks awful
You didn't pass the callbacks or the tstops to the cost function?
cost_function = build_loss_objective(prob,Tsit5(),L2Loss(t,data),
callback = cb, tstops = 2:2:10,
maxiters=10000,verbose=false)
all it's doing is feeding those args to the internal solve.
Thanks for getting back to me, and doing so qucikly - I passed the cost function as you suggested , but this result in an error when I run the next step of the code (attached below), the error doesn't happen if I leave the callback out - thats one of the reasons I am confused about how to deal with the parameter estimation :
Thanks
# Code that fails when call back is included in cost_function
# Checking parameters for cost function:
vals =collect(range(0.0±0,stop=1.1,length=100))
using Plots; plotly()
vals
[cost_function(i) for i in vals]
plot(vals,[cost_function(i) for i in vals],yscale=:log10,
xaxis = "Parameter", yaxis = "Cost", title = "1-Parameter Cost Function",
lw = 3)
UndefRefError: access to undefined reference (StackTrace belolw) - The alternative result is that my kernel (in jupyter or VSCode crashes, although I am never close to 100% usage of CPU or RAM (<= 50%)
Stacktrace: [1] getindex at .\array.jl:730 [inlined] [2] getindex at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.1\LinearAlgebra\src\adjtrans.jl:130 [inlined] [3] (::L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing})(::ODESolution{Measurement{Float64},2,Array{Array{Measurement{Float64},1},1},Nothing,Nothing,Array{Float64,1},Array{Array{Array{Measurement{Float64},1},1},1},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Measurement{Float64},getfield(Main, Symbol("##399")){getfield(Main, Symbol("##223#227")),getfield(Main, Symbol("##224#228")),getfield(Main, Symbol("##225#229")),Nothing,Nothing,getfield(Main, Symbol("##226#230")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,OrdinaryDiffEq.InterpolationData{getfield(Main, Symbol("##399")){getfield(Main, Symbol("##223#227")),getfield(Main, Symbol("##224#228")),getfield(Main, Symbol("##225#229")),Nothing,Nothing,getfield(Main, Symbol("##226#230")),Expr,Expr},Array{Array{Measurement{Float64},1},1},Array{Float64,1},Array{Array{Array{Measurement{Float64},1},1},1},OrdinaryDiffEq.Tsit5Cache{Array{Measurement{Float64},1},Array{Measurement{Float64},1},Array{Measurement{Float64},1},OrdinaryDiffEq.Tsit5ConstantCache{Measurement{Float64},Float64}}},DiffEqBase.DEStats{Nothing}}) at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\cost_functions.jl:49 [4] (::getfield(DiffEqParamEstim, Symbol("##14#18")){Nothing,Bool,Int64,typeof(DiffEqParamEstim.STANDARD_PROB_GENERATOR),Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:callback, :tstops, :maxiters, :verbose),Tuple{DiscreteCallback{typeof(condition),typeof(affect!),typeof(DiffEqBase.INITIALIZE_DEFAULT)},StepRange{Int64,Int64},Int64,Bool}}},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##399")){getfield(Main, Symbol("##223#227")),getfield(Main, Symbol("##224#228")),getfield(Main, Symbol("##225#229")),Nothing,Nothing,getfield(Main, Symbol("##226#230")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing},Nothing})(::Measurement{Float64}) at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\build_loss_objective.jl:29 [5] DiffEqObjective at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\build_loss_objective.jl:8 [inlined] [6] iterate at .\generator.jl:47 [inlined] [7] collect(::Base.Generator{Array{Measurement{Float64},1},DiffEqObjective{getfield(DiffEqParamEstim, Symbol("##14#18")){Nothing,Bool,Int64,typeof(DiffEqParamEstim.STANDARD_PROB_GENERATOR),Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:callback, :tstops, :maxiters, :verbose),Tuple{DiscreteCallback{typeof(condition),typeof(affect!),typeof(DiffEqBase.INITIALIZE_DEFAULT)},StepRange{Int64,Int64},Int64,Bool}}},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##399")){getfield(Main, Symbol("##223#227")),getfield(Main, Symbol("##224#228")),getfield(Main, Symbol("##225#229")),Nothing,Nothing,getfield(Main, Symbol("##226#230")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing},Nothing},getfield(DiffEqParamEstim, Symbol("##17#21"))}}) at .\array.jl:606
Doing some extra research I rewrote the code without the using Measurements: and it works well with the callbacks - I can't figure out why it would work in one case and not the other, but maybe you have some comments or ideas what need to be fixed to work with Measurements?
Thanks
using Pkg
using DifferentialEquations
using DiffEqParamEstim
using ParameterizedFunctions
using Plots
using DiffEqBiological
using Latexify
using BenchmarkTools
using Measurements
using StaticArrays
# using DiffEqCallbacks
# using ParameterizedFunctions
test = @ode_def begin
dx=-k*x
end k
x0 = [10.0]# ± 1]
const V = 1
k=1
prob = ODEProblem(test,x0,(0.0,10.0),k)
condition(u,t,integrator) = t in [2,4,6,8] # && u[1]/V<1
affect!(integrator) = integrator.u[1] += 10 #±1
cb = DiscreteCallback(condition,affect!)
sol = solve(prob,Tsit5(),callback=cb,tstops=[2,4,6,8])
# mean = [x[1].val for x in sol.u]
# band=[x[1].err for x in sol.u]
#plot(sol.t,mean, ribbon=band, alpha=0.5, width=3)
plot(sol, width=3)
t = collect(range(0,stop=10,length=1000))
using RecursiveArrayTools # for VectorOfArray
randomized = VectorOfArray([(sol(t[i]).+rand(-1:0.01:1)[1]) for i in 1:length(t)])
data = convert(Array,randomized)
#plot(sol.t,mean, ribbon=band, alpha=0.5, width=3)
plot(sol)
scatter!(t,data')
#t= collect(range(0,stop=10,length=20))
cost_function = build_loss_objective(prob,Tsit5(),
tstops = [2,4,6,8], callback=cb,L2Loss(t,data'), maxiters=100000,verbose=false)
vals =collect(range(0,stop=2,length=1000))
using Plots; plotly()
vals
#[cost_function(i) for i in vals]
plot(vals,[cost_function(i) for i in vals],yscale=:log10,
xaxis = "Parameter", yaxis = "Cost", title = "1-Parameter Cost Function",
lw = 3)
What code is being ran and what is the full error message?
Here is the code - it the one I sent you before with your corrected cost function:
using Pkg
using DifferentialEquations
using DiffEqParamEstim
using ParameterizedFunctions
using Plots
using DiffEqBiological
using Latexify
using BenchmarkTools
using Measurements
using StaticArrays
# Equation
test = @ode_def begin
dx=-k*x
end k
x0 = [10.0 ± 1]
const V = 1
k=1
# Solve Equation
prob = ODEProblem(test,x0,(0.0,10.0),k)
condition(u,t,integrator) = t in [2,4,6,8] # && u[1]/V<1
affect!(integrator) = integrator.u[1] += 10±1
cb = DiscreteCallback(condition,affect!)
sol = solve(prob,Tsit5(),callback=cb,tstops=[2,4,6,8])
plot(sol, width=3)
# Simulate Data
t = collect(range(0,stop=10,length=500))
using RecursiveArrayTools # for VectorOfArray
randomized = VectorOfArray([(sol(t[i]).+rand(-2:0.01:2)[1]) for i in 1:length(t)])
data = convert(Array,randomized)
plot(sol)
scatter!(t,data')
# Objective Function
cost_function = build_loss_objective(prob,Tsit5(),
tstops = [2,4,6,8], callback=cb,L2Loss(t,data'), maxiters=100000,verbose=false)
# Plot cost function Float64
vals =collect(range(0,stop=2,length=1000))
plot(vals,[cost_function(i) for i in vals],yscale=:log10,
xaxis = "Parameter", yaxis = "Cost", title = "1-Parameter Cost Function",
lw = 3)
# Plot cost function Measurement
vals =collect(range(0±0,stop=2±0,length=1000))
plot(vals,[cost_function(i) for i in vals],yscale=:log10,
xaxis = "Parameter", yaxis = "Cost", title = "1-Parameter Cost Function",
lw = 3)
Everything runs well until # Plot cost function section I run this section using Float64 or Measurement type for vals.
Full Error Message if run Plot cost function Float64:
MethodError: no method matching Float64(::Measurement{Float64}) Closest candidates are: Float64(::Real, !Matched::RoundingMode) where T<:AbstractFloat at rounding.jl:194 Float64(::T<:Number) where T<:Number at boot.jl:741 Float64(!Matched::Int8) at float.jl:60 ...
Stacktrace: [1] _broadcast_getindex_evalf at .\broadcast.jl:578 [inlined] [2] _broadcast_getindex at .\broadcast.jl:551 [inlined] [3] getindex at .\broadcast.jl:511 [inlined] [4] copy at .\broadcast.jl:787 [inlined] [5] materialize at .\broadcast.jl:753 [inlined] [6] STANDARD_PROB_GENERATOR(::ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##363")){getfield(Main, Symbol("##3#7")),getfield(Main, Symbol("##4#8")),getfield(Main, Symbol("##5#9")),Nothing,Nothing,getfield(Main, Symbol("##6#10")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem}, ::Float64) at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\DiffEqParamEstim.jl:5 [7] (::getfield(DiffEqParamEstim, Symbol("##14#18")){Nothing,Bool,Int64,typeof(DiffEqParamEstim.STANDARD_PROB_GENERATOR),Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:tstops, :callback, :maxiters, :verbose),Tuple{Array{Int64,1},DiscreteCallback{typeof(condition),typeof(affect!),typeof(DiffEqBase.INITIALIZE_DEFAULT)},Int64,Bool}}},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##363")){getfield(Main, Symbol("##3#7")),getfield(Main, Symbol("##4#8")),getfield(Main, Symbol("##5#9")),Nothing,Nothing,getfield(Main, Symbol("##6#10")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing},Nothing})(::Float64) at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\build_loss_objective.jl:22 [8] (::DiffEqObjective{getfield(DiffEqParamEstim, Symbol("##14#18")){Nothing,Bool,Int64,typeof(DiffEqParamEstim.STANDARD_PROB_GENERATOR),Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:tstops, :callback, :maxiters, :verbose),Tuple{Array{Int64,1},DiscreteCallback{typeof(condition),typeof(affect!),typeof(DiffEqBase.INITIALIZE_DEFAULT)},Int64,Bool}}},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##363")){getfield(Main, Symbol("##3#7")),getfield(Main, Symbol("##4#8")),getfield(Main, Symbol("##5#9")),Nothing,Nothing,getfield(Main, Symbol("##6#10")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing},Nothing},getfield(DiffEqParamEstim, Symbol("##17#21"))})(::Float64) at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\build_loss_objective.jl:8 [9] iterate at .\generator.jl:47 [inlined] [10] collect(::Base.Generator{Array{Float64,1},DiffEqObjective{getfield(DiffEqParamEstim, Symbol("##14#18")){Nothing,Bool,Int64,typeof(DiffEqParamEstim.STANDARD_PROB_GENERATOR),Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:tstops, :callback, :maxiters, :verbose),Tuple{Array{Int64,1},DiscreteCallback{typeof(condition),typeof(affect!),typeof(DiffEqBase.INITIALIZE_DEFAULT)},Int64,Bool}}},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##363")){getfield(Main, Symbol("##3#7")),getfield(Main, Symbol("##4#8")),getfield(Main, Symbol("##5#9")),Nothing,Nothing,getfield(Main, Symbol("##6#10")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing},Nothing},getfield(DiffEqParamEstim, Symbol("##17#21"))}}) at .\array.jl:606
Full Error Message if run Plot cost function Measurement instead:
UndefRefError: access to undefined reference
Stacktrace: [1] getindex at .\array.jl:730 [inlined] [2] getindex at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.1\LinearAlgebra\src\adjtrans.jl:130 [inlined] [3] (::L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing})(::ODESolution{Measurement{Float64},2,Array{Array{Measurement{Float64},1},1},Nothing,Nothing,Array{Float64,1},Array{Array{Array{Measurement{Float64},1},1},1},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Measurement{Float64},getfield(Main, Symbol("##365")){getfield(Main, Symbol("##15#19")),getfield(Main, Symbol("##16#20")),getfield(Main, Symbol("##17#21")),Nothing,Nothing,getfield(Main, Symbol("##18#22")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,OrdinaryDiffEq.InterpolationData{getfield(Main, Symbol("##365")){getfield(Main, Symbol("##15#19")),getfield(Main, Symbol("##16#20")),getfield(Main, Symbol("##17#21")),Nothing,Nothing,getfield(Main, Symbol("##18#22")),Expr,Expr},Array{Array{Measurement{Float64},1},1},Array{Float64,1},Array{Array{Array{Measurement{Float64},1},1},1},OrdinaryDiffEq.Tsit5Cache{Array{Measurement{Float64},1},Array{Measurement{Float64},1},Array{Measurement{Float64},1},OrdinaryDiffEq.Tsit5ConstantCache{Measurement{Float64},Float64}}},DiffEqBase.DEStats{Nothing}}) at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\cost_functions.jl:49 [4] (::getfield(DiffEqParamEstim, Symbol("##14#18")){Nothing,Bool,Int64,typeof(DiffEqParamEstim.STANDARD_PROB_GENERATOR),Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:tstops, :callback, :maxiters, :verbose),Tuple{Array{Int64,1},DiscreteCallback{typeof(condition),typeof(affect!),typeof(DiffEqBase.INITIALIZE_DEFAULT)},Int64,Bool}}},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##365")){getfield(Main, Symbol("##15#19")),getfield(Main, Symbol("##16#20")),getfield(Main, Symbol("##17#21")),Nothing,Nothing,getfield(Main, Symbol("##18#22")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing},Nothing})(::Measurement{Float64}) at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\build_loss_objective.jl:29 [5] DiffEqObjective at C:\Users\awolf-yadlin.julia\packages\DiffEqParamEstim\Rdg1H\src\build_loss_objective.jl:8 [inlined] [6] iterate at .\generator.jl:47 [inlined] [7] collect(::Base.Generator{Array{Measurement{Float64},1},DiffEqObjective{getfield(DiffEqParamEstim, Symbol("##14#18")){Nothing,Bool,Int64,typeof(DiffEqParamEstim.STANDARD_PROB_GENERATOR),Base.Iterators.Pairs{Symbol,Any,NTuple{4,Symbol},NamedTuple{(:tstops, :callback, :maxiters, :verbose),Tuple{Array{Int64,1},DiscreteCallback{typeof(condition),typeof(affect!),typeof(DiffEqBase.INITIALIZE_DEFAULT)},Int64,Bool}}},ODEProblem{Array{Measurement{Float64},1},Tuple{Float64,Float64},true,Int64,getfield(Main, Symbol("##365")){getfield(Main, Symbol("##15#19")),getfield(Main, Symbol("##16#20")),getfield(Main, Symbol("##17#21")),Nothing,Nothing,getfield(Main, Symbol("##18#22")),Expr,Expr},Nothing,DiffEqBase.StandardODEProblem},Tsit5,L2Loss{Array{Float64,1},LinearAlgebra.Adjoint{Measurement{Float64},Array{Measurement{Float64},2}},Nothing,Nothing},Nothing},getfield(DiffEqParamEstim, Symbol("##17#21"))}}) at .\array.jl:606
thanks-
A
a second question related to callbacks is: Do discrete callbacks work with DAE? take this code for example:
function f(out,du,u,p,t)
k₁₂, k₂₁, kdeg =p
X1=u[1]
X2=u[2]
X3=u[3]
out[1] = -(k₁₂+kdeg)*X1+k₂₁*X2 - du[1]
out[2] = k₁₂*X1-k₂₁*X2 - du[2]
out[3] = u[1] - u[2] - u[3]
end
u₀ = [10.0, 0, 0]
du₀ = [0, 0, 1.0]
tspan = (0.0,10.0)
p=[1,0,0]
differential_vars = [true,true, false]
prob = DAEProblem(f,du₀,u₀,tspan,p,differential_vars=differential_vars)
using Sundials
#sol = solve(prob,IDA(linear_solver=:GMRES))
condition(u,t,integrator) = t in [2,4,6,8] # && u[1]/V<1
affect!(integrator) = integrator.u[1] +=10# 10#±1
# affect!(integrator) = integrator.u[1] *=1.01
cb = DiscreteCallback(condition,affect!)
sol = solve(prob,IDA(linear_solver=:GMRES),callback=cb,tstops=[2,4,6,8],alg_hints=[:stiff])
if i solve without callbacks using commented code there is no issue whatsoever:
Also if I use callbacks that don't change much (commented code too) there is also not problems
if i try to use callbacks that actually modify u[1] (code exactly as above): affect!(integrator) = integrator.u[1] +=10 I get the following: "[IDAS ERROR] IDASolve At t = 2 and h = 4.88281e-007, the error test failed repeatedly or with |h| = hmin."
Is this because by adding the discrete callback I am jumping to far from 0 in out[1]? is there a way around to make the callbacks work with DAEProbelms when you add big jumps?
Thanks,
A
PS- sorry for all the questions and issues - I hope some of this are helpful things and not me just being :Dense
Do discrete callbacks work with DAE?
Yes, the issue here was actually quite subtle. Since you changed u
, the residual of f(res,du,u,p,t)
was no longer zero, so the new initial condition was not consistent. However, requiring you to change du
seems not nice, so what I did was added a consistency change and IC finding step after callback modifications, and released this as Sundials v3.1.0. That fixes this problem and so when you update it should be good.
Thanks so much - I am very appreciative of how quickly you respond to questions and fix issues! Going to give it a try tonight :) take care,
A
Here's a version of the cost function that works with measurement types:
using OrdinaryDiffEq
using DiffEqParamEstim
using ParameterizedFunctions
using Measurements
# Equation
test = @ode_def begin
dx=-k*x
end k
x0 = [10.0 ± 1]
const V = 1
k=1
# Solve Equation
prob = ODEProblem(test,x0,(0.0,10.0),k)
condition(u,t,integrator) = t in [2,4,6,8] # && u[1]/V<1
affect!(integrator) = integrator.u[1] += 10±1
cb = DiscreteCallback(condition,affect!;save_positions=(false,false))
sol = solve(prob,Tsit5(),callback=cb,tstops=[2,4,6,8])
# Simulate Data
t = collect(range(0,stop=10,length=500))
using RecursiveArrayTools # for VectorOfArray
randomized = VectorOfArray([(sol(t[i]).+rand(-2:0.01:2)[1]) for i in 1:length(t)])
data = convert(Array,randomized)
# Objective Function
cost_function = build_loss_objective(prob,Tsit5(),L2Loss(t,data'),
tstops = [2,4,6,8], callback=cb, maxiters=100000,verbose=false)
# Plot cost function Measurement
vals =collect(range(0±0,stop=2±0,length=1000))
cost_function(vals[1])
Note that p
has to be a measurement if u0
is a measurement because it will auto-uptype u0
to match p
in order to handle dual numbers for automatic differentiation. But it will downtype u0
back to a float if p
is a float, or at least it tries to and recognize it can't which gives the error. This is then fixed by matching types on u0
and p
. The output of the cost function is then an uncertainty type, so I don't know how you want to plot it or handle it, but it's interesting (maybe weigh by the amount of uncertainty?).
I think I answered all of the questions so I'll close this. Generally it's better to ask help questions on https://discourse.julialang.org/ or our chat channel. The issues are mainly for development issues but I'm not overly strict about that.
I'll make sure to address questions through the correct channel from now on- Again thanks for helping me,
Ale
I've been looking for a while, but i am not sure if there are any example or anyway to do parameter estimation in a problem with callbacks - The parameter estimation takes the problem, but the callbacks are added in the solve stage. I've been playing with your conditional dose example - Is there anyway around this issue to recover the correct parameters? please let me know if this is a legitimate question, I am new to Julia and ODE programing in general. thanks Here is the code I use:
The minimal is found around 0.15, while the real parameter is 1 - this is happening because the cost function doesn't know about the callbacks if I run same code without callback in the solution the minimal is found correctly at 1 thanks for your help, please let me know if this is inappropriate and I will not bother you again! Ale