# How fast does a model has to be for NMPC

**URL:** <https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694>\
**Category:** Modelling & Simulations\
**Tags:** question, package, modelpredictivecontr\
**Created:** [September 29, 2024, 7:43pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694 "2024-09-29T19:43:35Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 1, 2024, 3:05pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/21 "2024-10-01T15:05:21Z")

</div>

All I am saying is that accurate force control is key for a reliable and efficient kite power system. The more accurate the controller the smaller you can choose the security margins. And the smaller these margins the more energy you can harvest with the same hardware.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [October 1, 2024, 5:55pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/22 "2024-10-01T17:55:30Z")

</div>

Published 22 years ago, Biegler and co-workers managed to solve quite large problems, see [Redirecting](https://doi.org/10.1016/S0959-1524(02)00002-1). I seem to recall that they considered a system with 200 inputs, 800 outputs, and updated this multiple times per second (or maybe my memory serves me poorly…). I seem to recall that they used some Schur decomposition algorithm in their optimization code. Also, I think they only considered problems with constraints in the control inputs, which greatly simplifies the problem (avoiding infeasibility).

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 1, 2024, 5:58pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/23 "2024-10-01T17:58:45Z")

</div>

Linear quadratic MPC is _much_ easier and more reliable than nonlinear MPC with arbitrary constraints.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [October 3, 2024, 7:13am UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/24 "2024-10-03T07:13:24Z")

</div>

Good overview. One more “constraint” wrt. how fast one can make the system – this may not apply for the case in question, of course:

- Does the system have unstable zero dynamics/is it non-minimum phase?

The following response is typical in hydropower systems:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/d/1d9af959b26a9cf86a8f07b0b92d23f4b67745ae.png)

The inverse response is due to a transmission zero at s=+0.5 (time in seconds), and to get a stable closed loop with MPC, a minimum requirement is that the horizon goes beyond the dip/inverse response.

Multivariable systems may also have unstable zero dynamics, e.g., the Four Tank laboratory case developed at Lund University 2-3 decades ago.

[With “pole placement” type control, and generalizations to nonlinear systems, the closed loop system can be made arbitrarily fast, but then will have virtually zero robustness wrt. model error. For optimal control based systems, transmission zeros (or rather: some invariant zero types) put constraints on the closed loop system, see, e.g., H. Kwakernaak and R. Sivan’s classic book _Linear Optimal Control Systems_ from 1972.]

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 3, 2024, 7:19am UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/25 "2024-10-03T07:19:54Z")

</div>

I [coded up a bunch of rules-of-thumb](https://github.com/JuliaControl/ControlSystems.jl/pull/699/files) as an automatic check for ControlSystems, maybe I should add a mention about prediction horizon for MPC in the verbose output here.

---

<div class="post-metadata">

**Author:** ![Bart\_van\_de\_Lint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bart_van_de_lint/32/212161_2.png) [@Bart\_van\_de\_Lint](https://discourse.julialang.org/u/Bart_van_de_Lint)\
**Post date:** [October 8, 2024, 2:20pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/26 "2024-10-08T14:20:46Z")

</div>

I did some testing here: [GitHub - Albatross-Kite-Transport/KitePredictiveControl.jl](https://github.com/Albatross-Kite-Transport/KitePredictiveControl.jl)

I found out the following:

The model is too slow for NMPC with the KiteModels.jl model combined with `RungeKutta(4)` with supersampling.

Luckily, linearizing the model solves the speed problem. And this can be combined easily with online linearization, like @franckgaga suggested. Linearizing the kite model takes around 5 seconds, so this would not be done every timestep. But it doesn’t look like it is needed every timestep.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 8, 2024, 2:30pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/27 "2024-10-08T14:30:57Z")

</div>

How many states does your model have? I think my KPS4 model is a lot simpler, isn’t it? I need about 66 states for the 6 segment, one line version.

---

<div class="post-metadata">

**Author:** ![Bart\_van\_de\_Lint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bart_van_de_lint/32/212161_2.png) [@Bart\_van\_de\_Lint](https://discourse.julialang.org/u/Bart_van_de_Lint)\
**Post date:** [October 8, 2024, 3:25pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/28 "2024-10-08T15:25:08Z")

</div>

I have 70 states for the 2-segment version of the 3 line model.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 8, 2024, 3:26pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/29 "2024-10-08T15:26:53Z")

</div>

Please double check if there is a way to make the linearization faster. The second time should already be much faster than the first time.

---

<div class="post-metadata">

**Author:** ![Bart\_van\_de\_Lint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bart_van_de_lint/32/212161_2.png) [@Bart\_van\_de\_Lint](https://discourse.julialang.org/u/Bart_van_de_Lint)\
**Post date:** [October 8, 2024, 3:29pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/30 "2024-10-08T15:29:47Z")

</div>

@franckgaga should know this better than me, but I think it depends on the speed of the nonlinear solver. If so, will there be faster solvers anytime soon?

The 5s linearization time is when running linearize multiple times.

Edit: when using Profileview, I can see that `linearize!` spends a lot of time in calculating the jacobians with RungeKutta. Because the kite model is quite stiff, it needs a lot of supersampling, which makes RungeKutta slow. As I understand it, a solver better suited for stiff models would speed up linearization significantly.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 8, 2024, 4:00pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/31 "2024-10-08T16:00:40Z")

</div>

You could try to use an integrator that handles stiff systems, like [`SeeToDee.SimpleColloc`](https://baggepinnen.github.io/SeeToDee.jl/dev/api/#SeeToDee.SimpleColloc). If you do, make note of the tip

```julia
Info "Differentiation" For fast automatic differentiation through this solver

```

---

<div class="post-metadata">

**Author:** ![franckgaga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/franckgaga/32/218241_2.png) [@franckgaga](https://discourse.julialang.org/u/franckgaga)\
**Post date:** [October 8, 2024, 4:07pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/32 "2024-10-08T16:07:14Z")

</div>

Yes, you can try the to use a custom ODE solver (a.k.a integrator). You will need to define your system as a discrete one in MPC.jl, using the `solver=nothing` option.

---

<div class="post-metadata">

**Author:** ![Bart\_van\_de\_Lint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bart_van_de_lint/32/212161_2.png) [@Bart\_van\_de\_Lint](https://discourse.julialang.org/u/Bart_van_de_Lint)\
**Post date:** [October 8, 2024, 4:54pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/33 "2024-10-08T16:54:01Z")

</div>

I don’t fully understand how. I get that I should do

```julia
model = setname!(NonLinModel(f!, h!, Ts, nu, nx, ny, solver=nothing); u=vu, x=vx, y=vy)

```

But where do I use the SeeToDee integrator? As an argument when running linearize?

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 8, 2024, 5:05pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/34 "2024-10-08T17:05:47Z")

</div>

You discretize `f!` with the integrator and then pass the discretize dynamics function instead of `f!`

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 9, 2024, 8:04am UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/35 "2024-10-09T08:04:16Z")

</div>

Did you get it to work? If you did, did it get any faster?

---

<div class="post-metadata">

**Author:** ![Bart\_van\_de\_Lint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bart_van_de_lint/32/212161_2.png) [@Bart\_van\_de\_Lint](https://discourse.julialang.org/u/Bart_van_de_Lint)\
**Post date:** [October 9, 2024, 8:05am UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/36 "2024-10-09T08:05:48Z")

</div>

I am getting this error when linearizing…

```julia
linearize
┌ Warning: Potential Rank Deficient Matrix Detected. Attempting to solve using Pivoted QR Factorization.
└ @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/internal/linear_solve.jl:156
ERROR: LoadError: SingularException(350)
Stacktrace:
  [1] generic_trimatdiv!(C::SubArray{…}, uploc::Char, isunitc::Char, tfun::typeof(identity), A::SubArray{…}, B::SubArray{…})
    @ LinearAlgebra ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/triangular.jl:1141
  [2] _ldiv!
    @ ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/triangular.jl:752 [inlined]
  [3] ldiv!
    @ ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/triangular.jl:757 [inlined]
  [4] ldiv!(A::QR{ForwardDiff.Dual{…}, Matrix{…}, Vector{…}}, B::Matrix{ForwardDiff.Dual{…}})
    @ LinearAlgebra ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/qr.jl:669
  [5] ldiv!
    @ ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/qr.jl:673 [inlined]
  [6] ldiv!(A::QRPivoted{ForwardDiff.Dual{…}, Matrix{…}, Vector{…}, Vector{…}}, b::Vector{ForwardDiff.Dual{…}})
    @ LinearAlgebra ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/qr.jl:678
  [7] ldiv!(Y::Vector{…}, A::QRPivoted{…}, B::Base.ReinterpretArray{…})
    @ LinearAlgebra ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/factorization.jl:168
  [8] _ldiv!
    @ ~/.julia/packages/LinearSolve/0Q5jw/src/factorization.jl:11 [inlined]
  [9] macro expansion
    @ ~/.julia/packages/LinearSolve/0Q5jw/src/LinearSolve.jl:167 [inlined]
 [10] solve!(cache::LinearSolve.LinearCache{…}, alg::LinearSolve.QRFactorization{…}; kwargs::@Kwargs{})
    @ LinearSolve ~/.julia/packages/LinearSolve/0Q5jw/src/LinearSolve.jl:151
 [11] solve!
    @ ~/.julia/packages/LinearSolve/0Q5jw/src/LinearSolve.jl:151 [inlined]
 [12] #solve!#8
    @ ~/.julia/packages/LinearSolve/0Q5jw/src/common.jl:274 [inlined]
 [13] solve!(::LinearSolve.LinearCache{…})
    @ LinearSolve ~/.julia/packages/LinearSolve/0Q5jw/src/common.jl:273
 [14] (::NonlinearSolve.LinearSolverCache{…})(; A::Matrix{…}, b::Base.ReinterpretArray{…}, linu::Vector{…}, du::Vector{…}, p::Nothing, weight::Nothing, cachedata::Nothing, reuse_A_if_factorization::Bool, verbose::Bool, kwargs::@Kwargs{})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/internal/linear_solve.jl:173
 [15] LinearSolverCache
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/internal/linear_solve.jl:120 [inlined]
 [16] __internal_solve!(cache::NonlinearSolve.NewtonDescentCache{…}, J::Matrix{…}, fu::Base.ReinterpretArray{…}, u::Base.ReinterpretArray{…}, idx::Val{…}; skip_solve::Bool, new_jacobian::Bool, kwargs::@Kwargs{})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/descent/newton.jl:84
 [17] __internal_solve! (repeats 2 times)
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/descent/newton.jl:74 [inlined]
 [18] __step!(cache::NonlinearSolve.GeneralizedFirstOrderAlgorithmCache{…}; recompute_jacobian::Nothing, kwargs::@Kwargs{})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generalized_first_order.jl:245
 [19] __step!
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generalized_first_order.jl:226 [inlined]
 [20] #step!#131
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:50 [inlined]
 [21] step!
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:45 [inlined]
 [22] solve!(cache::NonlinearSolve.GeneralizedFirstOrderAlgorithmCache{…})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:13
 [23] __solve(::NonlinearProblem{…}, ::GeneralizedFirstOrderAlgorithm{…}; stats::SciMLBase.NLStats, kwargs::@Kwargs{…})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:4
 [24] solve_call(_prob::NonlinearProblem{…}, args::GeneralizedFirstOrderAlgorithm{…}; merge_callbacks::Bool, kwargshandle::Nothing, kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/vscDj/src/solve.jl:612
 [25] solve_up(prob::NonlinearProblem{…}, sensealg::Nothing, u0::Base.ReinterpretArray{…}, p::Tuple{…}, args::GeneralizedFirstOrderAlgorithm{…}; kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/vscDj/src/solve.jl:1076
 [26] solve(prob::NonlinearProblem{…}, args::GeneralizedFirstOrderAlgorithm{…}; sensealg::Nothing, u0::Nothing, p::Nothing, wrap::Val{…}, kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/vscDj/src/solve.jl:1064
 [27] (::SimpleColloc{…})(x0::Vector{…}, u::Vector{…}, p::Vector{…}, t::Float64; abstol::Float64)
    @ SeeToDee ~/.julia/packages/SeeToDee/t9mPJ/src/SeeToDee.jl:259
 [28] (::SimpleColloc{…})(x0::Vector{…}, u::Vector{…}, p::Vector{…}, t::Float64)
    @ SeeToDee ~/.julia/packages/SeeToDee/t9mPJ/src/SeeToDee.jl:249
 [29] (::var"#f!#21"{SimpleColloc{…}, Vector{…}})(dx::Vector{ForwardDiff.Dual{…}}, x::Vector{ForwardDiff.Dual{…}}, u::Vector{Float64}, ::Vector{Float64}, ::Vector{Float64})
    @ Main ~/Code/KitePredictiveControl.jl/src/mtk_interface.jl:19
 [30] f!(xnext0::Vector{…}, model::NonLinModel{…}, x0::Vector{…}, u0::Vector{…}, d0::Vector{…}, p::Vector{…})
    @ ModelPredictiveControl ~/.julia/packages/ModelPredictiveControl/0rhFm/src/model/nonlinmodel.jl:208
 [31] (::ModelPredictiveControl.var"#myf_x0!#35"{Float64, NonLinModel{…}, Vector{…}, Vector{…}, NonLinModel{…}})(xnext0::Vector{ForwardDiff.Dual{…}}, x0::Vector{ForwardDiff.Dual{…}})
    @ ModelPredictiveControl ~/.julia/packages/ModelPredictiveControl/0rhFm/src/model/linearization.jl:124
 [32] chunk_mode_jacobian!(result::Matrix{…}, f!::ModelPredictiveControl.var"#myf_x0!#35"{…}, y::Vector{…}, x::Vector{…}, cfg::ForwardDiff.JacobianConfig{…})
    @ ForwardDiff ~/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:183
 [33] jacobian!(result::Matrix{Float64}, f!::Function, y::Vector{Float64}, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{…}, Float64, 12, Tuple{…}}, ::Val{true})
    @ ForwardDiff ~/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:80
 [34] jacobian!(result::Matrix{Float64}, f!::Function, y::Vector{Float64}, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{…}, Float64, 12, Tuple{…}})
    @ ForwardDiff ~/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:76
 [35] linearize!(linmodel::LinModel{…}, model::NonLinModel{…}; x::Vector{…}, u::Vector{…}, d::Vector{…})
    @ ModelPredictiveControl ~/.julia/packages/ModelPredictiveControl/0rhFm/src/model/linearization.jl:129
 [36] linearize!
    @ ~/.julia/packages/ModelPredictiveControl/0rhFm/src/model/linearization.jl:110 [inlined]
 [37] linearize(model::NonLinModel{Float64, var"#f!#21"{…}, var"#h!#22"{…}, Vector{…}, ModelPredictiveControl.EmptySolver}; kwargs::@Kwargs{})
    @ ModelPredictiveControl ~/.julia/packages/ModelPredictiveControl/0rhFm/src/model/linearization.jl:87
 [38] linearize(model::NonLinModel{Float64, var"#f!#21"{…}, var"#h!#22"{…}, Vector{…}, ModelPredictiveControl.EmptySolver})
    @ ModelPredictiveControl ~/.julia/packages/ModelPredictiveControl/0rhFm/src/model/linearization.jl:75
 [39] macro expansion
    @ ./timing.jl:279 [inlined]
 [40] top-level scope
    @ ~/Code/KitePredictiveControl.jl/src/KitePredictiveControl.jl:269
 [41] include(fname::String)
    @ Base.MainInclude ./client.jl:489
 [42] top-level scope
    @ REPL[30]:1

```

```julia
f_disc = SimpleColloc(f_ip, Ts, nx, 0, nu; n = 5, abstol = 1.0e-4, solver=NewtonRaphson(), residual=true)
@time linmodel = ModelPredictiveControl.linearize(model)

```

Edit: and when trying to simulate, I get another error:

```julia
@time res = sim!(model, 10, zeros(3))
ERROR: LoadError: Failed to automatically detect ForwardDiff compatability of
the parameter object.

```

Any idea how to fix this?

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 9, 2024, 12:05pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/37 "2024-10-09T12:05:47Z")

</div>

You should most likely use `residual = false` since your function `f!` computes \dot x and not

0 = F(\dot x, x, u, p, t)

I would also use a tighter tolerance, `abstol = 1.0e-4` may not be tight enough.

---

<div class="post-metadata">

**Author:** ![Bart\_van\_de\_Lint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bart_van_de_lint/32/212161_2.png) [@Bart\_van\_de\_Lint](https://discourse.julialang.org/u/Bart_van_de_Lint)\
**Post date:** [October 9, 2024, 2:10pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/39 "2024-10-09T14:10:40Z")

</div>

With residual=false and tighter tolerance I am getting the following error when trying to linearize using either the SeeToDee.linearize or MPC.linearize.

```julia
julia> SeeToDee.linearize(f_disc, x_0, ones(3), par, 10.0);
ERROR: MethodError: Cannot `convert` an object of type Vector{ForwardDiff.Dual{ForwardDiff.Tag{SeeToDee.var"#1#3"{SimpleColloc{typeof(f_oop), Float64, UnitRange{Int64}, UnitRange{Int64}, Matrix{Float64}, Vector{Float64}, Tuple{PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}}, NonlinearProblem{Matrix{Float64}, false, SciMLBase.NullParameters, NonlinearFunction{false, SciMLBase.FullSpecialize, typeof(SeeToDee.coldyn), UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}, GeneralizedFirstOrderAlgorithm{nothing, :NewtonRaphson, NoLineSearch{Bool}, Missing, NewtonDescent{Nothing, typeof(NonlinearSolve.DEFAULT_PRECS)}, Nothing, Nothing, Nothing}}, Vector{Float64}, Tuple{Vector{Float64}, Float64}}, Float64}, Float64, 12}} to an object of type Base.ReinterpretArray{ForwardDiff.Dual{ForwardDiff.Tag{SeeToDee.var"#1#3"{SimpleColloc{typeof(f_oop), Float64, UnitRange{Int64}, UnitRange{Int64}, Matrix{Float64}, Vector{Float64}, Tuple{PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}}, NonlinearProblem{Matrix{Float64}, false, SciMLBase.NullParameters, NonlinearFunction{false, SciMLBase.FullSpecialize, typeof(SeeToDee.coldyn), UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}, GeneralizedFirstOrderAlgorithm{nothing, :NewtonRaphson, NoLineSearch{Bool}, Missing, NewtonDescent{Nothing, typeof(NonlinearSolve.DEFAULT_PRECS)}, Nothing, Nothing, Nothing}}, Vector{Float64}, Tuple{Vector{Float64}, Float64}}, Float64}, Float64, 12}, 1, Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, false}

```

And still getting the same error when trying to simulate using the nonlinear model:

````julia
ERROR: Failed to automatically detect ForwardDiff compatability of
the parameter object. In order for ForwardDiff.jl automatic
differentiation to work on a solution object, the state of
the differential equation or nonlinear solve (`u0`) needs to
be converted to a Dual type which matches the values being
differentiated. For example, for a loss function loss(p)
where `p`` is a `Vector{Float64}`, this conversion is
equivalent to:

\```
# Convert u0 to match the new Dual element type of `p`
_prob = remake(prob, u0 = eltype(p).(prob.u0))
\```

````

Is it correct that I set `na` to zero in SimpleColloc()?

---

<div class="post-metadata">

**Author:** ![franckgaga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/franckgaga/32/218241_2.png) [@franckgaga](https://discourse.julialang.org/u/franckgaga)\
**Post date:** [October 9, 2024, 3:57pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/40 "2024-10-09T15:57:51Z")

</div>

It seems to be related to NonlinearSolve.jl calls that cannot be differentiated through `ForwardDiff.jl`. Normally there is additional informations in the stacktrace after the

```julia
ERROR: MethodError: Cannot `convert` an object of type Vector{ForwardDiff.Dual{ForwardDiff.Tag{SeeToDee.var"#1#3"{SimpleColloc{typeof(f_oop), Float64, UnitRange{Int64}, UnitRange{Int64}, Matrix{Float64}, Vector{Float64}, Tuple{PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}}, NonlinearProblem{Matrix{Float64}, false, SciMLBase.NullParameters, NonlinearFunction{false, SciMLBase.FullSpecialize, typeof(SeeToDee.coldyn), UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}, GeneralizedFirstOrderAlgorithm{nothing, :NewtonRaphson, NoLineSearch{Bool}, Missing, NewtonDescent{Nothing, typeof(NonlinearSolve.DEFAULT_PRECS)}, Nothing, Nothing, Nothing}}, Vector{Float64}, Tuple{Vector{Float64}, Float64}}, Float64}, Float64, 12}} to an object of type Base.ReinterpretArray{ForwardDiff.Dual{ForwardDiff.Tag{SeeToDee.var"#1#3"{SimpleColloc{typeof(f_oop), Float64, UnitRange{Int64}, UnitRange{Int64}, Matrix{Float64}, Vector{Float64}, Tuple{PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}}, NonlinearProblem{Matrix{Float64}, false, SciMLBase.NullParameters, NonlinearFunction{false, SciMLBase.FullSpecialize, typeof(SeeToDee.coldyn), UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}, GeneralizedFirstOrderAlgorithm{nothing, :NewtonRaphson, NoLineSearch{Bool}, Missing, NewtonDescent{Nothing, typeof(NonlinearSolve.DEFAULT_PRECS)}, Nothing, Nothing, Nothing}}, Vector{Float64}, Tuple{Vector{Float64}, Float64}}, Float64}, Float64, 12}, 1, Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, false}

```

line. Can you paste the rest of the stacktrace here?

edit: yes `na` should be 0.

---

<div class="post-metadata">

**Author:** ![Bart\_van\_de\_Lint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bart_van_de_lint/32/212161_2.png) [@Bart\_van\_de\_Lint](https://discourse.julialang.org/u/Bart_van_de_Lint)\
**Post date:** [October 9, 2024, 4:21pm UTC](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694/41 "2024-10-09T16:21:11Z")

</div>

> [@franckgaga](#):
>
> line. Can you paste the rest of the stacktrace here?

```julia-auto
julia> SeeToDee.linearize(f_disc, x_0, ones(3), par, 10.0);
ERROR: MethodError: Cannot `convert` an object of type Vector{ForwardDiff.Dual{ForwardDiff.Tag{SeeToDee.var"#1#3"{SimpleColloc{typeof(f_oop), Float64, UnitRange{Int64}, UnitRange{Int64}, Matrix{Float64}, Vector{Float64}, Tuple{PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}}, NonlinearProblem{Matrix{Float64}, false, SciMLBase.NullParameters, NonlinearFunction{false, SciMLBase.FullSpecialize, typeof(SeeToDee.coldyn), UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}, GeneralizedFirstOrderAlgorithm{nothing, :NewtonRaphson, NoLineSearch{Bool}, Missing, NewtonDescent{Nothing, typeof(NonlinearSolve.DEFAULT_PRECS)}, Nothing, Nothing, Nothing}}, Vector{Float64}, Tuple{Vector{Float64}, Float64}}, Float64}, Float64, 12}} to an object of type Base.ReinterpretArray{ForwardDiff.Dual{ForwardDiff.Tag{SeeToDee.var"#1#3"{SimpleColloc{typeof(f_oop), Float64, UnitRange{Int64}, UnitRange{Int64}, Matrix{Float64}, Vector{Float64}, Tuple{PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}, PreallocationTools.DiffCache{Matrix{Float64}, Vector{Float64}}}, NonlinearProblem{Matrix{Float64}, false, SciMLBase.NullParameters, NonlinearFunction{false, SciMLBase.FullSpecialize, typeof(SeeToDee.coldyn), UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}, GeneralizedFirstOrderAlgorithm{nothing, :NewtonRaphson, NoLineSearch{Bool}, Missing, NewtonDescent{Nothing, typeof(NonlinearSolve.DEFAULT_PRECS)}, Nothing, Nothing, Nothing}}, Vector{Float64}, Tuple{Vector{Float64}, Float64}}, Float64}, Float64, 12}, 1, Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, false}

Closest candidates are:
  convert(::Type{T}, ::T) where T
   @ Base Base.jl:84
  convert(::Type{T}, ::Factorization) where T<:AbstractArray
   @ LinearAlgebra ~/.julia/juliaup/julia-1.10.5+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/factorization.jl:108
  convert(::Type{T}, ::T) where T<:AbstractArray
   @ Base abstractarray.jl:16
  ...

Stacktrace:
  [1] setproperty!(x::NonlinearSolve.GeneralizedFirstOrderAlgorithmCache{…}, f::Symbol, v::Vector{…})
    @ Base ./Base.jl:40
  [2] set_u!(cache::NonlinearSolve.GeneralizedFirstOrderAlgorithmCache{…}, u::Vector{…})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/abstract_types.jl:240
  [3] update_from_termination_cache!(tc_cache::DiffEqBase.NonlinearTerminationModeCache{…}, cache::NonlinearSolve.GeneralizedFirstOrderAlgorithmCache{…}, ::AbsSafeBestTerminationMode{…}, u::Base.ReinterpretArray{…})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/internal/termination.jl:57
  [4] check_and_update!
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/internal/termination.jl:37 [inlined]
  [5] check_and_update!
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/internal/termination.jl:30 [inlined]
  [6] check_and_update!
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/internal/termination.jl:26 [inlined]
  [7] __step!(cache::NonlinearSolve.GeneralizedFirstOrderAlgorithmCache{…}; recompute_jacobian::Nothing, kwargs::@Kwargs{})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generalized_first_order.jl:317
  [8] __step!
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generalized_first_order.jl:226 [inlined]
  [9] #step!#131
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:50 [inlined]
 [10] step!
    @ ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:45 [inlined]
 [11] solve!(cache::NonlinearSolve.GeneralizedFirstOrderAlgorithmCache{…})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:13
 [12] __solve(::NonlinearProblem{…}, ::GeneralizedFirstOrderAlgorithm{…}; stats::SciMLBase.NLStats, kwargs::@Kwargs{…})
    @ NonlinearSolve ~/.julia/packages/NonlinearSolve/sBl1H/src/core/generic.jl:4
 [13] solve_call(_prob::NonlinearProblem{…}, args::GeneralizedFirstOrderAlgorithm{…}; merge_callbacks::Bool, kwargshandle::Nothing, kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/uqSeD/src/solve.jl:612
 [14] solve_up(prob::NonlinearProblem{…}, sensealg::Nothing, u0::Base.ReinterpretArray{…}, p::Tuple{…}, args::GeneralizedFirstOrderAlgorithm{…}; kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/uqSeD/src/solve.jl:1084
 [15] solve(prob::NonlinearProblem{…}, args::GeneralizedFirstOrderAlgorithm{…}; sensealg::Nothing, u0::Nothing, p::Nothing, wrap::Val{…}, kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/uqSeD/src/solve.jl:1072
 [16] (::SimpleColloc{…})(x0::Vector{…}, u::Vector{…}, p::Vector{…}, t::Float64; abstol::Float64)
    @ SeeToDee ~/.julia/packages/SeeToDee/t9mPJ/src/SeeToDee.jl:259
 [17] (::SimpleColloc{…})(x0::Vector{…}, u::Vector{…}, p::Vector{…}, t::Float64)
    @ SeeToDee ~/.julia/packages/SeeToDee/t9mPJ/src/SeeToDee.jl:249
 [18] (::SeeToDee.var"#1#3"{SimpleColloc{…}, Vector{…}, Tuple{…}})(x::Vector{ForwardDiff.Dual{…}})
    @ SeeToDee ~/.julia/packages/SeeToDee/t9mPJ/src/SeeToDee.jl:17
 [19] chunk_mode_jacobian(f::SeeToDee.var"#1#3"{SimpleColloc{…}, Vector{…}, Tuple{…}}, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{…}, Float64, 12, Vector{…}})
    @ ForwardDiff ~/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:183
 [20] jacobian(f::Function, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{SeeToDee.var"#1#3"{…}, Float64}, Float64, 12, Vector{ForwardDiff.Dual{…}}}, ::Val{true})
    @ ForwardDiff ~/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:23
 [21] jacobian(f::Function, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{SeeToDee.var"#1#3"{…}, Float64}, Float64, 12, Vector{ForwardDiff.Dual{…}}})
    @ ForwardDiff ~/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:19
 [22] linearize(::SimpleColloc{…}, ::Vector{…}, ::Vector{…}, ::Vector{…}, ::Vararg{…})
    @ SeeToDee ~/.julia/packages/SeeToDee/t9mPJ/src/SeeToDee.jl:17
 [23] top-level scope
    @ REPL[59]:1
Some type information was truncated. Use `show(err)` to see complete types.

```

[Previous page](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694.md?page=1)

[Next page](https://discourse.julialang.org/t/how-fast-does-a-model-has-to-be-for-nmpc/120694.md?page=3)
