I’m trying to linearize an ODE model…using ForwardDiff
, but don’t get the expected result. A simple example:
# Model with input functions
function watertank(dT,T,p,t,u)
# Parameters
g,h,d,per,A,rho,chp,Ux,Po = p
# Inputs
uP,uv,Ti,Ta,VdL = u
#
md = rho*uv*VdL
#
As = 2*A + per*h
V = A*h
m = rho*V
Cp = m*chp
Qd_el = Po*uP
Qd_a = Ux*As*(Ta-T[1])
dT[1] = (md*chp*(Ti-T[1]) + Qd_el + Qd_a)/Cp
#
return dT
end
Data for the model:
# -- constants
g = 9.81
h = 1.5
d = 0.5
per = pi*d
A = pi*d^2/4
rho = 1.0e3
chp = 4.19e3
Ux = 0.45
Po = 15e3
#
p = [g,h,d,per,A,rho,chp,Ux,Po];
#
T_op = [25.]
u_op = [0.5,0.5,28.,20.,8e-3/60];
Here, T_op
and u_op
constitute the operating point for the linearization. Next, I define functions which only depend on T
and u
:
wt_T(T) = watertank(copy(T),T,p,0,u_op)
wt_u(u) = watertank(copy(T_op),T_op,p,0,u)
These work as expected:
julia> wt_T(T_op)
1-element Array{Float64,1}:
0.006751564884010684
and similarly for wt_u(u_op)
.
Next, I introduce Jacobians:
J_T(T) = ForwardDiff.jacobian(wt_T,T)
J_u(u) = ForwardDiff.jacobian(wt_u,u)
The Jacobian wrt. T
works as expected:
julia> J_T(T_op)
1×1 Array{Float64,2}:
-0.00022735608347665157
HOWEVER, the Jacobian wrt. u
gives an error mesage:
julia> J_u(u_op)
MethodError: no method matching Float64(::ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5})
Closest candidates are:
Float64(::Real, !Matched::RoundingMode) where T<:AbstractFloat at rounding.jl:194
Float64(::T<:Number) where T<:Number at boot.jl:718
Float64(!Matched::Int8) at float.jl:60
...
Stacktrace:
[1] convert(::Type{Float64}, ::ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5}) at .\number.jl:7
[2] setindex!(::Array{Float64,1}, ::ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5}, ::Int64) at .\array.jl:766
[3] watertank(::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Int64, ::Array{ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5},1}) at .\In[2]:16
[4] wt_u(::Array{ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5},1}) at .\In[4]:3
[5] vector_mode_jacobian(::typeof(wt_u), ::Array{Float64,1}, ::ForwardDiff.JacobianConfig{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5,Array{ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5},1}}) at C:\Users\Bernt_Lie\.julia\packages\ForwardDiff\N0wMF\src\apiutils.jl:37
[6] jacobian(::Function, ::Array{Float64,1}, ::ForwardDiff.JacobianConfig{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5,Array{ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5},1}}, ::Val{true}) at C:\Users\Bernt_Lie\.julia\packages\ForwardDiff\N0wMF\src\jacobian.jl:17
[7] jacobian(::Function, ::Array{Float64,1}, ::ForwardDiff.JacobianConfig{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5,Array{ForwardDiff.Dual{ForwardDiff.Tag{typeof(wt_u),Float64},Float64,5},1}}) at C:\Users\Bernt_Lie\.julia\packages\ForwardDiff\N0wMF\src\jacobian.jl:15 (repeats 2 times)
[8] J_u(::Array{Float64,1}) at .\In[4]:4
[9] top-level scope at In[8]:1
What am I doing wrong?