@@ -121,7 +121,7 @@ struct NonLinMPC{
121121 # dummy vals (updated just before optimization):
122122 d0, D̂0, D̂e = zeros (NT, nd), zeros (NT, nd* Hp), zeros (NT, nd + nd* Hp)
123123 Uop, Yop, Dop = repeat (model. uop, Hp), repeat (model. yop, Hp), repeat (model. dop, Hp)
124- test_custom_functions (NT, model, JE, gc!, nc, Uop, Yop, Dop, p)
124+ test_custom_function_mpc (NT, model, JE, gc!, nc, Uop, Yop, Dop, p)
125125 Mo, Co, λo = init_orthocolloc (model, transcription)
126126 nZ̃ = get_nZ (estim, transcription, Hp, Hc) + nϵ
127127 Z̃ = zeros (NT, nZ̃)
@@ -167,7 +167,7 @@ controller minimizes the following objective function at each discrete time ``k`
167167```
168168subject to [`setconstraint!`](@ref) bounds, and the custom inequality constraints:
169169```math
170- \m athbf{g_c}(\m athbf{U_e}, \m athbf{ Ŷ_e}, \m athbf{ D̂_e}, \m athbf{ p}, ϵ) ≤ \m athbf{0}
170+ \m athbf{g_c}(\m athbf{U_e, Ŷ_e, D̂_e, p}, ϵ) ≤ \m athbf{0}
171171```
172172with the decision variables ``\m athbf{Z}`` and slack ``ϵ``. By default, a [`SingleShooting`](@ref)
173173transcription method is used, hence ``\m athbf{Z=ΔU}``. The economic function ``J_E`` can
@@ -222,8 +222,8 @@ This controller allocates memory at each time step for the optimization.
222222- `JE=(_,_,_,_,_)->0.0` : economic or custom cost function ``J_E(\m athbf{U_e}, \m athbf{Ŷ_e},
223223 \m athbf{D̂_e}, \m athbf{p}, ϵ)``.
224224- `gc=(_,_,_,_,_,_)->nothing` or `gc!` : custom nonlinear inequality constraint function
225- ``\m athbf{g_c}(\m athbf{U_e}, \m athbf{Ŷ_e}, \m athbf{ D̂_e}, \m athbf{ p}, ϵ)``, mutating or
226- not (details in Extended Help).
225+ ``\m athbf{g_c}(\m athbf{U_e}, \m athbf{Ŷ_e, D̂_e, p}, ϵ)``, mutating or not (details in
226+ Extended Help).
227227- `nc=0` : number of custom nonlinear inequality constraints.
228228- `p=model.p` : ``J_E`` and ``\m athbf{g_c}`` functions parameter ``\m athbf{p}`` (any type).
229229- `transcription=SingleShooting()` : a [`TranscriptionMethod`](@ref) for the optimization.
@@ -276,22 +276,24 @@ NonLinMPC controller with a sample time Ts = 10.0 s:
276276 extended vectors ``\m athbf{U_e}``, ``\m athbf{Ŷ_e}`` and ``\m athbf{D̂_e}`` as arguments.
277277 They also receives the slack ``ϵ`` (scalar), which is always zero if `Cwt=Inf`. The
278278 following table details the vector sizes and the time steps of the first and last data
279- point in them:
279+ point in them.
280280
281- | VECTOR | SIZE | FIRST TIME STEP | LAST TIME STEP |
282- | :--------------- | :------------- | :-------------- | :------------- |
283- | ``\m athbf{U_e}`` | `(nu*(Hp+1),)` | ``k + 0`` | ``k + H_p`` |
284- | ``\m athbf{Ŷ_e}`` | `(ny*(Hp+1),)` | ``k + 0`` | ``k + H_p`` |
285- | ``\m athbf{D̂_e}`` | `(nd*(Hp+1),)` | ``k + 0`` | ``k + H_p`` |
281+ | ARGUMENT | SIZE | FIRST SAMPLE | LAST SAMPLE |
282+ | :--------------- | :------------- | :----------- | :-----------|
283+ | ``\m athbf{U_e}`` | `((Hp+1)*nu,)` | ``k`` | ``k + H_p`` |
284+ | ``\m athbf{Ŷ_e}`` | `((Hp+1)*ny,)` | ``k`` | ``k + H_p`` |
285+ | ``\m athbf{D̂_e}`` | `((Hp+1)*nd,)` | ``k`` | ``k + H_p`` |
286+ | ``\m athbf{p}`` | var. | — | — |
287+ | ``ϵ`` | `()` | — | — |
286288
287289 More precisely, the last two time steps in ``\m athbf{U_e}`` are forced to be equal, i.e.
288290 ``\m athbf{u}(k+H_p) = \m athbf{u}(k+H_p-1)``, since ``H_c ≤ H_p`` implies that
289291 ``\m athbf{Δu}(k+H_p) = \m athbf{0}``. The vectors ``\m athbf{ŷ}(k)`` and ``\m athbf{d}(k)``
290292 are the current state estimator output and measured disturbance, respectively, and
291293 ``\m athbf{Ŷ}`` and ``\m athbf{D̂}``, their respective predictions from ``k+1`` to ``k+H_p``.
292294 If `LHS` represents the result of the left-hand side in the inequality
293- ``\m athbf{g_c}(\m athbf{U_e}, \m athbf{ Ŷ_e}, \m athbf{ D̂_e}, \m athbf{ p}, ϵ) ≤ \m athbf{0}``,
294- the function `gc` can be implemented in two possible ways:
295+ ``\m athbf{g_c}(\m athbf{U_e, Ŷ_e, D̂_e, p}, ϵ) ≤ \m athbf{0}``, the function `gc` can be
296+ implemented in two possible ways:
295297
296298 1. **Non-mutating function** (out-of-place): define it as `gc(Ue, Ŷe, D̂e, p, ϵ) -> LHS`.
297299 This syntax is simple and intuitive but it allocates more memory.
@@ -442,7 +444,7 @@ function NonLinMPC(
442444 nb = move_blocking (Hp, Hc)
443445 Hc = get_Hc (nb)
444446 validate_JE (NT, JE)
445- gc! = get_mutating_gc (NT, gc)
447+ gc! = get_mutating_gc_mpc (NT, gc)
446448 weights = ControllerWeights (estim. model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
447449 hessian = validate_hessian (hessian, gradient, DEFAULT_NONLINMPC_HESSIAN)
448450 return NonLinMPC {NT} (
@@ -471,18 +473,23 @@ function validate_JE(NT, JE)
471473end
472474
473475"""
474- validate_gc (NT, gc) -> ismutating
476+ validate_gc_mpc (NT, gc) -> ismutating
475477
476- Validate `gc` function argument signature and return `true` if it is mutating.
478+ Validate `gc` function argument signature for MPC and return `true` if it is mutating.
477479"""
478- function validate_gc (NT, gc)
480+ function validate_gc_mpc (NT, gc)
479481 ismutating = hasmethod (
480482 gc,
481483 # LHS, Ue, Ŷe, D̂e, p, ϵ
482484 Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Vector{NT}, Any, NT}
483485 )
486+ isnonmutating = hasmethod (
487+ gc,
488+ # Ue, Ŷe, D̂e, p, ϵ
489+ Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Any, NT}
490+ )
484491 # Ue, Ŷe, D̂e, p, ϵ
485- if ! (ismutating || hasmethod (gc, Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Any, NT}) )
492+ if ! (ismutating || isnonmutating )
486493 error (
487494 " the custom constraint function has no method with type signature " *
488495 " gc(Ue::Vector{$(NT) }, Ŷe::Vector{$(NT) }, D̂e::Vector{$(NT) }, p::Any, ϵ::$(NT) ) " *
@@ -494,8 +501,8 @@ function validate_gc(NT, gc)
494501end
495502
496503" Get mutating custom constraint function `gc!` from the provided function in argument."
497- function get_mutating_gc (NT, gc)
498- ismutating_gc = validate_gc (NT, gc)
504+ function get_mutating_gc_mpc (NT, gc)
505+ ismutating_gc = validate_gc_mpc (NT, gc)
499506 gc! = if ismutating_gc
500507 gc
501508 else
@@ -508,15 +515,15 @@ function get_mutating_gc(NT, gc)
508515end
509516
510517"""
511- test_custom_functions (NT, model::SimModel, JE, gc!, nc, Uop, Yop, Dop, p)
518+ test_custom_function_mpc (NT, model::SimModel, JE, gc!, nc, Uop, Yop, Dop, p)
512519
513520Test the custom functions `JE` and `gc!` at the operating point `Uop`, `Yop`, `Dop`.
514521
515522This function is called at the end of `NonLinMPC` construction. It warns the user if the
516523custom cost `JE` and constraint `gc!` functions crash at `model` operating points. This
517524should ease troubleshooting of simple bugs e.g.: the user forgets to set the `nc` argument.
518525"""
519- function test_custom_functions (NT, model:: SimModel , JE, gc!, nc, Uop, Yop, Dop, p)
526+ function test_custom_function_mpc (NT, model:: SimModel , JE, gc!, nc, Uop, Yop, Dop, p)
520527 uop, dop, yop = model. uop, model. dop, model. yop
521528 Ue, Ŷe, D̂e = [Uop; uop], [yop; Yop], [dop; Dop]
522529 ϵ = zero (NT)
@@ -729,11 +736,11 @@ function init_optimization!(
729736 mpc:: NonLinMPC , model:: SimModel , optim:: JuMP.GenericModel{JNT}
730737) where JNT<: Real
731738 # --- variables and linear constraints ---
732- con, transcription = mpc. con, mpc . transcription
739+ con = mpc. con
733740 nZ̃ = length (mpc. Z̃)
734741 JuMP. num_variables (optim) == 0 || JuMP. empty! (optim)
735742 JuMP. set_silent (optim)
736- limit_solve_time (mpc. optim, mpc . estim . model. Ts)
743+ limit_solve_time (mpc. optim, model. Ts)
737744 @variable (optim, Z̃var[1 : nZ̃])
738745 A = con. A[con. i_b, :]
739746 b = con. b[con. i_b]
@@ -742,15 +749,8 @@ function init_optimization!(
742749 beq = con. beq
743750 @constraint (optim, linconstrainteq, Aeq* Z̃var .== beq)
744751 # --- nonlinear optimization init ---
745- if mpc. nϵ == 1 && JuMP. solver_name (optim) == " Ipopt"
746- C = mpc. weights. Ñ_Hc[end ]
747- try
748- JuMP. get_attribute (optim, " nlp_scaling_max_gradient" )
749- catch
750- # default "nlp_scaling_max_gradient" to `10.0/C` if not already set:
751- JuMP. set_attribute (optim, " nlp_scaling_max_gradient" , 10.0 / C)
752- end
753- end
752+ C = mpc. nϵ > 0 ? mpc. weights. Ñ_Hc[end , end ] : Inf
753+ set_scaling_gradient! (optim, C)
754754 J_op = get_nonlinobj_op (mpc, optim)
755755 g_oracle, geq_oracle = get_nonlincon_oracle (mpc, optim)
756756 @objective (optim, Min, J_op (Z̃var... ))
@@ -926,7 +926,7 @@ function get_nonlincon_oracle(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JN
926926 myNaN, myInf = convert (JNT, NaN ), convert (JNT, Inf )
927927 ΔŨ:: Vector{JNT} = zeros (JNT, nΔŨ)
928928 x̂0end:: Vector{JNT} = zeros (JNT, nx̂)
929- K:: Vector{JNT} = zeros (JNT, nK)
929+ K:: Vector{JNT} = zeros (JNT, nK)
930930 Ue:: Vector{JNT} , Ŷe:: Vector{JNT} = zeros (JNT, nUe), zeros (JNT, nŶe)
931931 U0:: Vector{JNT} , Ŷ0:: Vector{JNT} = zeros (JNT, nU), zeros (JNT, nŶ)
932932 Û0:: Vector{JNT} , X̂0:: Vector{JNT} = zeros (JNT, nU), zeros (JNT, nX̂)
@@ -1081,7 +1081,7 @@ function update_predictions!(
10811081 ΔŨ = getΔŨ! (ΔŨ, mpc, transcription, Z̃)
10821082 Ŷ0, x̂0end = predict! (Ŷ0, x̂0end, X̂0, Û0, K, mpc, model, transcription, U0, Z̃)
10831083 Ue, Ŷe = extended_vectors! (Ue, Ŷe, mpc, U0, Ŷ0)
1084- ϵ = getϵ (mpc, Z̃)
1084+ ϵ = getϵ (mpc, Z̃)
10851085 gc = con_custom! (gc, mpc, Ue, Ŷe, ϵ)
10861086 g = con_nonlinprog! (g, mpc, model, transcription, x̂0end, Ŷ0, gc, ϵ)
10871087 geq = con_nonlinprogeq! (geq, X̂0, Û0, K, mpc, model, transcription, U0, Z̃)
@@ -1114,7 +1114,7 @@ end
11141114Evaluate the custom inequality constraint `gc` in-place and return it.
11151115"""
11161116function con_custom! (gc, mpc:: NonLinMPC , Ue, Ŷe, ϵ)
1117- mpc. con. nc ≠ 0 && mpc. con. gc! (gc, Ue, Ŷe, mpc. D̂e, mpc. p, ϵ)
1117+ mpc. con. nc > 0 && mpc. con. gc! (gc, Ue, Ŷe, mpc. D̂e, mpc. p, ϵ)
11181118 return gc
11191119end
11201120
0 commit comments