Giter VIP home page Giter VIP logo

steadystatediffeq.jl's Introduction

SteadyStateDiffEq.jl

Join the chat at https://gitter.im/JuliaDiffEq/Lobby Build Status Coverage Status codecov.io

SteadyStateDiffEq.jl is a component package in the DifferentialEquations ecosystem. It holds the steady state solvers for differential equations. While completely independent and usable on its own, users interested in using this functionality should check out DifferentialEquations.jl.

Breaking Changes in v2

  1. NLsolve.jl dependency has been dropped. SSRootfind requires a nonlinear solver to be specified.
  2. DynamicSS no longer stores abstol and reltol. To use separate tolerances for the odesolve and the termination, specify odesolve_kwargs in solve.
  3. The deprecated termination conditions are dropped, see NonlinearSolve.jl Docs for details on this.

steadystatediffeq.jl's People

Contributors

asinghvi17 avatar avik-pal avatar axla-io avatar chrisrackauckas avatar christopher-dg avatar david-pl avatar dependabot[bot] avatar devmotion avatar femtocleaner[bot] avatar frankschae avatar garibarba avatar github-actions[bot] avatar juliatagbot avatar luap-pik avatar m-bossart avatar ranocha avatar rudrasohan avatar scottpjones avatar staticfloat avatar thazhemadam avatar tkf avatar yingboma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

steadystatediffeq.jl's Issues

TagBot trigger issue

This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your TagBot.yml to include issue comment triggers.
Please see this post on Discourse for instructions and more details.

If you'd like for me to do this for you, comment TagBot fix on this issue.
I'll open a PR within a few hours, please be patient!

Error with SteadyStateProblem and SSRootfind on GPU

Hi, I am a Julia beginner so this might be a trivial mistake on my side... When I run the following code

using DifferentialEquations, DiffEqSensitivity, CUDA

CUDA.allowscalar(false) 

N = 10
p = ones(N)
u0 = ones(N)

p = cu(p)
u0 = cu(u0)

f(u, p, t) = u .* u .- (2f0 .* p) 

probN = SteadyStateProblem(f, u0, p)
solution = solve(probN, SSRootfind())

CUDA.allowscalar(true) 
println(Array(solution))

I get the error:

ERROR: LoadError: Scalar indexing is disallowed.
Invocation of setindex! resulted in scalar indexing of a GPU array.
This is typically caused by calling an iterating implementation of a method.
Such implementations *do not* execute on the GPU, but very slowly on the CPU,
and therefore are only permitted from the REPL for prototyping purposes.
If you did intend to index this array, annotate the caller with @allowscalar.
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:33
  [2] assertscalar(op::String)
    @ GPUArraysCore ~/.julia/packages/GPUArraysCore/rSIl2/src/GPUArraysCore.jl:78
  [3] setindex!
    @ ~/.julia/packages/GPUArrays/gok9K/src/host/indexing.jl:17 [inlined]
  [4] trust_region_(df::NLSolversBase.OnceDifferentiable{CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}, CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}}, initial_x::CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, xtol::Float32, ftol::Float32, iterations::Int64, store_trace::Bool, show_trace::Bool, extended_trace::Bool, factor::Float32, autoscale::Bool, cache::NLsolve.NewtonTrustRegionCache{CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}})
    @ NLsolve ~/.julia/packages/NLsolve/gJL1I/src/solvers/trust_region.jl:150
  [5] trust_region (repeats 2 times)
    @ ~/.julia/packages/NLsolve/gJL1I/src/solvers/trust_region.jl:235 [inlined]
  [6] nlsolve(df::NLSolversBase.OnceDifferentiable{CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}, CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}}, initial_x::CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}; method::Symbol, xtol::Float32, ftol::Float64, iterations::Int64, store_trace::Bool, show_trace::Bool, extended_trace::Bool, linesearch::LineSearches.Static, linsolve::NLsolve.var"#27#29", factor::Float32, autoscale::Bool, m::Int64, beta::Int64, aa_start::Int64, droptol::Float32)
    @ NLsolve ~/.julia/packages/NLsolve/gJL1I/src/nlsolve/nlsolve.jl:26
  [7] nlsolve(f::Function, initial_x::CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}; method::Symbol, autodiff::Symbol, inplace::Bool, kwargs::Base.Pairs{Symbol, Float64, Tuple{Symbol}, NamedTuple{(:ftol,), Tuple{Float64}}})
    @ NLsolve ~/.julia/packages/NLsolve/gJL1I/src/nlsolve/nlsolve.jl:52
  [8] #2
    @ ~/.julia/packages/SteadyStateDiffEq/qtEru/src/algorithms.jl:6 [inlined]
  [9] __solve(::SteadyStateProblem{CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, false, CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, ODEFunction{false, typeof(f), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}}, ::SSRootfind{SteadyStateDiffEq.var"#2#4"}; abstol::Float64, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ SteadyStateDiffEq ~/.julia/packages/SteadyStateDiffEq/qtEru/src/solve.jl:44
 [10] __solve
    @ ~/.julia/packages/SteadyStateDiffEq/qtEru/src/solve.jl:5 [inlined]
 [11] #solve_call#28
    @ ~/.julia/packages/DiffEqBase/tp3vN/src/solve.jl:437 [inlined]
 [12] solve_call
    @ ~/.julia/packages/DiffEqBase/tp3vN/src/solve.jl:409 [inlined]
 [13] #solve_up#34
    @ ~/.julia/packages/DiffEqBase/tp3vN/src/solve.jl:780 [inlined]
 [14] solve_up
    @ ~/.julia/packages/DiffEqBase/tp3vN/src/solve.jl:765 [inlined]
 [15] #solve#33
    @ ~/.julia/packages/DiffEqBase/tp3vN/src/solve.jl:760 [inlined]
 [16] solve(prob::SteadyStateProblem{CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, false, CuArray{Float32, 1, CUDA.Mem.DeviceBuffer}, ODEFunction{false, typeof(f), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}}, args::SSRootfind{SteadyStateDiffEq.var"#2#4"})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/tp3vN/src/solve.jl:755
 [17] top-level scope
    @ ~/projects/lpjml/src/root_finding_diff.jl:15
in expression starting at /home/ftei-dsw/projects/lpjml/src/root_finding_diff.jl:15

I am not sure what the problem is and any help would be greatly appreciated! :)
My environment is:

[052768ef] CUDA v3.12.0
[41bf760c] DiffEqSensitivity v6.79.0
[0c46a032] DifferentialEquations v7.2.0

and the GPU is a Quadro RTX 5000 Mobile / Max-Q.

DynamicSS crashes

Consider the following snippet:

function f(u, p, t)
    return -u
end

prob = ODEProblem(f, ones(5), (0.0, 100.0))
prob = SteadyStateProblem(prob)
 solve(prob, DynamicSS(Tsit5()))

This should be the most straightforward possible. However, it crashes with the following error message:

type Tsit5ConstantCache has no field tmp

Stacktrace:
 [1] allDerivPass at /home/henrik/.julia/v0.6/DiffEqCallbacks/src/terminatesteadystate.jl:11 [inlined]
 [2] #48 at /home/henrik/.julia/v0.6/DiffEqCallbacks/src/terminatesteadystate.jl:25 [inlined]
 [3] apply_discrete_callback! at /home/henrik/.julia/v0.6/OrdinaryDiffEq/src/callbacks.jl:189 [inlined]
 [4] handle_callbacks!(::OrdinaryDiffEq.ODEIntegrator{OrdinaryDiffEq.Tsit5,Array{Float64,1},Float64,Void,Float64,Float64,Float64,Array{Array{Float64,1},1},DiffEqBase.ODESolution{Float64,2,Array{Array{Float64,1},1},Void,Void,Array{Float64,1},Array{Array{Array{Float64,1},1},1},DiffEqBase.ODEProblem{Array{Float64,1},Float64,false,Void,#f,Void,Void,UniformScaling{Int64},DiffEqBase.StandardODEProblem},OrdinaryDiffEq.Tsit5,OrdinaryDiffEq.InterpolationData{#f,Array{Array{Float64,1},1},Array{Float64,1},Array{Array{Array{Float64,1},1},1},OrdinaryDiffEq.Tsit5ConstantCache{Float64,Float64}}},#f,Void,OrdinaryDiffEq.Tsit5ConstantCache{Float64,Float64},OrdinaryDiffEq.DEOptions{Float64,Float64,Float64,Float64,DiffEqBase.#ODE_DEFAULT_NORM,DiffEqBase.CallbackSet{Tuple{},Tuple{DiffEqBase.DiscreteCallback{DiffEqCallbacks.##48#50{Float64,Float64,DiffEqCallbacks.#allDerivPass},DiffEqCallbacks.##49#51,DiffEqBase.#INITIALIZE_DEFAULT}}},DiffEqBase.#ODE_DEFAULT_ISOUTOFDOMAIN,DiffEqBase.#ODE_DEFAULT_PROG_MESSAGE,DiffEqBase.#ODE_DEFAULT_UNSTABLE_CHECK,DataStructures.BinaryHeap{Float64,DataStructures.LessThan},DataStructures.BinaryHeap{Float64,DataStructures.LessThan},Void,Void,Int64,Array{Float64,1},Array{Float64,1},Array{Float64,1}},Array{Float64,1}}) at /home/henrik/.julia/v0.6/OrdinaryDiffEq/src/integrators/integrator_utils.jl:306
 [5] loopfooter!(::OrdinaryDiffEq.ODEIntegrator{OrdinaryDiffEq.Tsit5,Array{Float64,1},Float64,Void,Float64,Float64,Float64,Array{Array{Float64,1},1},DiffEqBase.ODESolution{Float64,2,Array{Array{Float64,1},1},Void,Void,Array{Float64,1},Array{Array{Array{Float64,1},1},1},DiffEqBase.ODEProblem{Array{Float64,1},Float64,false,Void,#f,Void,Void,UniformScaling{Int64},DiffEqBase.StandardODEProblem},OrdinaryDiffEq.Tsit5,OrdinaryDiffEq.InterpolationData{#f,Array{Array{Float64,1},1},Array{Float64,1},Array{Array{Array{Float64,1},1},1},OrdinaryDiffEq.Tsit5ConstantCache{Float64,Float64}}},#f,Void,OrdinaryDiffEq.Tsit5ConstantCache{Float64,Float64},OrdinaryDiffEq.DEOptions{Float64,Float64,Float64,Float64,DiffEqBase.#ODE_DEFAULT_NORM,DiffEqBase.CallbackSet{Tuple{},Tuple{DiffEqBase.DiscreteCallback{DiffEqCallbacks.##48#50{Float64,Float64,DiffEqCallbacks.#allDerivPass},DiffEqCallbacks.##49#51,DiffEqBase.#INITIALIZE_DEFAULT}}},DiffEqBase.#ODE_DEFAULT_ISOUTOFDOMAIN,DiffEqBase.#ODE_DEFAULT_PROG_MESSAGE,DiffEqBase.#ODE_DEFAULT_UNSTABLE_CHECK,DataStructures.BinaryHeap{Float64,DataStructures.LessThan},DataStructures.BinaryHeap{Float64,DataStructures.LessThan},Void,Void,Int64,Array{Float64,1},Array{Float64,1},Array{Float64,1}},Array{Float64,1}}) at /home/henrik/.julia/v0.6/OrdinaryDiffEq/src/integrators/integrator_utils.jl:264
 [6] solve!(::OrdinaryDiffEq.ODEIntegrator{OrdinaryDiffEq.Tsit5,Array{Float64,1},Float64,Void,Float64,Float64,Float64,Array{Array{Float64,1},1},DiffEqBase.ODESolution{Float64,2,Array{Array{Float64,1},1},Void,Void,Array{Float64,1},Array{Array{Array{Float64,1},1},1},DiffEqBase.ODEProblem{Array{Float64,1},Float64,false,Void,#f,Void,Void,UniformScaling{Int64},DiffEqBase.StandardODEProblem},OrdinaryDiffEq.Tsit5,OrdinaryDiffEq.InterpolationData{#f,Array{Array{Float64,1},1},Array{Float64,1},Array{Array{Array{Float64,1},1},1},OrdinaryDiffEq.Tsit5ConstantCache{Float64,Float64}}},#f,Void,OrdinaryDiffEq.Tsit5ConstantCache{Float64,Float64},OrdinaryDiffEq.DEOptions{Float64,Float64,Float64,Float64,DiffEqBase.#ODE_DEFAULT_NORM,DiffEqBase.CallbackSet{Tuple{},Tuple{DiffEqBase.DiscreteCallback{DiffEqCallbacks.##48#50{Float64,Float64,DiffEqCallbacks.#allDerivPass},DiffEqCallbacks.##49#51,DiffEqBase.#INITIALIZE_DEFAULT}}},DiffEqBase.#ODE_DEFAULT_ISOUTOFDOMAIN,DiffEqBase.#ODE_DEFAULT_PROG_MESSAGE,DiffEqBase.#ODE_DEFAULT_UNSTABLE_CHECK,DataStructures.BinaryHeap{Float64,DataStructures.LessThan},DataStructures.BinaryHeap{Float64,DataStructures.LessThan},Void,Void,Int64,Array{Float64,1},Array{Float64,1},Array{Float64,1}},Array{Float64,1}}) at /home/henrik/.julia/v0.6/OrdinaryDiffEq/src/solve.jl:342
 [7] #solve#1263(::Array{Any,1}, ::Function, ::DiffEqBase.ODEProblem{Array{Float64,1},Float64,false,Void,#f,Void,Void,UniformScaling{Int64},DiffEqBase.StandardODEProblem}, ::OrdinaryDiffEq.Tsit5, ::Array{Any,1}, ::Array{Any,1}, ::Array{Any,1}, ::Type{Val{true}}) at /home/henrik/.julia/v0.6/OrdinaryDiffEq/src/solve.jl:7
 [8] (::DiffEqBase.#kw##solve)(::Array{Any,1}, ::DiffEqBase.#solve, ::DiffEqBase.ODEProblem{Array{Float64,1},Float64,false,Void,#f,Void,Void,UniformScaling{Int64},DiffEqBase.StandardODEProblem}, ::OrdinaryDiffEq.Tsit5, ::Array{Any,1}, ::Array{Any,1}, ::Array{Any,1}, ::Type{Val{true}}) at ./<missing>:0 (repeats 2 times)
 [9] #solve#16(::Array{Any,1}, ::Function, ::DiffEqBase.SteadyStateProblem{Array{Float64,1},false,Void,Void,#f,UniformScaling{Int64}}, ::SteadyStateDiffEq.DynamicSS{OrdinaryDiffEq.Tsit5,Float64,Float64}) at /home/henrik/.julia/v0.6/SteadyStateDiffEq/src/solve.jl:45
 [10] solve(::DiffEqBase.SteadyStateProblem{Array{Float64,1},false,Void,Void,#f,UniformScaling{Int64}}, ::SteadyStateDiffEq.DynamicSS{OrdinaryDiffEq.Tsit5,Float64,Float64}) at /home/henrik/.julia/v0.6/SteadyStateDiffEq/src/solve.jl:42`

Error when solving SteadyStateProblem with DynamicSS and Dual numbers

Probably related to this issue, same MWE, but calling init instead of solve.

MWE :

using ModelingToolkit
using DifferentialEquations
using Turing
using ForwardDiff
using ForwardDiff: Dual

@variables begin
    t
    y1(t) = 1.0
    y2(t) = 0.0
    y3(t) = 0.0
    y4(t) = 0.0
    y5(t) = 0.0
    y6(t) = 0.0
    y7(t) = 0.0
    y8(t) = 0.0057
end

@parameters begin
    k1 = 1.71
    k2 = 280.0
    k3 = 8.32
    k4 = 0.69
    k5 = 0.43
    k6 = 1.81
end

D = Differential(t)
eqs = [
    D(y1) ~ (-k1*y1 + k5*y2 + k3*y3 + 0.0007),
    D(y2) ~ (k1*y1 - 8.75*y2),
    D(y3) ~ (-10.03*y3 + k5*y4 + 0.035*y5),
    D(y4) ~ (k3*y2 + k1*y3 - 1.12*y4),
    D(y5) ~ (-1.745*y5 + k5*y6 + k5*y7),
    D(y6) ~ (-k2*y6*y8 + k4*y4 + k1*y5 - k5*y6 + k4*y7),
    D(y7) ~ (k2*y6*y8 - k6*y7),
    D(y8) ~ (-k2*y6*y8 + k6*y7)
]

@named model = ODESystem(eqs)

u0 = [
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(1.8983788068509213,0.6970981087506788,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.0057,0.0,0.0,0.0,0.0,0.0,0.0,0.0)
]

p = [
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(1.5174072564237708,0.0,0.38355212192378396,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.43,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(8.32,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(268.1197063467946,0.0,0.0,44.91823438292696,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(0.69,0.0,0.0,0.0,0.0,0.0,0.0,0.0),
    Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}}(20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0)
]

prob = SteadyStateProblem(model, u0, p)
alg = DynamicSS(QNDF())
sol = solve(prob, alg)

gives

ERROR: MethodError: no method matching Float64(::Dual{ForwardDiff.Tag{Turing.TuringTag, Float64}, Float64, 7})

and when I change solver to alg = DynamicSS(TRBDF2()) it gives

ERROR: "No matching function wrapper was found!"

cc @SebastianM-C

Pass Jacobian function to NLsolve

I'm not sure but I don't know how to pass a Jacobian function to NLsolve when I solve via

solve(prob, SSRootfind(...))

It seems only the "state" function f! is grabbed from prob (and not the Jacobian, even if it is there). Is that correct? Any way to fix that so that one can then solve for steady-states using efficient Newton-like methods?

[inconsistent behaviour] DynamicSS saving all times

The documentation that the solution object of SteadyStateProblem has no time information which makes sense, but when using the dynamical solver it stores the time steps as well as the states for each step.

Wouldn't it make sense for a SteadyStateProblem to by default use save_everystep=false?
I think this makes sense because this is what the name suggests and would make the behaviour when using nlsolve and the dynamical approach more similar.
Additionally to get the time evolution until the steady state is reached one can simply use an ODEProblem and the TerminateSteadyState callback or explicitly set save_everystep=true.

Have an "run until steady-state" option

In the past I have used the DESolve suite from R and I always liked the idea that one could calculate the steady-state by simply running the simulation until the state variables did not change more than an specified tolerance. This always worked even when non-linear solver got stuck. Furthermore, this may be useful for models where the steady-state is dependent on the initial conditions (i.e. hysteresis).

I wonder if such a feature could be added to this package (or somewhere else in the suite) and what the best strategy would be. Maybe a new problem type is required?

Potential Problems in Convergence Criteria for Steady State

Dear @ChrisRackauckas et. al.,

I am following up on a potential issue I ran into with convergence criteria on the DynamicSS solver and/or TerminateSteadyState callback. I spent a week or so trying to track down the quirk, and my tentative conclusion is that, for my particular system, I was running into situations where the TerminateSteadyState callback would terminate integration prematurely.

The issue I have is probably a bit of a niche one, but it may come up from time to time, so I wrote up a benchmarking problem to illustrate what I think is happening. The high level version is that I'm working on a parameter estimation problem that requires me to solve for the steady state value of multiple state variables. In general, it is hard-to-impossible to provide good guesses as to the true solution, so I opt to solve the temporal problem and integrate to steady state. The solution then gets compared with laboratory measurements, and we use a least squares routine to regress parameter values.

The differential equations that describe this system tend to be an extremely stiff system with state variables and derivative values spanning many orders of magnitude. I believe what is happening with DynamicSS() is that, at times, the system will meet the steady state convergence criteria without truly being at steady state. I spoke with Chris about this, and, in theory, with good values of relative tolerance specific to each state variable, you could probably handle this using the default test criteria in TerminateSteadyState. However, in my case, the magnitude of the state variable and its derivative are highly sensitive to the parameter values, and the parameter values are unknown a priori, which makes it difficult to provide rational values for relative tolerances at the outset.

I created what is probably a fairly contrived problem (I stripped out the parameter estimation part and reduced the number of state variables to two), but I think it highlights the issue reasonably well. The two state variables approach steady state values that are 8 orders of magnitude apart on time scales that are probably 15 orders of magnitude apart.

I encounter this type of physical system in describing the accumulation of species adsorbed on surfaces, where the rates and equilibrium values can vary by many orders of magnitude. Superficially, one might conclude that a steady state value of 1e-8 or 1e-23 are both still effectively zero compared to the other state variable with a steady state value very near 1; however, in calculating rates, these values are often multiplied by proportionality constants that may be on the scale of 1e10 or 1e20, so even small numbers are important in calculating the physically observable response of the system, i.e., this makes a big difference in the parameter estimation problem.

In any event, I'm linking the benchmarking code below. I'm still not 100% sure these issues aren't operator error, but I've done my level best to suss out the details, and I provide a set of parameters where integrating the problem to t --> infinity gives a different set of values for the state variables than using the DynamicSS solver.

https://github.com/jqbond/Test-Cases/blob/master/SSPROBLEM.jl

I played around with tracking the mean value and standard deviation of the state variables as an alternate criteria for termination. It works fine, but, as Chris pointed out to me, is a bit more expensive. I have not played around much with alternative criteria, but am happy to do so if others can confirm this as a potential issue with TerminateSteadyState.

Sincerely,

Jesse

abstol and or reltol work differently with ForwardDiff vs FiniteDiff

Using very small values for abstol and reltol (1e-14) with DynamicSS on a SteadyStateProblem, FiniteDiff solves out to t = 70,000, while ForwardDiff stops at t = 228. The true gradient is [0.0, -296.29629633013286], and FiniteDiff gets that with [-2.6518679901607456e-7, -296.2962963356087], while ForwardDiff is [0.0015469937539040605, -296.29629629628164], good but not great. The gradients are calculated at the bottom of the code with FiniteDiff.finite_difference_gradient and ForwardDiff.gradient

Are the tolerances actually being met with ForwardDiff? Is there a maxiter in the termination conditions in DiffEqBase that is getting hit? Reducing the tolerances to 1e-16 crashes FiniteDiff but ForwardDiff improves to [1.2214211430632144e-5, -296.2962962962962] and goes to t = 1219.

While DynamicSS is not needed on this MWE, it very often is the best choice.

using FiniteDiff
using ForwardDiff
using Optimization
using OptimizationOptimJL
using NonlinearSolve
using DifferentialEquations
using SteadyStateDiffEq
using Plots

function sys!(du, u, (p,p_fix,kf,plateau,kd,start_time,end_time), t)
    #@show t,forcing_function(t,plateau,kd,start_time,end_time),p,p_fix,kf
    du[1] = kf[1]*(1.0 - forcing_function(t,plateau,kd,start_time,end_time)) - p[1]*u[1]
    du[2] = p[1]*u[1] - p_fix[1]*u[2]
    du[3] = p_fix[1]*u[2] - p[2]*u[3]
    if t > 50
     #   @show u
      #  @show du
      @show t
    end
    return nothing
end

function forcing_function(t,plateau,kd,start_time,end_time)
    if t < start_time
        return plateau*t
    else
        if t <= end_time
            return plateau
        else
            if t > end_time && t < Inf
                return plateau*(exp(-kd*(t-end_time)))
            else
                return 0.0
            end
        end
    end
end



function set_kf_outer(probss,u03)
    function set_kf_inner(kf_guess,(u0,p_guess,p_fix,plateau,kd,start_time,end_time))
        # Solve for steady state with current p_guess and an initial guess of kf and u0
        plateau = 0.0
        sol = solve(remake(probss,u0=eltype(kf_guess).(u0),p=(p_guess,p_fix,kf_guess,plateau,kd,start_time,end_time)),DynamicSS(AutoTsit5(Rosenbrock23()),abstol = 1e-14,reltol = 1e-14))
        # Compare kf at steady state to measured u0[3]
        # @show sol.u
        # @show sol.resid
        # @show sol.prob
        @show (sol[3]-u03)^2
        return (sol[3]-u03)^2
    end
end

function main()
    #### Parameters and state variables
    kf0= [10.0] #true value of zero order production rate
    p0 = [1.0,0.25,0.5] #true values of parameters
    p_fix = [p0[2]] # a parameter that is known, note that the system is otherwise unidentifiable
    p_var = [p0[1],p0[3]] # Unknown parameters
    u0_guess = [1000.0,750.0,20.0] #initial guess at steady state of state variables, except u0[3] is known to be 20.0
    u03 = 20.0 # measured value
    plateau = 50.0 # Zero order production rate changes at time = 0, reaches a fractional change given by plateau at start_time
    kd = 1.0 # Rate constant for exponential decay back to original value starting at end_time
    start_time = 1.0
    end_time = 10.0

    #### Set up ODE problem
    t_end = 36.0 # Length of simulation
    tspan = (0.0,t_end) # timespan of simulation
    probODE = ODEProblem(sys!,u0_guess,tspan,(p_var,p_fix,kf0,plateau,kd,start_time,end_time))
    
    #### Set up steady state problem
    probss = SteadyStateProblem(probODE)
    sol_ss = solve(probss)
    u0_ss = sol_ss.u
    @show "u0_ss true",sol_ss.u
    
    #### Initial guesses
    p_guess = [0.1,3.0] #inital guess at values in p_val
    kf_guess = [100.0] #initial guess at kf0
    

    #### Set up optimization problem to determine kf for current value of p_guess
    set_kf = set_kf_outer(probss,u03)
    optkf = OptimizationFunction(set_kf,Optimization.AutoForwardDiff())
    prob_set_kf = OptimizationProblem(optkf,kf_guess,(u0_guess,p_guess,p_fix,plateau,kd,start_time,end_time))
    
    @show FiniteDiff.finite_difference_gradient(x -> set_kf(kf_guess,(u0_guess,x,p_fix,plateau,kd,start_time,end_time)),p_guess)
    @show ForwardDiff.gradient(x -> set_kf(kf_guess,(u0_guess,x,p_fix,plateau,kd,start_time,end_time)),p_guess )

    return nothing
end

main() ```

tspan should probably have a default value or warning

This is related to the termination criteria potentially stopping too early with default values of abstol and reltol. If the abstol or reltol are set low to prevent early termination, then if they can't be met the solve runs to tspan = infinity. This crashes with "ERROR: ArgumentError: matrix contains Infs or NaNs", which doesn't really give the sense that time has run to 1.446951554681122e307.

Having a default value of say tspan = 1000000 or a warning when t got large could be helpful.

The following code has abstol and reltol too small for FiniteDiff gradient, but just right for ForwardDiff gradient. Thus it crashes with FiniteDiff gradient due to running to t = 1e307.

using FiniteDiff
using ForwardDiff
using Optimization
using OptimizationOptimJL
using NonlinearSolve
using DifferentialEquations
using SteadyStateDiffEq
using Plots

function sys!(du, u, (p,p_fix,kf,plateau,kd,start_time,end_time), t)
    #@show t,forcing_function(t,plateau,kd,start_time,end_time),p,p_fix,kf
    du[1] = kf[1]*(1.0 - forcing_function(t,plateau,kd,start_time,end_time)) - p[1]*u[1]
    du[2] = p[1]*u[1] - p_fix[1]*u[2]
    du[3] = p_fix[1]*u[2] - p[2]*u[3]
    
     #   @show u
      #  @show du
      @show t,dt
    
    return nothing
end

function forcing_function(t,plateau,kd,start_time,end_time)
    if t < start_time
        return plateau*t
    else
        if t <= end_time
            return plateau
        else
            if t > end_time && t < Inf
                return plateau*(exp(-kd*(t-end_time)))
            else
                return 0.0
            end
        end
    end
end



function set_kf_outer(probss,u03)
    function set_kf_inner(kf_guess,(u0,p_guess,p_fix,plateau,kd,start_time,end_time))
        # Solve for steady state with current p_guess and an initial guess of kf and u0
        plateau = 0.0
        sol = solve(remake(probss,u0=eltype(kf_guess).(u0),p=(p_guess,p_fix,kf_guess,plateau,kd,start_time,end_time)),DynamicSS(AutoTsit5(Rosenbrock23()),abstol = 1e-16,reltol = 1e-16))
        # Compare kf at steady state to measured u0[3]
        # @show sol.u
        # @show sol.resid
        # @show sol.prob
        @show (sol[3]-u03)^2
        return (sol[3]-u03)^2
    end
end

function main()
    #### Parameters and state variables
    kf0= [10.0] #true value of zero order production rate
    p0 = [1.0,0.25,0.5] #true values of parameters
    p_fix = [p0[2]] # a parameter that is known, note that the system is otherwise unidentifiable
    p_var = [p0[1],p0[3]] # Unknown parameters
    u0_guess = [1000.0,750.0,20.0] #initial guess at steady state of state variables, except u0[3] is known to be 20.0
    u03 = 20.0 # measured value
    plateau = 0.5 # Zero order production rate changes at time = 0, reaches a fractional change given by plateau at start_time
    kd = 1.0 # Rate constant for exponential decay back to original value starting at end_time
    start_time = 1.0
    end_time = 10.0

    #### Set up ODE problem
    t_end = 36.0 # Length of simulation
    tspan = (0.0,t_end) # timespan of simulation
    probODE = ODEProblem(sys!,u0_guess,tspan,(p_var,p_fix,kf0,plateau,kd,start_time,end_time))
    
    #### Set up steady state problem
    probss = SteadyStateProblem(probODE)
    sol_ss = solve(probss)
    u0_ss = sol_ss.u
    @show "u0_ss true",sol_ss.u
    
    #### Initial guesses
    p_guess = [0.1,3.0] #inital guess at values in p_val
    kf_guess = [100.0] #initial guess at kf0
    

    #### Set up optimization problem to determine kf for current value of p_guess
    set_kf = set_kf_outer(probss,u03)
    optkf = OptimizationFunction(set_kf,Optimization.AutoForwardDiff())
    prob_set_kf = OptimizationProblem(optkf,kf_guess,(u0_guess,p_guess,p_fix,plateau,kd,start_time,end_time))
    
    
    @show FiniteDiff.finite_difference_gradient(x -> set_kf(kf_guess,(u0_guess,x,p_fix,plateau,kd,start_time,end_time)),p_guess)
    @show ForwardDiff.gradient(x -> set_kf(kf_guess,(u0_guess,x,p_fix,plateau,kd,start_time,end_time)),p_guess )
    # @show set_kf(kf_guess,(u0_guess,p_guess,p_fix,plateau,kd,start_time,end_time))
    # @show set_kf(kf_guess,(u0_guess,[p_guess[1]*1.01,p_guess[2]],p_fix,plateau,kd,start_time,end_time))
    # @show set_kf(kf_guess,(u0_guess,[p_guess[1],p_guess[2]*1.01],p_fix,plateau,kd,start_time,end_time))
    
   

    return nothing
end

main()

f does not fix t=0

From the docs "The steady state solvers interpret the f by fixing t=0.". But it doesn't seem to do this.

The example below works, but if you instead define the SteadyStateProblem with 'SimpleKinetics!' instead of 'SimpleKineticsSS', it crashes.

using DifferentialEquations, Optimization, OptimizationPolyalgorithms, OptimizationOptimJL,
      SciMLSensitivity, Zygote, Plots, BenchmarkTools,ForwardDiff,NLsolve, Statistics
      

function SimpleKinetics!(du, u, p, t)
    x, y,x2,y2 = u
    β, δ = p

    du[1] =   (1.0-0.1*t) - β*x
    du[2] =  -δ*y + β*x
    du[3] =   0.1*t - β*x2
    du[4] =  -δ*y2 + β*x2
end

function SimpleKineticsSS(du, u, p, t)
    t = 0.0
    SimpleKinetics!(du, u, p, t)
end

function loss_wrapper(prob,tsteps,probSS)
    function loss_closure(p)
        u0=solve(remake(probSS,p=p),SSRootfind())

        sol = solve(remake(prob,u0=u0,p=p), Tsit5(), saveat = tsteps)

        loss = sum(abs2, sol.-0.5) 
        @show loss
        return loss, sol
    end
end

callback = function (p, l, pred)
  
  plt = plot(pred, ylim = (0, 6))
  display(plt)
  
  return false
end


function main()
    tspan = (0.0, 10.0)
    tsteps = 0.0:0.1:10.0
    p = [1.0, 3.0]
    u0 = [2.0, 1.0,0.0,0.0]
   
    prob = ODEProblem(SimpleKinetics!, u0, tspan, p)
   
    probSS = SteadyStateProblem{true}(SimpleKineticsSS, u0, p)
 
    solODE = solve(remake(prob,u0=u0,p=p), Tsit5(), saveat = tsteps)
    display(plot(solODE))
    
    u0=solve(probSS,SSRootfind())
    solODE = solve(remake(prob,u0=u0,p=p), Tsit5(), saveat = tsteps)
    display(plot(solODE))

    loss = loss_wrapper(prob,tsteps,probSS)

    adtype = Optimization.AutoForwardDiff()
    optf = Optimization.OptimizationFunction((x,p)->loss(x), adtype)
    optprob = Optimization.OptimizationProblem(optf, p)

    sol = Optimization.solve(optprob, PolyOpt(), callback = callback, maxiters = 100)
                                   
    p =sol.u
    @show p
    u0=solve(remake(probSS,p=p),SSRootfind())
    solODE = solve(remake(prob,u0=u0,p=p), Tsit5(), saveat = tsteps)
    display(plot(solODE))

    @show sum(abs2, solODE.-0.5) 
end

main()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.