Modia.jl
Modia.jl copied to clipboard
linearize!(model, analytic=true, ...
I tried to linearize a simple electrical system and received an error message when using option analytic=true
linearize!(model, analytic=false, ...==> OKsimulate!(...==> OK
The problem occurs when getDerivatives! is called from ForwardDiff.Jacobian, then
_leq_mode.residual_value is set to:
Any[Dual{ForwardDiff.Tag{ModiaLang.var"#modelToLinearize!#54"{SimulationModel{Float64,OrderedCollections.OrderedDict{Symbol,Any},OrderedCollections.OrderedDict{Symbol,Any},Float64}},Float64}}(-400001.0,-1000.0,-0.0,-400000.0,-0.0)]
which can not be handled by function LinearEquationsIteration.
generated function getDerivatives!
code = quote
function getDerivatives(_der_x, _x, _m, _time)::Nothing
_m.time = ModiaLang.getValue(_time)
_m.nGetDerivatives += 1
instantiatedModel = _m
_p = _m.evaluatedParameters
_leq_mode = nothing
time = _time
var"T1.X.ixRe" = _x[1]
var"T1.X.ixIm" = _x[2]
var"C1.voltsRe" = _x[3]
var"C1.voltsIm" = _x[4]
var"T1.Omegarated" = _p[:Omegarated]
var"T1.wReference" = _p[:wReference]
begin
local var"T1.X.voltsRe", var"T1.R.voltsRe", var"C1.ampsRe", var"T1.X.iparallelRe"
_leq_mode = _m.linearEquations[1]
_leq_mode.mode = -2
ModiaBase.TimerOutputs.@timeit _m.timer "LinearEquationsIteration"
while ModiaBase.LinearEquationsIteration(_leq_mode, _m.isInitial, _m.time, _m.timer)
var"T1.X.voltsRe" = _leq_mode.vTear_value[1]
var"T1.R.voltsRe" = -1var"C1.voltsRe" + -1var"T1.X.voltsRe"
var"C1.ampsRe" = var"T1.R.voltsRe" / ((_p[:T1])[:R])[:r]
var"T1.X.iparallelRe" = -((var"T1.X.ixRe" + -1var"C1.ampsRe"))
_leq_mode.residual_value[1] = ustrip(((_p[:T1])[:X])[:rparallel] * var"T1.X.iparallelRe" - var"T1.X.voltsRe")
end
_leq_mode = nothing
end
var"der(T1.X.ixRe)" = -((var"T1.X.voltsRe" - ((_p[:T1])[:X])[:x] * -(var"T1.wReference" * var"T1.X.ixIm"))) / -(((_p[:T1])[:X])[:x] * (1 / var"T1.Omegarated"))
begin
local var"T1.X.voltsIm", var"T1.R.voltsIm", var"C1.ampsIm", var"T1.X.iparallelIm"
_leq_mode = _m.linearEquations[2]
_leq_mode.mode = -2
ModiaBase.TimerOutputs.@timeit _m.timer "LinearEquationsIteration" while ModiaBase.LinearEquationsIteration(_leq_mode, _m.isInitial, _m.time, _m.timer)
var"T1.X.voltsIm" = _leq_mode.vTear_value[1]
var"T1.R.voltsIm" = -1var"C1.voltsIm" + -1var"T1.X.voltsIm"
var"C1.ampsIm" = var"T1.R.voltsIm" / ((_p[:T1])[:R])[:r]
var"T1.X.iparallelIm" = -((var"T1.X.ixIm" + -1var"C1.ampsIm"))
_leq_mode.residual_value[1] = ustrip(((_p[:T1])[:X])[:rparallel] * var"T1.X.iparallelIm" - var"T1.X.voltsIm")
end
_leq_mode = nothing
end
var"der(T1.X.ixIm)" = -((var"T1.X.voltsIm" - ((_p[:T1])[:X])[:x] * (var"T1.wReference" * var"T1.X.ixRe"))) / -(((_p[:T1])[:X])[:x] * (1 / var"T1.Omegarated"))
var"T1.R.p.vRe" = -((-1var"T1.R.voltsRe" + -1var"T1.X.voltsRe"))
var"T1.R.p.vIm" = var"T1.R.voltsIm" + var"T1.X.voltsIm"
var"C1.Omegarated" = _p[:Omegarated]
var"C1.wReference" = _p[:wReference]
var"der(C1.voltsRe)" = -((var"C1.ampsRe" * (_p[:C1])[:b] - -(var"C1.wReference" * var"C1.voltsIm"))) / -(1 / var"C1.Omegarated")
var"der(C1.voltsIm)" = -((var"C1.ampsIm" * (_p[:C1])[:b] - var"C1.wReference" * var"C1.voltsRe")) / -(1 / var"C1.Omegarated")
_der_x[1] = var"der(T1.X.ixRe)"
_der_x[2] = var"der(T1.X.ixIm)"
_der_x[3] = var"der(C1.voltsRe)"
_der_x[4] = var"der(C1.voltsIm)"
if _m.storeResult
ModiaLang.addToResult!(_m, _der_x, time, var"T1.Omegarated", var"T1.wReference", var"T1.X.voltsRe", var"T1.X.voltsIm", var"T1.X.iparallelRe", var"T1.X.iparallelIm", var"T1.R.voltsRe", var"T1.R.p.vRe", var"T1.R.voltsIm", var"T1.R.p.vIm", var"C1.Omegarated", var"C1.wReference", var"C1.ampsRe", var"C1.ampsIm")
end
return nothing
end
end
versions
"Modia" version = "0.5.0" "ModiaBase" version = "0.7.5" "ModiaLang" version = "0.8.1" Julia: Version 1.5.3 (2020-11-09) platform: LINUX x86_64
###PS: After reading your paper from the ongoing MODELICA conference, I had a better understanding but couldn't resolve it.
Yes, I know. There are also other situations where analytic=true does not work. I spent some time on it, but did not find a solution. I have documented this in the description of linearize (analytic=true might not work) and used analytic=false (numeric linearization) as a default - which should always work. A workaround is to perform linearization numerically with Double64, which should give an even higher precision as analytic linearization with Float64.
model2 = SimulationModel{Double64}(model1) # transform instantiated model1 from Float64 to Double64
(A,x0) = linearize!(model2)
below my proposal for linearize!(model, analytic=true) . Not perfect, but it works
Modification of file ModiaBase...EquationAndStateInfo.jl
structure: mutable struct LinearEquations{FloatType <: Real}
For Vectors/Matrix: A,x,b,residuals,luA , I changed the type from FloatType to Union{FloatType,Any}
mutable struct LinearEquations{FloatType <: Real}
odeMode::Bool # Set from the calling function after LinearEquations was instantiated (default: true)
# = true (standard mode): Compute "x" from equation "residuals = A*x - b"
# = false (DAE solver): During events (including initialization)
# compute "x" as for odeMode=true. Outside of events:
# (1) "x" is set from the outside (= der(x_dae) provided by DAE solver)
# (2) Compute "residuals" from "residuals := A*x - b"
# (3) From the outside copy "residuals" into "residuals_dae" of the DAE solver.
A_is_constant::Bool # = true, if A-matrix is constant
x_names::Vector{String} # Names of the x-variables
x_lengths::Vector{Int} # Lengths of the x-variables (sum(x_lengths) = length(x))
x::Vector{Union{FloatType,Any}} # Values of iteration variables
nResiduals::Int # Number of residual variables
A::Matrix{Union{FloatType,Any}}
b::Vector{Union{FloatType,Any}}
pivots::Vector{Int} # Pivot vector if recursiveFactorization = true
residuals::Vector{Union{FloatType,Any}} # Values of the residuals FloatType vector; length(residuals) = sum(residuals_length) = sum(x_lengths)
residual_value::AbstractVector # Values of the residual variables ::Vector{Any}, length(residual_values) = nResiduals
# Iteration status of for-loop
mode::Int # Operational mode (see function LinearEquationsIteration)
niter::Int # Current number of iterations in the fix point iteration scheme
niter_max::Int # Maximum number of iterations
success::Bool # = true, if solution of A*x = b is successfully computed
# = false, if solution is not computed; continue with fix point iteration
# For warning message if niter > niter_max
inconsistentPositive::Vector{String}
inconsistentNegative::Vector{String}
# Constructed during initialization
residual_unitRanges::Vector{UnitRange{Int}} # residuals[residual_unitRanges[i]] = residual_value[i], if residual is a vector
residual_indices::Vector{Int} # residuals[residual_indices[i]] = residual_value[i], if residual is a scalar
recursiveFactorization::Bool # = true, if RecursiveFactorization.jl shall be used to solve the linear equation system
luA::LU{Union{FloatType,Any},Array{Union{FloatType,Any},2}} # lu-Decomposition of A
...
This works for nx==1, but not for nx>1 when lu! is called.
additional modification in RecursiveFactorization...lu.jl
zero() function for type Dual does not exist. So I changed to convert()
function _generic_lufact!(A, ::Val{Pivot}, ipiv, info) where Pivot
m, n = size(A)
minmn = length(ipiv)
@inbounds begin
for k = 1:minmn
# find index max
kp = k
if Pivot
# =====>>>> amax = abs(zero(eltype(A))) <<<<====
amax = convert(eltype(A),0)
for i = k:m
absi = abs(A[i,k])
if absi > amax
kp = i
...
version
name = "ModiaBase" version = "0.8.0-dev"