1- """
2- LinModel(model::NonLinModel; x=model.x0+model.xop, u=model.uop, d=model.dop)
1+ " A linearization buffer for the [`linearize`](@ref) function."
2+ struct LinearizationBuffer{
3+ NT <: Real ,
4+ JB_FUD <: JacobianBuffer ,
5+ JB_FXD <: JacobianBuffer ,
6+ JB_FXU <: JacobianBuffer ,
7+ JB_HD <: JacobianBuffer ,
8+ JB_HX <: JacobianBuffer
9+ }
10+ x:: Vector{NT}
11+ u:: Vector{NT}
12+ d:: Vector{NT}
13+ buffer_f_at_u_d:: JB_FUD
14+ buffer_f_at_x_d:: JB_FXD
15+ buffer_f_at_x_u:: JB_FXU
16+ buffer_h_at_d :: JB_HD
17+ buffer_h_at_x :: JB_HX
18+ function LinearizationBuffer (
19+ x:: Vector{NT} ,
20+ u:: Vector{NT} ,
21+ d:: Vector{NT} ,
22+ buffer_f_at_u_d:: JB_FUD ,
23+ buffer_f_at_x_d:: JB_FXD ,
24+ buffer_f_at_x_u:: JB_FXU ,
25+ buffer_h_at_d:: JB_HD ,
26+ buffer_h_at_x:: JB_HX
27+ ) where {NT<: Real , JB_FUD, JB_FXD, JB_FXU, JB_HD, JB_HX}
28+ return new {NT, JB_FUD, JB_FXD, JB_FXU, JB_HD, JB_HX} (
29+ x, u, d,
30+ buffer_f_at_u_d,
31+ buffer_f_at_x_d,
32+ buffer_f_at_x_u,
33+ buffer_h_at_d,
34+ buffer_h_at_x
35+ )
36+ end
37+
38+ end
339
4- Call [`linearize(model; x, u, d)`](@ref) and return the resulting linear model.
5- """
6- LinModel (model:: NonLinModel ; kwargs... ) = linearize (model; kwargs... )
40+ Base. show (io:: IO , buffer:: LinearizationBuffer ) = print (io, " LinearizationBuffer object" )
41+
42+ function LinearizationBuffer (NT, f!, h!, nu, nx, ny, nd, p)
43+ x, u, d, f_at_u_d!, f_at_x_d!, f_at_x_u!, h_at_d!, h_at_x! = get_linearize_funcs (
44+ NT, f!, h!, nu, nx, ny, nd, p
45+ )
46+ xnext, y = Vector {NT} (undef, nx), Vector {NT} (undef, ny) # TODO : to replace ?
47+ return LinearizationBuffer (
48+ x, u, d,
49+ JacobianBuffer (f_at_u_d!, xnext, x),
50+ JacobianBuffer (f_at_x_d!, xnext, u),
51+ JacobianBuffer (f_at_x_u!, xnext, d),
52+ JacobianBuffer (h_at_d!, y, x),
53+ JacobianBuffer (h_at_x!, y, d)
54+ )
55+ end
56+
57+ " Get the linearization functions for [`NonLinModel`](@ref) `f!` and `h!` functions."
58+ function get_linearize_funcs (NT, f!, h!, nu, nx, ny, nd, p)
59+ x = Vector {NT} (undef, nx)
60+ u = Vector {NT} (undef, nu)
61+ d = Vector {NT} (undef, nd)
62+ f_at_u_d! (xnext, x) = f! (xnext, x, u, d, p)
63+ f_at_x_d! (xnext, u) = f! (xnext, x, u, d, p)
64+ f_at_x_u! (xnext, d) = f! (xnext, x, u, d, p)
65+ h_at_d! (y, x) = h! (y, x, d, p)
66+ h_at_x! (y, d) = h! (y, x, d, p)
67+ return x, u, d, f_at_u_d!, f_at_x_d!, f_at_x_u!, h_at_d!, h_at_x!
68+ end
769
870@doc raw """
971 linearize(model::SimModel; x=model.x0+model.xop, u=model.uop, d=model.dop) -> linmodel
92154
93155Linearize `model` and store the result in `linmodel` (in-place).
94156
95- The keyword arguments are identical to [`linearize`](@ref). The code allocates a small
96- amount of memory to compute the Jacobians .
157+ The keyword arguments are identical to [`linearize`](@ref). The code is allocation-free if
158+ `model` simulations does not allocate .
97159
98160# Examples
99161```jldoctest
@@ -112,26 +174,22 @@ function linearize!(
112174 linmodel:: LinModel{NT} , model:: SimModel ; x= model. x0+ model. xop, u= model. uop, d= model. dop
113175) where NT<: Real
114176 nonlinmodel = model
115- buffer = nonlinmodel. buffer
177+ buffer, linbuffer = nonlinmodel. buffer, nonlinmodel . linbuffer
116178 # --- remove the operating points of the nonlinear model (typically zeros) ---
117179 x0, u0, d0 = buffer. x, buffer. u, buffer. d
118180 u0 .= u .- nonlinmodel. uop
119181 d0 .= d .- nonlinmodel. dop
120182 x0 .= x .- nonlinmodel. xop
121183 # --- compute the Jacobians at linearization points ---
122- A:: Matrix{NT} , Bu:: Matrix{NT} , Bd:: Matrix{NT} = linmodel. A, linmodel. Bu, linmodel. Bd
123- C:: Matrix{NT} , Dd:: Matrix{NT} = linmodel. C, linmodel. Dd
124184 xnext0:: Vector{NT} , y0:: Vector{NT} = linmodel. buffer. x, linmodel. buffer. y
125- myf_x0! (xnext0, x0) = f! (xnext0, nonlinmodel, x0, u0, d0, model. p)
126- myf_u0! (xnext0, u0) = f! (xnext0, nonlinmodel, x0, u0, d0, model. p)
127- myf_d0! (xnext0, d0) = f! (xnext0, nonlinmodel, x0, u0, d0, model. p)
128- myh_x0! (y0, x0) = h! (y0, nonlinmodel, x0, d0, model. p)
129- myh_d0! (y0, d0) = h! (y0, nonlinmodel, x0, d0, model. p)
130- ForwardDiff. jacobian! (A, myf_x0!, xnext0, x0)
131- ForwardDiff. jacobian! (Bu, myf_u0!, xnext0, u0)
132- ForwardDiff. jacobian! (Bd, myf_d0!, xnext0, d0)
133- ForwardDiff. jacobian! (C, myh_x0!, y0, x0)
134- ForwardDiff. jacobian! (Dd, myh_d0!, y0, d0)
185+ linbuffer. x .= x0
186+ linbuffer. u .= u0
187+ linbuffer. d .= d0
188+ jacobian! (linmodel. A, linbuffer. buffer_f_at_u_d, xnext0, x0)
189+ jacobian! (linmodel. Bu, linbuffer. buffer_f_at_x_d, xnext0, u0)
190+ jacobian! (linmodel. Bd, linbuffer. buffer_f_at_x_u, xnext0, d0)
191+ jacobian! (linmodel. C, linbuffer. buffer_h_at_d, y0, x0)
192+ jacobian! (linmodel. Dd, linbuffer. buffer_h_at_x, y0, d0)
135193 # --- compute the nonlinear model output at operating points ---
136194 xnext0, y0 = linmodel. buffer. x, linmodel. buffer. y
137195 h! (y0, nonlinmodel, x0, d0, model. p)
0 commit comments