From 9385defa36c6d81869227b8de9011ccfb1af1423 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sat, 12 Mar 2022 09:30:05 +0100 Subject: [PATCH 01/63] Initial version (not yet ready) --- src/CodeGeneration.jl | 4 +- src/EvaluateParameters.jl | 28 +++++-- test/TestLinearSystems.jl | 164 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 test/TestLinearSystems.jl diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index d9fdd8b..19d5d40 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -420,7 +420,7 @@ mutable struct SimulationModel{FloatType,TimeType} parameters = deepcopy(parameterDefinition) # Determine x_start and previous values - evaluatedParameters = propagateEvaluateAndInstantiate!(FloatType, unitless, modelModule, parameters, equationInfo, previous_dict, previous, pre_dict, pre, hold_dict, hold) + evaluatedParameters = propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitless, modelModule, parameters, equationInfo, previous_dict, previous, pre_dict, pre, hold_dict, hold) if isnothing(evaluatedParameters) return nothing end @@ -1049,7 +1049,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters if length(m.options.merge) > 0 m.parameters = mergeModels(m.parameters, m.options.merge) - m.evaluatedParameters = propagateEvaluateAndInstantiate!(FloatType, m.unitless, m.modelModule, m.parameters, m.equationInfo, m.previous_dict, m.previous, m.pre_dict, m.pre, m.hold_dict, m.hold) + m.evaluatedParameters = propagateEvaluateAndInstantiate!(FloatType, TimeType, m.buildDict, m.unitless, m.modelModule, m.parameters, m.equationInfo, m.previous_dict, m.previous, m.pre_dict, m.pre, m.hold_dict, m.hold) if isnothing(m.evaluatedParameters) return false end diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index ac54d3f..8d08bce 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -61,9 +61,9 @@ Recursively traverse the hierarchical collection `parameters` and perform the fo - Return the evaluated `parameters` if successfully evaluated, and otherwise return nothing, if an error occurred (an error message was printed). """ -function propagateEvaluateAndInstantiate!(FloatType, unitless::Bool, modelModule, parameters, eqInfo, previous_dict, previous, pre_dict, pre, hold_dict, hold; log=false) +function propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitless::Bool, modelModule, parameters, eqInfo, previous_dict, previous, pre_dict, pre, hold_dict, hold; log=false) x_found = fill(false, length(eqInfo.x_info)) - map = propagateEvaluateAndInstantiate2!(FloatType, unitless, modelModule, parameters, eqInfo, x_found, previous_dict, previous, pre_dict, pre, hold_dict, hold, [], ""; log=log) + map = propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitless, modelModule, parameters, eqInfo, x_found, previous_dict, previous, pre_dict, pre, hold_dict, hold, [], ""; log=log) if isnothing(map) return nothing @@ -163,7 +163,7 @@ function changeDotToRef(ex) end -function propagateEvaluateAndInstantiate2!(FloatType, unitless::Bool, modelModule, parameters, eqInfo::Modia.EquationInfo, x_found::Vector{Bool}, +function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitless::Bool, modelModule, parameters, eqInfo::Modia.EquationInfo, x_found::Vector{Bool}, previous_dict, previous, pre_dict, pre, hold_dict, hold, environment, path::String; log=false) if log @@ -171,9 +171,10 @@ function propagateEvaluateAndInstantiate2!(FloatType, unitless::Bool, modelModul end current = OrderedDict{Symbol,Any}() # should be Map() - # Determine, whether "parameters" has a ":_constructor" key and handle this specially - constructor = nothing - usePath = false + # Determine, whether "parameters" has a ":_constructor" or "_stateInfoFunction" key and handle this specially + constructor = nothing + stateInfoFunction = nothing + usePath = false if haskey(parameters, :_constructor) # For example: obj = (_class = :Par, _constructor = :(Modia3D.Object3D), _path = true, kwargs...) # or: rev = (_constructor = (_class = :Par, value = :(Modia3D.ModiaRevolute), _path=true), kwargs...) @@ -190,6 +191,10 @@ function propagateEvaluateAndInstantiate2!(FloatType, unitless::Bool, modelModul end end + elseif haskey(parameters, :_stateInfoFunction) + # For example: obj = (_stateInfoFunction = Par(functionPath = :(stateInfoLinearStateSpaceSystem)) + stateInfoFunction = parameters[:_stateInfoFunction][:functionPath] + elseif haskey(parameters, :value) # For example: p1 = (_class = :Var, parameter = true, value = 0.2) # or: p2 = (_class = :Var, parameter = true, value = :(2*p1)) @@ -202,7 +207,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, unitless::Bool, modelModul if log println(" 2: ... key = $k, value = $v") end - if k == :_constructor || k == :_path || (k == :_class && !isnothing(constructor)) + if k == :_constructor || k == :_stateInfoFunction || k == :_path || (k == :_class && !isnothing(constructor)) if log println(" 3: ... key = $k") end @@ -242,7 +247,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, unitless::Bool, modelModul println(" 7: ... key = $k, v = $v") end # For example: k = (a = 2.0, b = :(2*Lx)) - value = propagateEvaluateAndInstantiate2!(FloatType, unitless, modelModule, v, eqInfo, x_found, previous_dict, previous, pre_dict, pre, hold_dict, hold, + value = propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitless, modelModule, v, eqInfo, x_found, previous_dict, previous, pre_dict, pre, hold_dict, hold, vcat(environment, [current]), appendKey(path, k); log=log) if log println(" 8: ... key = $k, value = $value") @@ -322,6 +327,13 @@ function propagateEvaluateAndInstantiate2!(FloatType, unitless::Bool, modelModul end end + if !isnothing(stateInfoFunction) + # Call: stateInfoFunction(model, FloatType, Timetype, buildDict, path) + # (1) Generate an instance of subModel and store it in buildDict[path] + # (2) Define subModel states and store them in xxx + Core.eval(modelModule, :($stateInfoFunction($current, $FloatType, $TimeType, $buildDict, $path))) + end + if isnothing(constructor) return current # (; current...) else diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl new file mode 100644 index 0000000..46d611d --- /dev/null +++ b/test/TestLinearSystems.jl @@ -0,0 +1,164 @@ +module TestLinearSystems + +using Modia +using Modia.OrderedCollections +using Modia.LinearAlgebra +@usingModiaPlot + +""" + ls = LinearStateSpace(; A, B, C, x_init=nothing) + +Define a linear state space system Model: + +```math +\begin{aligned} +\frac{dx}{dt} &= A*x + B*u \\ + y &= C*x +\end{aligned} +``` + +where + +- `x_init` is the optional vector of init-values. If not provided, zeros will be used. +- The number of **inputs** and **outputs** is **fixed**, after @instantiateModel(..) was called. +- The number of **states** can be **changed** before simulation starts, + by providing appropriate ``A,B,C`` matrices and `x_init` vector as `merge` value in `simulate!(..., merge = ...)`. + +# Example +``` +using Modia +usingModiaPlot +SSTest = Model(ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[1.0;;])), # one State + y = Var(start=0.0) + equations = :[ss.u[1] = 1.0, + y = ss.y[1]] + ) +ssTest = @instantiateModel(SSTest, merge=Map(ss = Map(A=[-1/0.1 0.0; + 0.0 -1/0.2], B=[2.0/0.1;2.0/0.2;;], C=[1.0 2.0] ) # two states +simulate!(ssTest, stopTime=5.0) +plot(ssTest, ("ss.x", "u", "y")) +``` +""" +ModelLinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace!), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated + _stateInfoFunction = Par(functionPath = :(stateInfoLinearStateSpace!)), # Called once after new A,B,C values are merged + kwargs...) + +mutable struct LinearStateSpaceStruct{FloatType} + path::String # Path name of instance + A::Matrix{FloatType} + B::Matrix{FloatType} + C::Matrix{FloatType} + x_init::Vector{FloatType} # Initial values of states + x::Vector{FloatType} # Actual values of states + y::Vector{FloatType} # Internal memory for y + derx::Vector{FloatType} # Internal memory for derx + + function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, + x_init::Union{AbstractVector,Nothing}=nothing, + u::AbstractVector, y::AbstractVector, # Code generated with buildLinearStateSpace! provides start values of u and y. + path::String, kwargs...) where {FloatType} + println("... 4: LinearStateSpaceStruct called for $path") + if length(kwargs) > 0 + @warn "LinearStateSpaceStruct with path=$path ignores keyword arguments: $(kwargs...)" + end + @assert(size(A,2) == size(A,1)) + @assert(size(B,1) == size(A,1)) + @assert(size(C,2) == size(A,1)) + @assert(size(u,1) == size(B,2)) + @assert(size(y,1) == size(C,1)) + copyA = Matrix{FloatType}(deepcopy(A)) + copyB = Matrix{FloatType}(deepcopy(B)) + copyC = Matrix{FloatType}(deepcopy(C)) + copy_x_init = if isnothing(x_init); zeros(FloatType, size(A,1)) else Vector{FloatType}(deepcopy(x_init)) end + new(path, copyA, copyB, copyC, copy_x_init, copy_x_init, zeros(FloatType,size(C,1)), zeros(FloatType,size(A,1))) + end +end + +mutable struct LinearStateSpaceBuild{FloatType} + # Cannot be changed after @instantiatedModel(..) + path::String # Path name of instance, e.g. "a.b.c" + nu::Int # Number of inputs + ny::Int # Number of outputs + + # Can be changed after @instantiateModel + ls::Union{LinearStateSpaceStruct{FloatType}, Nothing} + + function LinearStateSpaceBuild{FloatType}(path::String, nu::Int, ny::Int) where {FloatType} + println("... 2: LinearStateSpaceBuild called with path = $path") + new(path,nu,ny,nothing) + end +end + + +function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, + buildDict::OrderedCollections.OrderedDict{String,Any}, + path::Union{Expr,Symbol,Nothing}) + # Called from @instantiatedModel, during instantiation of the model. + pathAsString = isnothing(path) ? "" : string(path) + println("... 1: buildLinearStateSpace! called for path = ", pathAsString) + + # Determine nu,ny from model.B. model.C + nu = size(model[:B],2) + ny = size(model[:C],1) + u_zeros = zeros(FloatType,nu) + y_zeros = zeros(FloatType,ny) + + # Define code to be generated + lsCode = Model(ls = Var(hideResult=true), + u = Var(input = true, start = u_zeros), + y = Var(output = true, start = y_zeros), + equations = :[ + ls = getLinearStateSpace!(instantiatedModel,$pathAsString) + y = computeOutputs!(ls) + success = computeStateDerivatives!(ls,u)]) + + # Store build info in buildDict + buildDict[pathAsString] = LinearStateSpaceBuild{FloatType}(pathAsString, nu, ny) + return lsCode +end + + +function stateInfoLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, + buildDict::OrderedCollections.OrderedDict{String,Any}, + path::String)::Nothing + # Called during evaluation of the parameters (before initialization) + println("... 3: stateInfoLinearStateSpace! called for $path with model = $model") + lsBuild::LinearStateSpaceBuild{FloatType} = buildDict[path] + ls = LinearStateSpaceStruct{FloatType}(; path, model...) + A = ls.A + @assert(size(A,2) == size(A,1)) + @assert(size(ls.B,2) == lsBuild.nu) + @assert(size(ls.C,1) == lsBuild.ny) + lsBuild.ls = ls + return nothing +end + + +function getLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} + ls = instantiatedModel.buildDict[path].ls + # Store states + return ls +end + +function computeOutputs!(ls) + ls.y .= 0 + mul!(ls.y, ls.C, ls.x) +end + +function computeStateDerivatives!(ls, u)::Bool + ls.derx .= 0 + mul!(ls.derx, ls.A, ls.x) + mul!(ls.derx, ls.B, u) + return true +end + +SSTest = Model( + ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[2.0;;], x_init=[1.1]), + equations = :[ss.u = [1.0], + y = ss.y] + ) +ssTest = @instantiateModel(SSTest, logCode=true) +simulate!(ssTest, stopTime=5.0) +plot(ssTest, "y") + +end \ No newline at end of file From 5e44e4b9259ed962deda3a98b6b0a12267cc6c5f Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 13 Mar 2022 09:34:00 +0100 Subject: [PATCH 02/63] Improve TestLinearSystems.jl test --- src/EvaluateParameters.jl | 9 +++++++-- test/TestLinearSystems.jl | 15 ++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 8d08bce..6520660 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -192,8 +192,13 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl end elseif haskey(parameters, :_stateInfoFunction) - # For example: obj = (_stateInfoFunction = Par(functionPath = :(stateInfoLinearStateSpaceSystem)) - stateInfoFunction = parameters[:_stateInfoFunction][:functionPath] + # For example: obj = (_stateInfoFunction = Par(functionName = :(stateInfoLinearStateSpaceSystem)) + _stateInfoFunction = parameters[:_stateInfoFunction] + if haskey(_stateInfoFunction, :functionName) + stateInfoFunction = _stateInfoFunction[:functionName] + else + @warn "Model $path has key :_stateInfoFunction but its value has no key :functionName" + end elseif haskey(parameters, :value) # For example: p1 = (_class = :Var, parameter = true, value = 0.2) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 46d611d..78960e3 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -40,7 +40,7 @@ plot(ssTest, ("ss.x", "u", "y")) ``` """ ModelLinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace!), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated - _stateInfoFunction = Par(functionPath = :(stateInfoLinearStateSpace!)), # Called once after new A,B,C values are merged + _stateInfoFunction = Par(functionName = :(stateInfoLinearStateSpace!)), # Called once after new A,B,C values are merged kwargs...) mutable struct LinearStateSpaceStruct{FloatType} @@ -55,6 +55,7 @@ mutable struct LinearStateSpaceStruct{FloatType} function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, x_init::Union{AbstractVector,Nothing}=nothing, + nu::Int, ny::Int, u::AbstractVector, y::AbstractVector, # Code generated with buildLinearStateSpace! provides start values of u and y. path::String, kwargs...) where {FloatType} println("... 4: LinearStateSpaceStruct called for $path") @@ -66,6 +67,8 @@ mutable struct LinearStateSpaceStruct{FloatType} @assert(size(C,2) == size(A,1)) @assert(size(u,1) == size(B,2)) @assert(size(y,1) == size(C,1)) + @assert(size(u,1) == nu) + @assert(size(y,1) == ny) copyA = Matrix{FloatType}(deepcopy(A)) copyB = Matrix{FloatType}(deepcopy(B)) copyC = Matrix{FloatType}(deepcopy(C)) @@ -97,9 +100,11 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: pathAsString = isnothing(path) ? "" : string(path) println("... 1: buildLinearStateSpace! called for path = ", pathAsString) - # Determine nu,ny from model.B. model.C - nu = size(model[:B],2) - ny = size(model[:C],1) + # Determine nu,ny from model (must be Integer literals >= 0) + nu::Int = model[:nu] + ny::Int = model[:ny] + @assert(nu >= 0) + @assert(ny >= 0) u_zeros = zeros(FloatType,nu) y_zeros = zeros(FloatType,ny) @@ -153,7 +158,7 @@ function computeStateDerivatives!(ls, u)::Bool end SSTest = Model( - ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[2.0;;], x_init=[1.1]), + ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[2.0;;], x_init=[1.1], nu=1, ny=1), equations = :[ss.u = [1.0], y = ss.y] ) From 9fad869fdc7b10d49695cc39c30f6d4d0b3af79b Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 13 Mar 2022 11:28:15 +0100 Subject: [PATCH 03/63] Add states in model function (incomplete) --- src/CodeGeneration.jl | 82 ++++++++++++++++++++++--------------- src/EquationAndStateInfo.jl | 28 +++++++++++++ src/EvaluateParameters.jl | 2 +- test/TestLinearSystems.jl | 31 ++++++++------ 4 files changed, 98 insertions(+), 45 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 19d5d40..2424f33 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -369,35 +369,6 @@ mutable struct SimulationModel{FloatType,TimeType} # Construct result dictionary result_info = OrderedDict{String, ResultInfo}() vSolvedWithInitValuesAndUnit2 = OrderedDict{String,Any}( [(string(key),vSolvedWithInitValuesAndUnit[key]) for key in keys(vSolvedWithInitValuesAndUnit)] ) - # Store x and der_x - for (xe_index, xe_info) in enumerate(equationInfo.x_info) - result_info[xe_info.x_name] = ResultInfo(RESULT_X , xe_index) - result_info[xe_info.der_x_name] = ResultInfo(RESULT_DER_X, xe_index) - end - - # Store variables - for (i, name) in enumerate(variableNames) - str_name = string(name) - if !haskey(result_info, str_name) - result_info[str_name] = ResultInfo(RESULT_VARS, i) - end - end - - # Store eliminated variables - for v in vEliminated - name = var_name(v) - if ModiaBase.isZero(vProperty, v) - result_info[name] = ResultInfo(RESULT_ZERO) - elseif ModiaBase.isAlias(vProperty, v) - name2 = var_name( ModiaBase.alias(vProperty, v) ) - result_info[name] = result_info[name2] - else # negated alias - name2 = var_name( ModiaBase.negAlias(vProperty, v) ) - info2 = result_info[name2] - result_info[name] = ResultInfo(info2.store, info2.index, true) - end - end - # Build previous-arrays previous = Vector{Any}(missing, length(previousVars)) previous_names = string.(previousVars) @@ -424,21 +395,54 @@ mutable struct SimulationModel{FloatType,TimeType} if isnothing(evaluatedParameters) return nothing end - x_start = initialStateVector(equationInfo, FloatType) + x_start = updateEquationInfo!(equationInfo, FloatType) nx = length(x_start) nextPrevious = deepcopy(previous) nextPre = deepcopy(pre) nextHold = deepcopy(hold) + @show equationInfo.nx + @show nx # Provide storage for x_vec - x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.x_info)] - + x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.x_info)] + # Construct data structure for linear equations linearEquations = Modia.LinearEquations{FloatType}[] for leq in equationInfo.linearEquations push!(linearEquations, Modia.LinearEquations{FloatType}(leq...)) end + # Define result + # Store x and der_x + for (xe_index, xe_info) in enumerate(equationInfo.x_info) + result_info[xe_info.x_name] = ResultInfo(RESULT_X , xe_index) + result_info[xe_info.der_x_name] = ResultInfo(RESULT_DER_X, xe_index) + end + + # Store variables + for (i, name) in enumerate(variableNames) + str_name = string(name) + if !haskey(result_info, str_name) + result_info[str_name] = ResultInfo(RESULT_VARS, i) + end + end + + # Store eliminated variables + for v in vEliminated + name = var_name(v) + if ModiaBase.isZero(vProperty, v) + result_info[name] = ResultInfo(RESULT_ZERO) + elseif ModiaBase.isAlias(vProperty, v) + name2 = var_name( ModiaBase.alias(vProperty, v) ) + result_info[name] = result_info[name2] + else # negated alias + name2 = var_name( ModiaBase.negAlias(vProperty, v) ) + info2 = result_info[name2] + result_info[name] = ResultInfo(info2.store, info2.index, true) + end + end + + # Initialize execution flags eventHandler = EventHandler{FloatType,TimeType}(nz=nz, nAfter=nAfter) eventHandler.initial = true @@ -522,6 +526,14 @@ function get_xinfo(m::SimulationModel, x_index::Int)::Tuple{Int, Int, String} end +get_state(m::SimulationModel, x_index::Int) = m.x_vec[x_index - m.equationInfo.nxFixedLength] + +function set_stateDerivative!(m::SimulationModel, x_index::Int, derx) + # Should appendVariable(m.der_x, derx), but order of derx appendVariable defined by sorting order in code!!!! + # Needs to be fixed!!!! +end + + """ v_zero = reinit(instantiatedModel, _x, j, v_new, _leqMode; v_threshold=0.01) @@ -1069,6 +1081,12 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Initialize auxiliary arrays for event iteration m.x_init .= 0 m.der_x .= 0 + @show m.equationInfo.nx + @show m.x_vec + @show m.x_start + @show m.x_init + @show m.der_x + @show m.equationInfo # Log parameters if m.options.logParameters diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index f73b816..596b9d5 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -807,6 +807,34 @@ function initialStateVector(eqInfo::EquationInfo, FloatType::Type)::Vector{Float end +function addOrUpdateStateInfo(eqInfo::EquationInfo, x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; + stateCategory::StateCategory = XD, + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false)::Int where {FloatType} + if haskey(eqInfo.x_dict, x_name) + # State is already defined. Update it. + ix = eqInfo.x_dict[x_name] + xi_info = eqInfo.x_info[ix] + @assert(xi_info.der_x_name == der_x_name) + @assert(xi_info.unit == unit) + xi_info.startOrInit = startOrInit + xi_info.nominal = nominal + xi_info.unbounded = unbounded + else + # State is not yet defined. Add it. + xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), + stateCategory, unit, startOrInit, fixed, nominal, unbounded) + push!(eqInfo.x_info, xi_info) + ix = length(eqInfo.x_info) + eqInfo.x_dict[x_name] = ix + eqInfo.der_x_dict[der_x_name] = ix + end + return ix +end + + """ x_start = updateEquationInfo!(eqInfo::EquationInfo, FloatType) diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 6520660..7b655c5 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -336,7 +336,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl # Call: stateInfoFunction(model, FloatType, Timetype, buildDict, path) # (1) Generate an instance of subModel and store it in buildDict[path] # (2) Define subModel states and store them in xxx - Core.eval(modelModule, :($stateInfoFunction($current, $FloatType, $TimeType, $buildDict, $path))) + Core.eval(modelModule, :($stateInfoFunction($current, $FloatType, $TimeType, $buildDict, $eqInfo, $path))) end if isnothing(constructor) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 78960e3..eef03ab 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -45,11 +45,11 @@ ModelLinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearState mutable struct LinearStateSpaceStruct{FloatType} path::String # Path name of instance + ix::Int # Index with respect to equationInfo.x_info A::Matrix{FloatType} B::Matrix{FloatType} C::Matrix{FloatType} x_init::Vector{FloatType} # Initial values of states - x::Vector{FloatType} # Actual values of states y::Vector{FloatType} # Internal memory for y derx::Vector{FloatType} # Internal memory for derx @@ -73,7 +73,7 @@ mutable struct LinearStateSpaceStruct{FloatType} copyB = Matrix{FloatType}(deepcopy(B)) copyC = Matrix{FloatType}(deepcopy(C)) copy_x_init = if isnothing(x_init); zeros(FloatType, size(A,1)) else Vector{FloatType}(deepcopy(x_init)) end - new(path, copyA, copyB, copyC, copy_x_init, copy_x_init, zeros(FloatType,size(C,1)), zeros(FloatType,size(A,1))) + new(path, 0, copyA, copyB, copyC, copy_x_init, zeros(FloatType,size(C,1)), zeros(FloatType,size(A,1))) end end @@ -113,9 +113,9 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: u = Var(input = true, start = u_zeros), y = Var(output = true, start = y_zeros), equations = :[ - ls = getLinearStateSpace!(instantiatedModel,$pathAsString) - y = computeOutputs!(ls) - success = computeStateDerivatives!(ls,u)]) + ls = getLinearStateSpace!(instantiatedModel, $pathAsString) + y = computeOutputs!(instantiatedModel, ls) + success = computeStateDerivatives!(instantiatedModel, ls, u)]) # Store build info in buildDict buildDict[pathAsString] = LinearStateSpaceBuild{FloatType}(pathAsString, nu, ny) @@ -125,6 +125,7 @@ end function stateInfoLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, buildDict::OrderedCollections.OrderedDict{String,Any}, + eqInfo::Modia.EquationInfo, path::String)::Nothing # Called during evaluation of the parameters (before initialization) println("... 3: stateInfoLinearStateSpace! called for $path with model = $model") @@ -134,10 +135,11 @@ function stateInfoLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeTy @assert(size(A,2) == size(A,1)) @assert(size(ls.B,2) == lsBuild.nu) @assert(size(ls.C,1) == lsBuild.ny) - lsBuild.ls = ls + ls.ix = Modia.addOrUpdateStateInfo(eqInfo, path*".x", path*".der(x)", ls.x_init) + lsBuild.ls = ls return nothing end - + function getLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls @@ -145,15 +147,19 @@ function getLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeT return ls end -function computeOutputs!(ls) +function computeOutputs!(instantiatedModel, ls) + x = Modia.get_state(instantiatedModel, ls.ix) ls.y .= 0 - mul!(ls.y, ls.C, ls.x) + mul!(ls.y, ls.C, x) end -function computeStateDerivatives!(ls, u)::Bool +function computeStateDerivatives!(instantiatedModel, ls, u)::Bool + x = Modia.getState(instantiatedModel, ls.ix) ls.derx .= 0 - mul!(ls.derx, ls.A, ls.x) + + mul!(ls.derx, ls.A, x) mul!(ls.derx, ls.B, u) + Modia.set_stateDerivative!(instantiatedModel, ls.ix, ls.derx) return true end @@ -164,6 +170,7 @@ SSTest = Model( ) ssTest = @instantiateModel(SSTest, logCode=true) simulate!(ssTest, stopTime=5.0) -plot(ssTest, "y") +Modia.printResultInfo(ssTest) +plot(ssTest, ("ss.x", "ss.u", "y")) end \ No newline at end of file From 4993f87f3e93b402ef2da6669b4e68d9ce04f3bf Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 24 Apr 2022 19:06:25 +0200 Subject: [PATCH 04/63] * Add states in model function (has bugs) --- Project.toml | 2 +- src/CodeGeneration.jl | 148 ++++++++++++++++++++++++++---------- src/EquationAndStateInfo.jl | 21 ++++- src/Modia.jl | 4 +- src/ModiaLang.jl | 3 +- src/SimulateAndPlot.jl | 4 +- test/TestLinearSystems.jl | 27 ++++--- 7 files changed, 145 insertions(+), 64 deletions(-) diff --git a/Project.toml b/Project.toml index 81531f0..7eac0a0 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ authors = ["Hilding Elmqvist ", "Martin Otter "] name = "Modia" uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e" -version = "0.8.3" +version = "0.8.4-dev" [compat] DataFrames = "1" diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 2424f33..3fa2aae 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -334,10 +334,13 @@ mutable struct SimulationModel{FloatType,TimeType} time::TimeType nGetDerivatives::Int # Number of getDerivatives! calls nf::Int # Number of getDerivatives! calls from integrator (without zero-crossing calls) - x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of state vector element equationInfo.x_info[equationInfo.nxFixedLength+i] + x::Vector{FloatType} # Reference of x-vector passed to getDerivatives!(..) + x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nxFixedLength+i] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) - der_x::Vector{FloatType} # Derivatives of states x or x_init + der_x_visible::Vector{FloatType} # Derivatives of states x or x_init that correspond to visible states + der_x_hidden::Vector{FloatType} # Derivatives of states x or x_init that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) + der_x_full::Vector{FloatType} # Derivatives of states x (needed in DAE mode) odeIntegrator::Bool # = true , if ODE integrator used # = false, if DAE integrator used @@ -400,11 +403,11 @@ mutable struct SimulationModel{FloatType,TimeType} nextPrevious = deepcopy(previous) nextPre = deepcopy(pre) nextHold = deepcopy(hold) - @show equationInfo.nx - @show nx + #@show equationInfo.nx + #@show nx # Provide storage for x_vec - x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.x_info)] + x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.nxVisibleLength)] # Construct data structure for linear equations linearEquations = Modia.LinearEquations{FloatType}[] @@ -458,8 +461,9 @@ mutable struct SimulationModel{FloatType,TimeType} previous, nextPrevious, previous_names, previous_dict, pre, nextPre, pre_names, pre_dict, hold, nextHold, hold_names, hold_dict, - isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, - x_vec, x_start, zeros(FloatType,nx), zeros(FloatType,nx), true, LinearEquationsCopyInfoForDAEMode[], + isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, zeros(FloatType,0), + x_vec, x_start, zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), + zeros(FloatType,nx), true, LinearEquationsCopyInfoForDAEMode[], missing, false, result_info, Tuple[], missing, Vector{FloatType}[], false, unitless) end @@ -487,8 +491,9 @@ mutable struct SimulationModel{FloatType,TimeType} deepcopy(m.previous), deepcopy(m.nextPrevious), m.previous_names, m.previous_dict, deepcopy(m.pre), deepcopy(m.nextPre), m.pre_names, m.pre_dict, deepcopy(m.hold), deepcopy(m.nextHold), m.hold_names, m.hold_dict, - isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, deepcopy(m.x_vec), - convert(Vector{FloatType}, m.x_start), zeros(FloatType,nx), zeros(FloatType,nx), true, LinearEquationsCopyInfoForDAEMode[], + isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, zeros(FloatType,0), deepcopy(m.x_vec), + convert(Vector{FloatType}, m.x_start), zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), + zeros(FloatType,nx), true, LinearEquationsCopyInfoForDAEMode[], missing, false, m.result_info, Tuple[], missing, Vector{FloatType}[], false, m.unitless) end end @@ -525,12 +530,38 @@ function get_xinfo(m::SimulationModel, x_index::Int)::Tuple{Int, Int, String} return (ibeg, iend, xinfo.unit) end +export copyState! -get_state(m::SimulationModel, x_index::Int) = m.x_vec[x_index - m.equationInfo.nxFixedLength] +""" + copyState!(m::SimulationModel, x_index::Int, xi) + +Copy state of m.equationInfo.x_info[x_index] into pre-allocated vector xi. +""" +function copyState!(m::SimulationModel{FloatType,TimeType}, x_index::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} + @assert(length(xi) == m.equationInfo.x_info[x_index].length) + startIndex = m.equationInfo.x_info[x_index].startIndex - 1 + for i = 1:length(xi) + xi[i] = m.x[startIndex+i] + end + return nothing +end + + +""" + set_hiddenStateDerivative!(m::SimulationModel, x_index, der_x) -function set_stateDerivative!(m::SimulationModel, x_index::Int, derx) - # Should appendVariable(m.der_x, derx), but order of derx appendVariable defined by sorting order in code!!!! - # Needs to be fixed!!!! +Copy hidden state derivative der_x of m.equationInfo.x_info[x_index] into full state derivative vector +""" +function set_hiddenStateDerivative!(m::SimulationModel, x_index::Int, der_x)::Nothing + @assert(length(der_x) == m.equationInfo.x_info[x_index].length) + startIndex = m.equationInfo.x_info[x_index].startIndex - m.equationInfo.nxVisible - 1 + #@show startIndex + #@show m.der_x_hidden + #@show der_x + for i = 1:length(der_x) + m.der_x_hidden[startIndex+i] = der_x[i] + end + return nothing end @@ -1013,21 +1044,18 @@ invokelatest_getDerivatives_without_der_x!(x, m, t) = TimerOutputs.@timeit m.tim eqInfo = m.equationInfo x_vec = m.x_vec j = 0 - for i in eqInfo.nxFixedLength+1:length(eqInfo.x_info) + for i in eqInfo.nxFixedLength+1:eqInfo.nxVisibleLength j += 1 xe = eqInfo.x_info[i] x_vec[j] .= x[xe.startIndex:(xe.startIndex+xe.length-1)] end end - empty!(m.der_x) + empty!(m.der_x_visible) + m.der_x_hidden .= 0 + m.x = x Base.invokelatest(m.getDerivatives!, x, m, t) - @assert(length(m.der_x) == m.equationInfo.nx) -end - -invokelatest_getDerivatives!(der_x, x, m, t) = begin - invokelatest_getDerivatives_without_der_x!(x, m, t) - der_x .= m.der_x + @assert(length(m.der_x_visible) + length(m.der_x_hidden) == length(x)) end @@ -1073,21 +1101,28 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti m.x_start = updateEquationInfo!(m.equationInfo, FloatType) nx = length(m.x_start) resize!(m.x_init, nx) - resize!(m.der_x, nx) + resize!(m.der_x_visible, m.equationInfo.nxVisible) + resize!(m.der_x_hidden , nx - m.equationInfo.nxVisible) + resize!(m.der_x_full , nx) eqInfo = m.equationInfo - m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nxFixedLength+1:length(eqInfo.x_info)] + m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nxFixedLength+1:eqInfo.nxVisibleLength] end # Initialize auxiliary arrays for event iteration m.x_init .= 0 - m.der_x .= 0 + m.der_x_visible .= 0 + m.der_x_hidden .= 0 + m.der_x_full .= 0 + #= @show m.equationInfo.nx @show m.x_vec @show m.x_start @show m.x_init - @show m.der_x + @show m.der_x_visible + @show m.der_x_hidden @show m.equationInfo - + =# + # Log parameters if m.options.logParameters parameters = m.parameters @@ -1215,22 +1250,24 @@ function outputs!(x, t, integrator)::Nothing invokelatest_getDerivatives_without_der_x!(x, m, t) else if t==m.options.startTime - m.der_x .= integrator.du # Since IDA gives an error for integrator(t, Val{1]}) at the initial time instant + m.der_x_full .= integrator.du # Since IDA gives an error for integrator(t, Val{1]}) at the initial time instant else - integrator(m.der_x, t, Val{1}) # Compute derx + integrator(m.der_x_full, t, Val{1}) # Compute derx by interpolation end # Copy derx to linearEquations for copyInfo in m.daeCopyInfo leq = m.linearEquations[ copyInfo.ileq ] for i in 1:length(copyInfo.index) - leq.x[i] = m.der_x[ copyInfo.index[i] ] + leq.x[i] = m.der_x_full[ copyInfo.index[i] ] end end m.solve_leq = false invokelatest_getDerivatives_without_der_x!(x, m, t) m.solve_leq = true end + copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) + push!(m.result_der_x, deepcopy(m.der_x_full)) m.storeResult = false if !m.success m.result_x = integrator.sol @@ -1267,15 +1304,42 @@ end =# +""" + copyDerivatives!(der_x, der_x_visible, der_x_hidden) + +Copy der_x_visible and der_x_hidden to der_x (der_x .= [der_x_visible, der_x_hidden]) +""" +@inline function copyDerivatives!(der_x, der_x_visible, der_x_hidden)::Nothing + if length(der_x_hidden) == 0 + der_x .= der_x_visible + else + @inbounds begin + @assert(length(der_x) == length(der_x_visible) + length(der_x_hidden)) + for i = 1:length(der_x_visible) + der_x[i] = der_x_visible[i] + end + istart = length(der_x_visible) + for i = 1:length(der_x_hidden) + der_x[istart+i] = der_x_hidden[i] + end + end + end + return nothing +end + + """ derivatives!(derx, x, m, t) DifferentialEquations callback function to get the derivatives. """ -derivatives!(der_x, x, m, t) = begin - m.nf += 1 - invokelatest_getDerivatives!(der_x, x, m, t) - end +function derivatives!(der_x, x, m, t) + m.nf += 1 + invokelatest_getDerivatives_without_der_x!(x, m, t) + copyDerivatives!(der_x, m.der_x_visible, m.der_x_hidden) + return nothing +end + """ @@ -1297,8 +1361,10 @@ function DAEresidualsForODE!(residuals, derx, x, m, t)::Nothing m.solve_leq = false invokelatest_getDerivatives_without_der_x!(x, m, t) m.solve_leq = true - residuals .= m.der_x .- derx - + + copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) + residuals .= m.der_x_full .- derx + # Get residuals from linearEquations for copyInfo in m.daeCopyInfo leq = m.linearEquations[ copyInfo.ileq ] @@ -1528,7 +1594,6 @@ It is assumed that the first variable in `variableValues` is `time`. """ function addToResult!(m::SimulationModel, variableValues...)::Nothing push!(m.result_vars , variableValues) - push!(m.result_der_x, deepcopy(m.der_x)) return nothing end @@ -1573,7 +1638,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati if length(x_info) == 1 && x_info[1].x_name == "_dummy_x" && x_info[1].der_x_name == "der(_dummy_x)" # Explicitly solved pure algebraic variables. Introduce dummy equation - push!(code_der_x, :( Modia.appendVariable!(_m.der_x, -_x[1]) )) + push!(code_der_x, :( Modia.appendVariable!(_m.der_x_visible, -_x[1]) )) else i1 = 1 for i in 1:equationInfo.nxFixedLength @@ -1609,7 +1674,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati end i1 = 0 - for i in equationInfo.nxFixedLength+1:length(equationInfo.x_info) + for i in equationInfo.nxFixedLength+1:equationInfo.nxVisibleLength # x-element is a dynamic vector (length can change before initialization) xe = x_info[i] x_name = xe.x_name_julia @@ -1622,12 +1687,13 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati end end - for xe in equationInfo.x_info + for i in 1:equationInfo.nxVisibleLength + xe = equationInfo.x_info[i] der_x_name = xe.der_x_name_julia if hasUnits - push!(code_der_x, :( Modia.appendVariable!(_m.der_x, Modia.stripUnit( $der_x_name )) )) + push!(code_der_x, :( Modia.appendVariable!(_m.der_x_visible, Modia.stripUnit( $der_x_name )) )) else - push!(code_der_x, :( Modia.appendVariable!(_m.der_x, $der_x_name) )) + push!(code_der_x, :( Modia.appendVariable!(_m.der_x_visible, $der_x_name) )) end end end diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 596b9d5..43cdf9a 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -731,7 +731,10 @@ mutable struct EquationInfo linearEquations::Vector{Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}} vSolvedWithFixedTrue::Vector{String} nx::Int # = length(x) or -1 if not yet known - nxFixedLength::Int # x_info[1:nxFixedLengt] are states with fixed length (does not change after compilation) + nxVisible::Int # = number of visible x-elements or -1 if not yet known + nxFixedLength::Int # x_info[1:nxFixedLength] are states with fixed length (does not change after compilation) or -1 if not yet known + nxVisibleLength::Int # x_info[1:nxVisibleLength] are states that are visible in getDerivatives!(..) or -1 if not yet known + # x_info[nxVisibleLength+1:end] are states defined in functions that are not visible in getDerivatives!(..) x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] # or empty vector, if not yet known. x_dict::OrderedCollections.OrderedDict{String,Int} # x_dict[x_name] returns the index of x_name with respect to x_info @@ -750,12 +753,14 @@ EquationInfo(; status = MANUAL, linearEquations = Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}[], vSolvedWithFixedTrue = String[], nxFixedLength = -1, + nxVisibleLength = -1, x_infoByIndex = Int[], defaultParameterAndStartValues::Union{AbstractDict,Nothing} = nothing, ResultType = nothing, ResultTypeHasFloatType = false) = EquationInfo(status, ode, nz, x_info, residualCategories, linearEquations, - vSolvedWithFixedTrue, stateVectorLength(x_info), -1, x_infoByIndex, + vSolvedWithFixedTrue, -1, -1, + nxFixedLength, nxVisibleLength , x_infoByIndex, OrderedCollections.OrderedDict{String,Int}(), OrderedCollections.OrderedDict{String,Int}(), defaultParameterAndStartValues, @@ -777,7 +782,9 @@ function initEquationInfo!(eqInfo::EquationInfo)::Nothing xi_info.startIndex = startIndex startIndex += xi_info.length end - eqInfo.nx = startIndex - 1 + eqInfo.nx = startIndex - 1 + eqInfo.nxVisible = eqInfo.nx + eqInfo.nxVisibleLength = length(eqInfo.x_info) return nothing end @@ -841,7 +848,8 @@ end Set eqInfo.x_dict, eqInfo.der_x_dict, eqInfo.nx and eqInfo.x_info[:].startIndex """ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} - nxFixedLength = eqInfo.nxFixedLength + nxFixedLength = eqInfo.nxFixedLength + nxVisibleLength = eqInfo.nxVisibleLength if nxFixedLength == 0 startIndex = 1 else @@ -857,6 +865,11 @@ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex += xi_info.length end eqInfo.nx = startIndex - 1 + + nxVisible = 0 + for i = nxVisibleLength+1:length(x_info) + nxVisible += x_info[i].length + end return initialStateVector(eqInfo, FloatType) end diff --git a/src/Modia.jl b/src/Modia.jl index 7842298..da3f530 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -9,8 +9,8 @@ Main module of Modia. module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory -const Version = "0.8.2" -const Date = "2022-03-08" +const Version = "0.8.4-dev" +const Date = "2022-04-24" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 08e2e28..d6b591c 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -723,7 +723,8 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # convertedStartValues = convert(Vector{FloatType}, [ustrip(v) for v in startValues]) # ustrip.(value) does not work for MonteCarloMeasurements # @show mappedParameters - x_startValues = initialStateVector(equationInfo, FloatType) + x_startValues = nothing # deprecated, is no longer used; just temporarily kept for backwards compatibility + # = initialStateVector(equationInfo, FloatType) # println("Build SimulationModel") diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 1dede57..2aec44d 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -271,7 +271,8 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me m.odeIntegrator = false nx = length(m.x_init) differential_vars = eh.nz > 0 ? fill(true, nx) : nothing # due to DifferentialEquations issue #549 - TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x, m.x_init, tspan, m, differential_vars = differential_vars) + copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) + TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x_full, m.x_init, tspan, m, differential_vars = differential_vars) empty!(m.daeCopyInfo) if length(sizesOfLinearEquationSystems) > 0 && maximum(sizesOfLinearEquationSystems) >= options.nlinearMinForDAE # Prepare data structure to efficiently perform copy operations for DAE integrator @@ -649,6 +650,7 @@ function ModiaResult.rawSignal(m::SimulationModel, name::AbstractString) end if haskey(m.result_info, name) + #println("rawSignal: name = $name") resInfo = m.result_info[name] if resInfo.store == RESULT_X diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index eef03ab..b564661 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -51,6 +51,7 @@ mutable struct LinearStateSpaceStruct{FloatType} C::Matrix{FloatType} x_init::Vector{FloatType} # Initial values of states y::Vector{FloatType} # Internal memory for y + x::Vector{FloatType} # Internal memory for x derx::Vector{FloatType} # Internal memory for derx function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, @@ -73,7 +74,7 @@ mutable struct LinearStateSpaceStruct{FloatType} copyB = Matrix{FloatType}(deepcopy(B)) copyC = Matrix{FloatType}(deepcopy(C)) copy_x_init = if isnothing(x_init); zeros(FloatType, size(A,1)) else Vector{FloatType}(deepcopy(x_init)) end - new(path, 0, copyA, copyB, copyC, copy_x_init, zeros(FloatType,size(C,1)), zeros(FloatType,size(A,1))) + new(path, 0, copyA, copyB, copyC, copy_x_init, zeros(FloatType,size(C,1)), zeros(FloatType, size(A,1)), zeros(FloatType,size(A,1))) end end @@ -143,34 +144,32 @@ end function getLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls - # Store states + copyState!(instantiatedModel, ls.ix, ls.x) return ls end -function computeOutputs!(instantiatedModel, ls) - x = Modia.get_state(instantiatedModel, ls.ix) - ls.y .= 0 - mul!(ls.y, ls.C, x) +function computeOutputs!(instantiatedModel::SimulationModel{FloatType,TimeType}, ls)::Vector{FloatType} where {FloatType,TimeType} + mul!(ls.y, ls.C, ls.x) + return ls.y end function computeStateDerivatives!(instantiatedModel, ls, u)::Bool - x = Modia.getState(instantiatedModel, ls.ix) - ls.derx .= 0 - - mul!(ls.derx, ls.A, x) + mul!(ls.derx, ls.A, ls.x) mul!(ls.derx, ls.B, u) - Modia.set_stateDerivative!(instantiatedModel, ls.ix, ls.derx) + Modia.set_hiddenStateDerivative!(instantiatedModel, ls.ix, ls.derx) return true end +# ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[2.0;;], x_init=[1.1], nu=1, ny=1), + SSTest = Model( - ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[2.0;;], x_init=[1.1], nu=1, ny=1), + ss = ModelLinearStateSpace(A=[-0.1;;], B=[1.0;;], C=[1.0;;], x_init=[1.1], nu=1, ny=1), equations = :[ss.u = [1.0], y = ss.y] ) ssTest = @instantiateModel(SSTest, logCode=true) -simulate!(ssTest, stopTime=5.0) +simulate!(ssTest, stopTime=0.1, log=true, logStates=true) Modia.printResultInfo(ssTest) -plot(ssTest, ("ss.x", "ss.u", "y")) +plot(ssTest, ("ss.x", "ss.u", "ss.y")) end \ No newline at end of file From b29f338dcfbe0bf7c769be2050683a3edfd8ee3e Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 1 May 2022 11:23:35 +0200 Subject: [PATCH 05/63] Add states in model function: initial correct version --- src/CodeGeneration.jl | 14 +++++++------- test/TestLinearSystems.jl | 35 +++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 3fa2aae..34611ff 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -535,7 +535,7 @@ export copyState! """ copyState!(m::SimulationModel, x_index::Int, xi) -Copy state of m.equationInfo.x_info[x_index] into pre-allocated vector xi. +Copy state of m.equationInfo.x_info[x_index] from m.x into pre-allocated vector xi. """ function copyState!(m::SimulationModel{FloatType,TimeType}, x_index::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} @assert(length(xi) == m.equationInfo.x_info[x_index].length) @@ -554,13 +554,12 @@ Copy hidden state derivative der_x of m.equationInfo.x_info[x_index] into full s """ function set_hiddenStateDerivative!(m::SimulationModel, x_index::Int, der_x)::Nothing @assert(length(der_x) == m.equationInfo.x_info[x_index].length) + #println("set_hiddenStateDerivative!: x_index = $x_index, der_x = $der_x") startIndex = m.equationInfo.x_info[x_index].startIndex - m.equationInfo.nxVisible - 1 - #@show startIndex - #@show m.der_x_hidden - #@show der_x for i = 1:length(der_x) m.der_x_hidden[startIndex+i] = der_x[i] end + #println("m.der_x_hidden = ", m.der_x_hidden) return nothing end @@ -1031,7 +1030,7 @@ get_xe(x, xe_info) = xe_info.length == 1 ? x[xe_info.startIndex] : x[xe_info.sta #end import Printf -invokelatest_getDerivatives_without_der_x!(x, m, t) = TimerOutputs.@timeit m.timer "Modia getDerivatives!" begin +invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing = TimerOutputs.@timeit m.timer "Modia getDerivatives!" begin if m.options.logProgress && m.cpuLast != UInt64(0) cpuNew = time_ns() if (cpuNew - m.cpuLast) * 1e-9 > 5.0 @@ -1056,6 +1055,7 @@ invokelatest_getDerivatives_without_der_x!(x, m, t) = TimerOutputs.@timeit m.tim Base.invokelatest(m.getDerivatives!, x, m, t) @assert(length(m.der_x_visible) + length(m.der_x_hidden) == length(x)) + return nothing end @@ -1592,8 +1592,8 @@ end Add `variableValues...` to `simulationModel::SimulationModel`. It is assumed that the first variable in `variableValues` is `time`. """ -function addToResult!(m::SimulationModel, variableValues...)::Nothing - push!(m.result_vars , variableValues) +@inline function addToResult!(m::SimulationModel, variableValues...)::Nothing + push!(m.result_vars , deepcopy(variableValues)) return nothing end diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index b564661..8ef8953 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -59,7 +59,7 @@ mutable struct LinearStateSpaceStruct{FloatType} nu::Int, ny::Int, u::AbstractVector, y::AbstractVector, # Code generated with buildLinearStateSpace! provides start values of u and y. path::String, kwargs...) where {FloatType} - println("... 4: LinearStateSpaceStruct called for $path") + #println("... 4: LinearStateSpaceStruct called for $path") if length(kwargs) > 0 @warn "LinearStateSpaceStruct with path=$path ignores keyword arguments: $(kwargs...)" end @@ -88,7 +88,7 @@ mutable struct LinearStateSpaceBuild{FloatType} ls::Union{LinearStateSpaceStruct{FloatType}, Nothing} function LinearStateSpaceBuild{FloatType}(path::String, nu::Int, ny::Int) where {FloatType} - println("... 2: LinearStateSpaceBuild called with path = $path") + #println("... 2: LinearStateSpaceBuild called with path = $path") new(path,nu,ny,nothing) end end @@ -99,7 +99,7 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: path::Union{Expr,Symbol,Nothing}) # Called from @instantiatedModel, during instantiation of the model. pathAsString = isnothing(path) ? "" : string(path) - println("... 1: buildLinearStateSpace! called for path = ", pathAsString) + #println("... 1: buildLinearStateSpace! called for path = ", pathAsString) # Determine nu,ny from model (must be Integer literals >= 0) nu::Int = model[:nu] @@ -110,9 +110,10 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: y_zeros = zeros(FloatType,ny) # Define code to be generated - lsCode = Model(ls = Var(hideResult=true), - u = Var(input = true, start = u_zeros), - y = Var(output = true, start = y_zeros), + lsCode = Model(ls = Var(hideResult=true), + success = Var(hideResult=true), + u = Var(input = true, start = u_zeros), + y = Var(output = true, start = y_zeros), equations = :[ ls = getLinearStateSpace!(instantiatedModel, $pathAsString) y = computeOutputs!(instantiatedModel, ls) @@ -129,7 +130,7 @@ function stateInfoLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeTy eqInfo::Modia.EquationInfo, path::String)::Nothing # Called during evaluation of the parameters (before initialization) - println("... 3: stateInfoLinearStateSpace! called for $path with model = $model") + #println("... 3: stateInfoLinearStateSpace! called for $path with model = $model") lsBuild::LinearStateSpaceBuild{FloatType} = buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) A = ls.A @@ -148,28 +149,30 @@ function getLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeT return ls end -function computeOutputs!(instantiatedModel::SimulationModel{FloatType,TimeType}, ls)::Vector{FloatType} where {FloatType,TimeType} +function computeOutputs!(instantiatedModel, ls) mul!(ls.y, ls.C, ls.x) return ls.y end function computeStateDerivatives!(instantiatedModel, ls, u)::Bool + # ls.derx .= ls.A*ls.x + ls.B*u mul!(ls.derx, ls.A, ls.x) - mul!(ls.derx, ls.B, u) + mul!(ls.derx, ls.B, u, 1.0, 1.0) Modia.set_hiddenStateDerivative!(instantiatedModel, ls.ix, ls.derx) return true end - -# ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[2.0;;], x_init=[1.1], nu=1, ny=1), - + +# T*der(x) + x = u +T = 0.2; SSTest = Model( - ss = ModelLinearStateSpace(A=[-0.1;;], B=[1.0;;], C=[1.0;;], x_init=[1.1], nu=1, ny=1), - equations = :[ss.u = [1.0], + ss = ModelLinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2], nu=1, ny=1), + equations = :[ss.u = [2.0], y = ss.y] ) + ssTest = @instantiateModel(SSTest, logCode=true) -simulate!(ssTest, stopTime=0.1, log=true, logStates=true) -Modia.printResultInfo(ssTest) +simulate!(ssTest, stopTime=1.0, log=true, logStates=true) +#Modia.printResultInfo(ssTest) plot(ssTest, ("ss.x", "ss.u", "ss.y")) end \ No newline at end of file From 607ec96016612f97208866ea959e864d674e73dd Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 1 May 2022 12:02:24 +0200 Subject: [PATCH 06/63] Cleanup of TestLinearSystems.jl --- test/TestLinearSystems.jl | 70 +++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 8ef8953..8d88d99 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -20,26 +20,38 @@ Define a linear state space system Model: where - `x_init` is the optional vector of init-values. If not provided, zeros will be used. -- The number of **inputs** and **outputs** is **fixed**, after @instantiateModel(..) was called. -- The number of **states** can be **changed** before simulation starts, - by providing appropriate ``A,B,C`` matrices and `x_init` vector as `merge` value in `simulate!(..., merge = ...)`. +- The number of **inputs** (= `size(B,2)`) and **outputs** (= `size(C,1)`) is **fixed**, after @instantiateModel(..) was called. +- The number of **states** (= `size(A,1)`) can be **changed** before simulation starts, + by providing appropriate ``A,B,C`` matrices and `x_init` vector as `merge` values in `simulate!(..., merge = ...)`. # Example ``` using Modia -usingModiaPlot -SSTest = Model(ss = ModelLinearStateSpace(A=[-1/0.1;;], B=[2.0/0.1;;], C=[1.0;;])), # one State - y = Var(start=0.0) - equations = :[ss.u[1] = 1.0, - y = ss.y[1]] +@usingModiaPlot + +# T*der(x) + x = u +T = 0.2; +SSTest = Model( + ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), # one state + equations = :[ss.u = 2.0, + y = ss.y[1]] ) -ssTest = @instantiateModel(SSTest, merge=Map(ss = Map(A=[-1/0.1 0.0; - 0.0 -1/0.2], B=[2.0/0.1;2.0/0.2;;], C=[1.0 2.0] ) # two states -simulate!(ssTest, stopTime=5.0) -plot(ssTest, ("ss.x", "u", "y")) + +ssTest = @instantiateModel(SSTest, logCode=true) +simulate!(ssTest, stopTime=1.0, log=true, logStates=true) +plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) + +simulate!(ssTest, stopTime=1.0, log=true, logStates=true, + merge=Map(ss = Map(A=[-1/T 0.0; + 0.0 -1/T], + B=[1.0/T; + 1.0/T;;], + C=[0.4 0.4;], + x_init=[0.2,0.4]))) # two states +plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) ``` """ -ModelLinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace!), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated +LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace!), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated _stateInfoFunction = Par(functionName = :(stateInfoLinearStateSpace!)), # Called once after new A,B,C values are merged kwargs...) @@ -56,7 +68,6 @@ mutable struct LinearStateSpaceStruct{FloatType} function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, x_init::Union{AbstractVector,Nothing}=nothing, - nu::Int, ny::Int, u::AbstractVector, y::AbstractVector, # Code generated with buildLinearStateSpace! provides start values of u and y. path::String, kwargs...) where {FloatType} #println("... 4: LinearStateSpaceStruct called for $path") @@ -68,8 +79,8 @@ mutable struct LinearStateSpaceStruct{FloatType} @assert(size(C,2) == size(A,1)) @assert(size(u,1) == size(B,2)) @assert(size(y,1) == size(C,1)) - @assert(size(u,1) == nu) - @assert(size(y,1) == ny) + @assert(size(u,1) == size(B,2)) + @assert(size(y,1) == size(C,1)) copyA = Matrix{FloatType}(deepcopy(A)) copyB = Matrix{FloatType}(deepcopy(B)) copyC = Matrix{FloatType}(deepcopy(C)) @@ -101,11 +112,11 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: pathAsString = isnothing(path) ? "" : string(path) #println("... 1: buildLinearStateSpace! called for path = ", pathAsString) - # Determine nu,ny from model (must be Integer literals >= 0) - nu::Int = model[:nu] - ny::Int = model[:ny] - @assert(nu >= 0) - @assert(ny >= 0) + # Determine nu,ny from model + B = model[:B] + C = model[:C] + nu = size(B,2) + ny = size(C,1) u_zeros = zeros(FloatType,nu) y_zeros = zeros(FloatType,ny) @@ -165,14 +176,23 @@ end # T*der(x) + x = u T = 0.2; SSTest = Model( - ss = ModelLinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2], nu=1, ny=1), - equations = :[ss.u = [2.0], - y = ss.y] + ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), # one state + equations = :[ss.u = 2.0, + y = ss.y[1]] ) ssTest = @instantiateModel(SSTest, logCode=true) simulate!(ssTest, stopTime=1.0, log=true, logStates=true) #Modia.printResultInfo(ssTest) -plot(ssTest, ("ss.x", "ss.u", "ss.y")) +plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) + +simulate!(ssTest, stopTime=1.0, log=true, logStates=true, + merge=Map(ss = Map(A=[-1/T 0.0; + 0.0 -1/T], + B=[1.0/T; + 1.0/T;;], + C=[0.4 0.4;], + x_init=[0.2,0.4]))) # two states +plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) end \ No newline at end of file From f8782b2053cc402797c7e91b59a98aa5eb2144ae Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 1 May 2022 13:31:55 +0200 Subject: [PATCH 07/63] - Added state of dummy differential equation (if model has only algebraic variables) as hidden state, and do no longer generate code for it. - Added function removeHiddenStates(equationInfo). - Remove hidden states, before parameters are evaluated with propagateEvaluateAndInstantiate!(..). - Rename function addOrUpdateStateInfo(..) to addState(..). - Remove not used vector x_infoByIndex from EquationInfo. --- src/CodeGeneration.jl | 2 +- src/EquationAndStateInfo.jl | 116 +++++++++++++++++++++--------------- src/EvaluateParameters.jl | 1 + src/Modia.jl | 2 +- src/StateSelection.jl | 4 +- test/TestLinearSystems.jl | 44 +++++++------- test/TestSource.jl | 2 +- test/include_all.jl | 19 +++--- 8 files changed, 106 insertions(+), 84 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 34611ff..bbdb0ba 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1050,7 +1050,7 @@ invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing = TimerOutputs.@tim end end empty!(m.der_x_visible) - m.der_x_hidden .= 0 + m.der_x_hidden .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 m.x = x Base.invokelatest(m.getDerivatives!, x, m, t) diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 43cdf9a..d644a76 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -515,17 +515,15 @@ Status of an EquationInfo instance: - `MANUAL`: Is defined manually. The following variables in x_info::Vector{StateElementInfo} are **not** defined: - x_names_julia, der_x_names_julia, length, unit, startIndex. - Also variables nx and x_infoByIndex are not defined. + x_names_julia, der_x_names_julia, length, unit, startIndex, nx. With function [`update_equationInfo!`](@ref), the variables length, unit, startIndex - in x_info::Vector{StateElementInfo} are computed, as well as nx and x_infoByIndex. + in x_info::Vector{StateElementInfo} are computed, as well as nx. - `CODE_GENERATION`: Is constructed during code generation with getSortedAndSolvedAST(..). The following variables in x_info::Vector{StateElementInfo} - are **not** defined: startIndex. - Also variables nx and x_infoByIndex are not defined. + are **not** defined: startIndex, nx. With function [`update_equationInfo!`](@ref), the variables startIndex - in x_info::Vector{StateElementInfo} are computed, as well as nx and x_infoByIndex. + in x_info::Vector{StateElementInfo} are computed, as well as nx. - `SOLVER_MODEL`: Is used during simulation in a SolverModel. With function [`update_equationInfo!`](@ref), missing variables are constructed depending @@ -735,8 +733,8 @@ mutable struct EquationInfo nxFixedLength::Int # x_info[1:nxFixedLength] are states with fixed length (does not change after compilation) or -1 if not yet known nxVisibleLength::Int # x_info[1:nxVisibleLength] are states that are visible in getDerivatives!(..) or -1 if not yet known # x_info[nxVisibleLength+1:end] are states defined in functions that are not visible in getDerivatives!(..) - x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] - # or empty vector, if not yet known. + #x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] + # # or empty vector, if not yet known. x_dict::OrderedCollections.OrderedDict{String,Int} # x_dict[x_name] returns the index of x_name with respect to x_info der_x_dict::OrderedCollections.OrderedDict{String,Int} # der_x_dict[der_x_name] returns the index of der_x_name with respect to x_info defaultParameterAndStartValues::Union{AbstractDict,Nothing} @@ -754,13 +752,12 @@ EquationInfo(; status = MANUAL, vSolvedWithFixedTrue = String[], nxFixedLength = -1, nxVisibleLength = -1, - x_infoByIndex = Int[], defaultParameterAndStartValues::Union{AbstractDict,Nothing} = nothing, ResultType = nothing, ResultTypeHasFloatType = false) = EquationInfo(status, ode, nz, x_info, residualCategories, linearEquations, vSolvedWithFixedTrue, -1, -1, - nxFixedLength, nxVisibleLength , x_infoByIndex, + nxFixedLength, nxVisibleLength, OrderedCollections.OrderedDict{String,Int}(), OrderedCollections.OrderedDict{String,Int}(), defaultParameterAndStartValues, @@ -814,30 +811,53 @@ function initialStateVector(eqInfo::EquationInfo, FloatType::Type)::Vector{Float end -function addOrUpdateStateInfo(eqInfo::EquationInfo, x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; - stateCategory::StateCategory = XD, - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false)::Int where {FloatType} - if haskey(eqInfo.x_dict, x_name) - # State is already defined. Update it. - ix = eqInfo.x_dict[x_name] - xi_info = eqInfo.x_info[ix] - @assert(xi_info.der_x_name == der_x_name) - @assert(xi_info.unit == unit) - xi_info.startOrInit = startOrInit - xi_info.nominal = nominal - xi_info.unbounded = unbounded - else - # State is not yet defined. Add it. - xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), - stateCategory, unit, startOrInit, fixed, nominal, unbounded) - push!(eqInfo.x_info, xi_info) - ix = length(eqInfo.x_info) - eqInfo.x_dict[x_name] = ix - eqInfo.der_x_dict[der_x_name] = ix +""" + removeHiddenStates(eqInfo::EquationInfo) + +Remove all hidden (non-visible) states from `eqInfo`. +""" +function removeHiddenStates(eqInfo::EquationInfo)::Nothing + if eqInfo.nx > eqInfo.nxVisible + for i = eqInfo.nxVisibleLength+1:length(eqInfo.x_info) + xi_info = eqInfo.x_info[i] + delete!(eqInfo.x_dict , xi_info.x_name) + delete!(eqInfo.der_x_dict, xi_info.der_x_name) + end + resize!(eqInfo.x_info, eqInfo.nxVisibleLength) + eqInfo.nx = eqInfo.nxVisible + end + return nothing +end + + +""" + xindex = addState(eqInfo::EquationInfo, + x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; + stateCategory::StateCategory = XD, + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false)::Int where {FloatType} + +Add new state to model and return its index (new state info is stored in eqInfo.x_info[xindex]). +""" +function addState(eqInfo::EquationInfo, x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; + stateCategory::StateCategory = XD, + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false)::Int where {FloatType} + if haskey(eqInfo.x_dict, x_name) || + haskey(eqInfo.der_x_dict, der_x_name) + error("Trying to add hidden state x_name=$x_name, der_x_name=$der_x_name but one or both names are already in use!") end + + xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), + stateCategory, unit, startOrInit, fixed, nominal, unbounded) + push!(eqInfo.x_info, xi_info) + ix = length(eqInfo.x_info) + eqInfo.x_dict[x_name] = ix + eqInfo.der_x_dict[der_x_name] = ix return ix end @@ -846,18 +866,26 @@ end x_start = updateEquationInfo!(eqInfo::EquationInfo, FloatType) Set eqInfo.x_dict, eqInfo.der_x_dict, eqInfo.nx and eqInfo.x_info[:].startIndex +and return initial state vector x_start """ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} - nxFixedLength = eqInfo.nxFixedLength - nxVisibleLength = eqInfo.nxVisibleLength - if nxFixedLength == 0 + nxFixedLength = eqInfo.nxFixedLength + x_info = eqInfo.x_info + if length(x_info) == 0 + # Handle systems with only algebraic variables, by introducing a dummy + # differential equation der_x[1] = -x[1], with state name _dummy_x + push!(x_info, Modia.StateElementInfo( + "_dummy_x", :(), "der(_dummy_x)", :(), XD, "", 0.0, true, NaN, false)) + startIndex = 1 + eqInfo.x_dict["_dummy_x"] = 1 + eqInfo.der_x_dict["der(_dummy_x)"] = 1 + elseif nxFixedLength == 0 startIndex = 1 else - xi_info = eqInfo.x_info[nxFixedLength] + xi_info = x_info[nxFixedLength] startIndex = xi_info.startIndex + xi_info.length end - x_info = eqInfo.x_info for i = nxFixedLength+1:length(x_info) xi_info = x_info[i] xi_info.length = length(xi_info.startOrInit) @@ -865,12 +893,7 @@ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex += xi_info.length end eqInfo.nx = startIndex - 1 - - nxVisible = 0 - for i = nxVisibleLength+1:length(x_info) - nxVisible += x_info[i].length - end - + return initialStateVector(eqInfo, FloatType) end @@ -947,11 +970,6 @@ function Base.show(io::IO, eqInfo::EquationInfo; indent=4) print(io, ",\n", indentation2, "nx = ", eqInfo.nx) end - if length(eqInfo.x_infoByIndex) > 0 - print(io, ",\n", indentation2, "x_infoByIndex = ") - show(io, eqInfo.x_infoByIndex) - end - if !isnothing(eqInfo.defaultParameterAndStartValues) print(io, ",\n", indentation2, "defaultParameterAndStartValues = ") show(io, eqInfo.defaultParameterAndStartValues, indent=12, finalLineBreak=false) diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 7b655c5..f2e746e 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -62,6 +62,7 @@ Recursively traverse the hierarchical collection `parameters` and perform the fo return nothing, if an error occurred (an error message was printed). """ function propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitless::Bool, modelModule, parameters, eqInfo, previous_dict, previous, pre_dict, pre, hold_dict, hold; log=false) + removeHiddenStates(eqInfo) x_found = fill(false, length(eqInfo.x_info)) map = propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitless, modelModule, parameters, eqInfo, x_found, previous_dict, previous, pre_dict, pre, hold_dict, hold, [], ""; log=log) diff --git a/src/Modia.jl b/src/Modia.jl index da3f530..0d29cde 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.8.4-dev" -const Date = "2022-04-24" +const Date = "2022-05-01" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/src/StateSelection.jl b/src/StateSelection.jl index 52e9732..aef6187 100644 --- a/src/StateSelection.jl +++ b/src/StateSelection.jl @@ -1523,6 +1523,7 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} # Handle systems with only algebraic variables, by introducing a dummy # differential equation der_x[1] = -x[1]. + #= if length(ODE_states) == 0 if log println("Model has only algebraic variables.\n", @@ -1531,7 +1532,8 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} push!(eq.equationInfo.x_info, Modia.StateElementInfo( "_dummy_x", :(), "der(_dummy_x)", :(), XD, "", 0.0, true, NaN, false)) end - + =# + # Finalize equationInfo initEquationInfo!(eq.equationInfo) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 8d88d99..6477121 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -29,23 +29,23 @@ where using Modia @usingModiaPlot -# T*der(x) + x = u +# T*der(x) + x = u T = 0.2; SSTest = Model( ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), # one state equations = :[ss.u = 2.0, y = ss.y[1]] ) - + ssTest = @instantiateModel(SSTest, logCode=true) simulate!(ssTest, stopTime=1.0, log=true, logStates=true) plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) simulate!(ssTest, stopTime=1.0, log=true, logStates=true, merge=Map(ss = Map(A=[-1/T 0.0; - 0.0 -1/T], - B=[1.0/T; - 1.0/T;;], + 0.0 -1/T], + B=[1.0/T; + 1.0/T;;], C=[0.4 0.4;], x_init=[0.2,0.4]))) # two states plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) @@ -57,7 +57,7 @@ LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace mutable struct LinearStateSpaceStruct{FloatType} path::String # Path name of instance - ix::Int # Index with respect to equationInfo.x_info + ix::Int # Index with respect to equationInfo.x_info A::Matrix{FloatType} B::Matrix{FloatType} C::Matrix{FloatType} @@ -67,7 +67,7 @@ mutable struct LinearStateSpaceStruct{FloatType} derx::Vector{FloatType} # Internal memory for derx function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, - x_init::Union{AbstractVector,Nothing}=nothing, + x_init::Union{AbstractVector,Nothing}=nothing, u::AbstractVector, y::AbstractVector, # Code generated with buildLinearStateSpace! provides start values of u and y. path::String, kwargs...) where {FloatType} #println("... 4: LinearStateSpaceStruct called for $path") @@ -140,19 +140,18 @@ function stateInfoLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeTy buildDict::OrderedCollections.OrderedDict{String,Any}, eqInfo::Modia.EquationInfo, path::String)::Nothing - # Called during evaluation of the parameters (before initialization) + # Called during evaluation of the parameters (before initialization) #println("... 3: stateInfoLinearStateSpace! called for $path with model = $model") lsBuild::LinearStateSpaceBuild{FloatType} = buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) - A = ls.A - @assert(size(A,2) == size(A,1)) + @assert(size(ls.A,2) == size(ls.A,1)) @assert(size(ls.B,2) == lsBuild.nu) @assert(size(ls.C,1) == lsBuild.ny) - ls.ix = Modia.addOrUpdateStateInfo(eqInfo, path*".x", path*".der(x)", ls.x_init) - lsBuild.ls = ls + ls.ix = Modia.addState(eqInfo, path*".x", path*".der(x)", ls.x_init) + lsBuild.ls = ls return nothing end - + function getLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls @@ -172,27 +171,28 @@ function computeStateDerivatives!(instantiatedModel, ls, u)::Bool Modia.set_hiddenStateDerivative!(instantiatedModel, ls.ix, ls.derx) return true end - -# T*der(x) + x = u + +# T*der(x) + x = u T = 0.2; SSTest = Model( ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), # one state equations = :[ss.u = 2.0, y = ss.y[1]] ) - + ssTest = @instantiateModel(SSTest, logCode=true) -simulate!(ssTest, stopTime=1.0, log=true, logStates=true) +simulate!(ssTest, stopTime=1.0, log=false, logStates=true, requiredFinalStates = [1.987867388853733]) #Modia.printResultInfo(ssTest) plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) -simulate!(ssTest, stopTime=1.0, log=true, logStates=true, +simulate!(ssTest, stopTime=1.0, log=false, logStates=true, merge=Map(ss = Map(A=[-1/T 0.0; - 0.0 -1/T], - B=[1.0/T; - 1.0/T;;], + 0.0 -1/T], + B=[1.0/T; + 1.0/T;;], C=[0.4 0.4;], - x_init=[0.2,0.4]))) # two states + x_init=[0.2,0.4])), # two states + requiredFinalStates = [1.98786636233743, 1.9892145443000466]) plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) end \ No newline at end of file diff --git a/test/TestSource.jl b/test/TestSource.jl index ef7da16..dfa3aa5 100644 --- a/test/TestSource.jl +++ b/test/TestSource.jl @@ -12,7 +12,7 @@ SineSource = Model( sineSource = @instantiateModel(SineSource, unitless=true) -simulate!(sineSource, Tsit5(), stopTime = 1.0, log=false, logStates=false) +simulate!(sineSource, Tsit5(), stopTime = 1.0, log=false, logStates=true) plot(sineSource, "y") diff --git a/test/include_all.jl b/test/include_all.jl index f21a7f4..2da667c 100644 --- a/test/include_all.jl +++ b/test/include_all.jl @@ -10,21 +10,22 @@ Test.@testset "Test basic functionality" begin include("TestStateSelection.jl") include("TestFilterCircuit.jl") include("TestFilterCircuit2.jl") - include("TestArrays.jl") + include("TestArrays.jl") + include("TestLinearSystems.jl") end Test.@testset "Test units, uncertainties" begin - include("TestUnitAsString.jl") + include("TestUnitAsString.jl") include("TestUnits.jl") include("TestUncertainties.jl") include("TestUnitsAndUncertainties.jl") - include("TestTwoInertiasAndIdealGear.jl") - include("TestTwoInertiasAndIdealGearWithUnits.jl") - include("TestTwoInertiasAndIdealGearWithUnitsAndUncertainties.jl") - include("TestTwoInertiasAndIdealGearWithMonteCarlo.jl") - include("TestTwoInertiasAndIdealGearWithUnitsAndMonteCarlo.jl") - include("TestLinearEquationSystemWithUnitsAndMonteCarlo.jl") + include("TestTwoInertiasAndIdealGear.jl") + include("TestTwoInertiasAndIdealGearWithUnits.jl") + include("TestTwoInertiasAndIdealGearWithUnitsAndUncertainties.jl") + include("TestTwoInertiasAndIdealGearWithMonteCarlo.jl") + include("TestTwoInertiasAndIdealGearWithUnitsAndMonteCarlo.jl") + include("TestLinearEquationSystemWithUnitsAndMonteCarlo.jl") end @@ -52,7 +53,7 @@ Test.@testset "Test multi returning functions" begin include("TestMultiReturningFunction5A.jl") include("TestMultiReturningFunction6.jl") include("TestMultiReturningFunction7A.jl") - include("TestMultiReturningFunction10.jl") + include("TestMultiReturningFunction10.jl") end include("../examples/runexamples.jl") From 87c1436df11db05a3e30e1c0e79e1857e5456781 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 1 May 2022 13:34:28 +0200 Subject: [PATCH 08/63] Trimm trailing spaces --- src/CodeGeneration.jl | 32 +++++++++---------- src/EquationAndStateInfo.jl | 64 ++++++++++++++++++------------------- src/EvaluateParameters.jl | 8 ++--- src/SimulateAndPlot.jl | 36 ++++++++++----------- src/StateSelection.jl | 22 ++++++------- test/TestLinearSystems.jl | 2 +- 6 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index bbdb0ba..0a4036c 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -335,7 +335,7 @@ mutable struct SimulationModel{FloatType,TimeType} nGetDerivatives::Int # Number of getDerivatives! calls nf::Int # Number of getDerivatives! calls from integrator (without zero-crossing calls) x::Vector{FloatType} # Reference of x-vector passed to getDerivatives!(..) - x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nxFixedLength+i] + x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nxFixedLength+i] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) der_x_visible::Vector{FloatType} # Derivatives of states x or x_init that correspond to visible states @@ -407,15 +407,15 @@ mutable struct SimulationModel{FloatType,TimeType} #@show nx # Provide storage for x_vec - x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.nxVisibleLength)] - + x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.nxVisibleLength)] + # Construct data structure for linear equations linearEquations = Modia.LinearEquations{FloatType}[] for leq in equationInfo.linearEquations push!(linearEquations, Modia.LinearEquations{FloatType}(leq...)) end - # Define result + # Define result # Store x and der_x for (xe_index, xe_info) in enumerate(equationInfo.x_info) result_info[xe_info.x_name] = ResultInfo(RESULT_X , xe_index) @@ -444,8 +444,8 @@ mutable struct SimulationModel{FloatType,TimeType} result_info[name] = ResultInfo(info2.store, info2.index, true) end end - - + + # Initialize execution flags eventHandler = EventHandler{FloatType,TimeType}(nz=nz, nAfter=nAfter) eventHandler.initial = true @@ -462,7 +462,7 @@ mutable struct SimulationModel{FloatType,TimeType} pre, nextPre, pre_names, pre_dict, hold, nextHold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, zeros(FloatType,0), - x_vec, x_start, zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), + x_vec, x_start, zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), zeros(FloatType,nx), true, LinearEquationsCopyInfoForDAEMode[], missing, false, result_info, Tuple[], missing, Vector{FloatType}[], false, unitless) end @@ -534,12 +534,12 @@ export copyState! """ copyState!(m::SimulationModel, x_index::Int, xi) - + Copy state of m.equationInfo.x_info[x_index] from m.x into pre-allocated vector xi. """ function copyState!(m::SimulationModel{FloatType,TimeType}, x_index::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} @assert(length(xi) == m.equationInfo.x_info[x_index].length) - startIndex = m.equationInfo.x_info[x_index].startIndex - 1 + startIndex = m.equationInfo.x_info[x_index].startIndex - 1 for i = 1:length(xi) xi[i] = m.x[startIndex+i] end @@ -549,13 +549,13 @@ end """ set_hiddenStateDerivative!(m::SimulationModel, x_index, der_x) - + Copy hidden state derivative der_x of m.equationInfo.x_info[x_index] into full state derivative vector """ function set_hiddenStateDerivative!(m::SimulationModel, x_index::Int, der_x)::Nothing @assert(length(der_x) == m.equationInfo.x_info[x_index].length) #println("set_hiddenStateDerivative!: x_index = $x_index, der_x = $der_x") - startIndex = m.equationInfo.x_info[x_index].startIndex - m.equationInfo.nxVisible - 1 + startIndex = m.equationInfo.x_info[x_index].startIndex - m.equationInfo.nxVisible - 1 for i = 1:length(der_x) m.der_x_hidden[startIndex+i] = der_x[i] end @@ -1122,7 +1122,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti @show m.der_x_hidden @show m.equationInfo =# - + # Log parameters if m.options.logParameters parameters = m.parameters @@ -1267,7 +1267,7 @@ function outputs!(x, t, integrator)::Nothing m.solve_leq = true end copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) - push!(m.result_der_x, deepcopy(m.der_x_full)) + push!(m.result_der_x, deepcopy(m.der_x_full)) m.storeResult = false if !m.success m.result_x = integrator.sol @@ -1306,7 +1306,7 @@ end """ copyDerivatives!(der_x, der_x_visible, der_x_hidden) - + Copy der_x_visible and der_x_hidden to der_x (der_x .= [der_x_visible, der_x_hidden]) """ @inline function copyDerivatives!(der_x, der_x_visible, der_x_hidden)::Nothing @@ -1361,10 +1361,10 @@ function DAEresidualsForODE!(residuals, derx, x, m, t)::Nothing m.solve_leq = false invokelatest_getDerivatives_without_der_x!(x, m, t) m.solve_leq = true - + copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) residuals .= m.der_x_full .- derx - + # Get residuals from linearEquations for copyInfo in m.daeCopyInfo leq = m.linearEquations[ copyInfo.ileq ] diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index d644a76..d904fb6 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -26,7 +26,7 @@ export EquationInfoStatus, MANUAL, CODE_GENERATION, SOLVER_MODEL """ isFixedLengthStartOrInit(startOrInit::Any, name::AbstractString) - + Returns true, if `startOrInit` (so start value, init value, `nothing`) characterizes a value with fixed length, so `length(v_startOrInit)` is fixed after compilation (= either a number or a StaticArray). Note, if a start-value is not defined (`startOrInit = nothing`) a scalar default is used. @@ -174,7 +174,7 @@ mutable struct LinearEquations{FloatType <: Real} new(true, A_is_constant, x_names, Any[], x_lengths, nx_fixedLength, x_vec, zeros(FloatType,nx,nx), zeros(FloatType,nx), zeros(FloatType,nx), fill(0,nx), zeros(FloatType,nx), -2, 0, niter_max, false, String[], String[], - useRecursiveFactorizationUptoSize, useRecursiveFactorization) + useRecursiveFactorizationUptoSize, useRecursiveFactorization) end end LinearEquations(args...) = LinearEquations{Float64}(args...) @@ -434,12 +434,12 @@ function LinearEquationsIteration!(leq::LinearEquations{FloatType}, isInitial::B j = mode for i = 1:nx A[i,j] = (residuals[i] + b[i])/x[j] - end + end x[j] = 0 if j < nx leq.mode += 1 - x[leq.mode] = max(FloatType(1e-3), abs(b[leq.mode])) # convert(FloatType, 1) + x[leq.mode] = max(FloatType(1e-3), abs(b[leq.mode])) # convert(FloatType, 1) empty!(leq.residuals) return copy_x_into_x_vec!(leq) end @@ -574,7 +574,7 @@ mutable struct StateElementInfo der_x_name::String # Modia name of der_x-element or "" if either "der(x_name)" or if no name, der_x_name_julia # Julia name of der_x-element in getDerivatives! function # or not needed (since no code generation) - stateCategory::StateCategory # category of the state + stateCategory::StateCategory # category of the state unit::String # unit of x-element as string (or "" if not yet known) startOrInit::Any # start or init value or nothing depending on fixed # (init : if value and fixed=true @@ -587,8 +587,8 @@ mutable struct StateElementInfo # = false, if length of value is determined before initialization scalar::Bool # = true, if scalar # = false, if vector - length::Int # length of x-element - startIndex::Int # start index of element with respect to x-vector (if fixedLength=true) + length::Int # length of x-element + startIndex::Int # start index of element with respect to x-vector (if fixedLength=true) # or with respect to x_vec-vector (if fixedLength=false) end @@ -599,7 +599,7 @@ StateElementInfo(x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, startOrInit, fixed, nominal, unbounded) = StateElementInfo( x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, startOrInit, fixed, nominal, unbounded, - isFixedLengthStartOrInit(startOrInit, x_name), !(startOrInit isa AbstractArray), + isFixedLengthStartOrInit(startOrInit, x_name), !(startOrInit isa AbstractArray), startOrInit isa Nothing ? 1 : length(startOrInit), -1) @@ -631,8 +631,8 @@ function Base.show(io::IO, xe_info::StateElementInfo) print(io, ",", xe_info.nominal) print(io, ",", xe_info.unbounded) print(io, ",", xe_info.fixedLength) - print(io, ",", xe_info.scalar) - print(io, ",", xe_info.length) + print(io, ",", xe_info.scalar) + print(io, ",", xe_info.length) print(io, ",", xe_info.startIndex) print(io, ")") return nothing @@ -662,7 +662,7 @@ end """ nx = stateVectorLength(x_info::Vector{StateElementInfo}) - + Return the length of the state vector """ function stateVectorLength(x_info::Vector{StateElementInfo})::Int @@ -672,9 +672,9 @@ function stateVectorLength(x_info::Vector{StateElementInfo})::Int end return nx end - - + + """ eqInfo = EquationInfo(; status = MANUAL, @@ -732,7 +732,7 @@ mutable struct EquationInfo nxVisible::Int # = number of visible x-elements or -1 if not yet known nxFixedLength::Int # x_info[1:nxFixedLength] are states with fixed length (does not change after compilation) or -1 if not yet known nxVisibleLength::Int # x_info[1:nxVisibleLength] are states that are visible in getDerivatives!(..) or -1 if not yet known - # x_info[nxVisibleLength+1:end] are states defined in functions that are not visible in getDerivatives!(..) + # x_info[nxVisibleLength+1:end] are states defined in functions that are not visible in getDerivatives!(..) #x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] # # or empty vector, if not yet known. x_dict::OrderedCollections.OrderedDict{String,Int} # x_dict[x_name] returns the index of x_name with respect to x_info @@ -756,7 +756,7 @@ EquationInfo(; status = MANUAL, ResultType = nothing, ResultTypeHasFloatType = false) = EquationInfo(status, ode, nz, x_info, residualCategories, linearEquations, - vSolvedWithFixedTrue, -1, -1, + vSolvedWithFixedTrue, -1, -1, nxFixedLength, nxVisibleLength, OrderedCollections.OrderedDict{String,Int}(), OrderedCollections.OrderedDict{String,Int}(), @@ -778,7 +778,7 @@ function initEquationInfo!(eqInfo::EquationInfo)::Nothing der_x_dict[xi_info.der_x_name] = i xi_info.startIndex = startIndex startIndex += xi_info.length - end + end eqInfo.nx = startIndex - 1 eqInfo.nxVisible = eqInfo.nx eqInfo.nxVisibleLength = length(eqInfo.x_info) @@ -788,7 +788,7 @@ end """ x_init = initialStateVector(eqInfo::EquationInfo, FloatType) - + Return initial state vector `Vector{FloatType}` with stripped units. """ function initialStateVector(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} @@ -813,7 +813,7 @@ end """ removeHiddenStates(eqInfo::EquationInfo) - + Remove all hidden (non-visible) states from `eqInfo`. """ function removeHiddenStates(eqInfo::EquationInfo)::Nothing @@ -822,7 +822,7 @@ function removeHiddenStates(eqInfo::EquationInfo)::Nothing xi_info = eqInfo.x_info[i] delete!(eqInfo.x_dict , xi_info.x_name) delete!(eqInfo.der_x_dict, xi_info.der_x_name) - end + end resize!(eqInfo.x_info, eqInfo.nxVisibleLength) eqInfo.nx = eqInfo.nxVisible end @@ -831,21 +831,21 @@ end """ - xindex = addState(eqInfo::EquationInfo, - x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; + xindex = addState(eqInfo::EquationInfo, + x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; stateCategory::StateCategory = XD, unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, + fixed::Bool = true, + nominal::Float64 = NaN, unbounded::Bool = false)::Int where {FloatType} - + Add new state to model and return its index (new state info is stored in eqInfo.x_info[xindex]). """ -function addState(eqInfo::EquationInfo, x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; +function addState(eqInfo::EquationInfo, x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; stateCategory::StateCategory = XD, unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, + fixed::Bool = true, + nominal::Float64 = NaN, unbounded::Bool = false)::Int where {FloatType} if haskey(eqInfo.x_dict, x_name) || haskey(eqInfo.der_x_dict, der_x_name) @@ -857,7 +857,7 @@ function addState(eqInfo::EquationInfo, x_name::String, der_x_name::String, star push!(eqInfo.x_info, xi_info) ix = length(eqInfo.x_info) eqInfo.x_dict[x_name] = ix - eqInfo.der_x_dict[der_x_name] = ix + eqInfo.der_x_dict[der_x_name] = ix return ix end @@ -878,22 +878,22 @@ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa "_dummy_x", :(), "der(_dummy_x)", :(), XD, "", 0.0, true, NaN, false)) startIndex = 1 eqInfo.x_dict["_dummy_x"] = 1 - eqInfo.der_x_dict["der(_dummy_x)"] = 1 + eqInfo.der_x_dict["der(_dummy_x)"] = 1 elseif nxFixedLength == 0 startIndex = 1 else xi_info = x_info[nxFixedLength] startIndex = xi_info.startIndex + xi_info.length end - + for i = nxFixedLength+1:length(x_info) xi_info = x_info[i] xi_info.length = length(xi_info.startOrInit) xi_info.startIndex = startIndex startIndex += xi_info.length - end + end eqInfo.nx = startIndex - 1 - + return initialStateVector(eqInfo, FloatType) end diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index f2e746e..767a731 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -199,8 +199,8 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl stateInfoFunction = _stateInfoFunction[:functionName] else @warn "Model $path has key :_stateInfoFunction but its value has no key :functionName" - end - + end + elseif haskey(parameters, :value) # For example: p1 = (_class = :Var, parameter = true, value = 0.2) # or: p2 = (_class = :Var, parameter = true, value = :(2*p1)) @@ -339,7 +339,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl # (2) Define subModel states and store them in xxx Core.eval(modelModule, :($stateInfoFunction($current, $FloatType, $TimeType, $buildDict, $eqInfo, $path))) end - + if isnothing(constructor) return current # (; current...) else @@ -384,7 +384,7 @@ end """ modelOfPath = getModelFromSplittedPath(model, splittedPath::Vector{Symbol}) - + Return reference to the sub-model characterized by `splittedPath`. # Examples diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 2aec44d..a33567a 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -42,17 +42,17 @@ function getAlgorithmName(algorithm)::String return "???" end name = string(algorithmType) - - if algorithmType <: DifferentialEquations.OrdinaryDiffEq.QNDF + + if algorithmType <: DifferentialEquations.OrdinaryDiffEq.QNDF if algorithm.kappa == tuple(0//1,0//1,0//1,0//1,0//1) name = replace(name, "QNDF" => "QBDF") end - + elseif algorithmType <: DifferentialEquations.OrdinaryDiffEq.QNDF1 || algorithmType <: DifferentialEquations.OrdinaryDiffEq.QNDF2 if algorithm.kappa == 0 name = replace(name, "QNDF" => "QBDF") - end + end end return name end @@ -91,7 +91,7 @@ The symbols `CVODE_BDF` and `IDA` are exported from Modia, so that `simulate!(in and `simulate!(instantiatedModel, IDA(), ...)` can be used (instead of `import Sundials; simulate!(instantiatedModel, Sundials.xxx(), ...)`). -The simulation results are stored in `instantiatedModel` and can be plotted with +The simulation results are stored in `instantiatedModel` and can be plotted with `plot(instantiatedModel, ...)` and the result values can be retrieved with `rawSignal(..)` or `getPlotSignal(..)`. `printResultInfo(instantiatedModel)` prints information about the signals in the result file. @@ -223,7 +223,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me algorithm = Sundials.CVODE_BDF() end m.algorithmName = getAlgorithmName(algorithm) - + # Initialize/re-initialize SimulationModel if m.options.log || m.options.logEvaluatedParameters || m.options.logStates println("... Simulate model ", m.modelName) @@ -244,11 +244,11 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me @test false return nothing end - + enable_timer!(m.timer) reset_timer!(m.timer) - TimerOutputs.@timeit m.timer "Modia.simulate!" begin + TimerOutputs.@timeit m.timer "Modia.simulate!" begin sizesOfLinearEquationSystems = Int[length(leq.b) for leq in m.linearEquations] # Define problem and callbacks based on algorithm and model type @@ -265,13 +265,13 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me eh = m.eventHandler m.odeMode = true - m.solve_leq = true + m.solve_leq = true if typeof(algorithm) <: DifferentialEquations.DiffEqBase.AbstractDAEAlgorithm # DAE integrator m.odeIntegrator = false nx = length(m.x_init) differential_vars = eh.nz > 0 ? fill(true, nx) : nothing # due to DifferentialEquations issue #549 - copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) + copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x_full, m.x_init, tspan, m, differential_vars = differential_vars) empty!(m.daeCopyInfo) if length(sizesOfLinearEquationSystems) > 0 && maximum(sizesOfLinearEquationSystems) >= options.nlinearMinForDAE @@ -353,7 +353,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me callback=callbacks, adaptive=m.options.adaptive, saveat=tspan2, dt=dt, dtmax=m.options.dtmax, tstops = tstops, initializealg = DifferentialEquations.NoInit()) end - + # Compute and store outputs from last event until final time sol_t = solution.t sol_x = solution.u @@ -368,16 +368,16 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me if ismissing(algorithm) m.algorithmName = getAlgorithmName(solution.alg) end - + # Terminate simulation finalStates = solution.u[end] - finalTime = solution.t[end] + finalTime = solution.t[end] terminate!(m, finalStates, finalTime) - + # Raise an error, if simulation was not successful if !(solution.retcode == :Default || solution.retcode == :Success || solution.retcode == :Terminated) error("\nsolution = simulate!(", m.modelName, ", ...) failed with solution.retcode = :$(solution.retcode) at time = $finalTime.\n") - end + end end disable_timer!(m.timer) @@ -397,7 +397,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me println(" nStates = ", length(m.x_start)) println(" linearSystemSizes = ", sizesOfLinearEquationSystems) println(" useRecursiveFactorization = ", useRecursiveFactorization) - println(" odeModeLinearSystems = ", Bool[leq.odeMode for leq in m.linearEquations]) + println(" odeModeLinearSystems = ", Bool[leq.odeMode for leq in m.linearEquations]) println(" nResults = ", length(m.result_x.t)) println(" nGetDerivatives = ", m.nGetDerivatives, " (total number of getDerivatives! calls)") println(" nf = ", m.nf, " (number of getDerivatives! calls from integrator)") # solution.destats.nf @@ -474,7 +474,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end end =# - + return solution end @@ -866,7 +866,7 @@ function get_result(m::SimulationModel, name::AbstractString; unit=true) end -function setEvaluatedParametersInDataFrame!(obj::OrderedDict{Symbol,Any}, result_info, dataFrame::DataFrames.DataFrame, path::String, nResult::Int)::Nothing +function setEvaluatedParametersInDataFrame!(obj::OrderedDict{Symbol,Any}, result_info, dataFrame::DataFrames.DataFrame, path::String, nResult::Int)::Nothing for (key,value) in zip(keys(obj), obj) name = appendName(path, key) if typeof(value) <: OrderedDict{Symbol,Any} diff --git a/src/StateSelection.jl b/src/StateSelection.jl index aef6187..be866b0 100644 --- a/src/StateSelection.jl +++ b/src/StateSelection.jl @@ -72,7 +72,7 @@ The functions need to have the following arguments: - `var_startInitFixed(v::Int)::Tuple(Any,Bool)`:\\ Return `(startOrInit, fixed)`, where `startOrInit` is the `start` or `init` value or `nothing` - (if neither `start` nor `init` defined) and `fixed` is `true`, if an `init` value is defined. + (if neither `start` nor `init` defined) and `fixed` is `true`, if an `init` value is defined. - `var_is_state(v_original::Int)::Bool`:\\ Return true, if variable `v_original` is defined to be a state. @@ -1477,7 +1477,7 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} push!(x_without_start, v) end v_name = eq.fc.var_name(v) - + if isFixedLengthStartOrInit(v_startOrInit, v_name) v_der_x = eq.A[v] v_unit = unitless ? "" : eq.fc.var_unit(v) @@ -1487,7 +1487,7 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} v_nominal = eq.fc.var_nominal(v) v_unbounded = eq.fc.var_unbounded(v) v_stateCategory = Modia.XD - + push!(x_info, Modia.StateElementInfo( v_name, v_julia_name, v_der_x_name, v_der_x_julia_name, @@ -1496,8 +1496,8 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} else # length(v_startOrInit) may change after compilation push!(x_vec , v) - push!(x_vec_startOrInit, v_startOrInit) - push!(x_vec_fixed , v_fixed) + push!(x_vec_startOrInit, v_startOrInit) + push!(x_vec_fixed , v_fixed) end end eq.equationInfo.nxFixedLength = length(x_info) @@ -1513,12 +1513,12 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} v_nominal = eq.fc.var_nominal(v) v_unbounded = eq.fc.var_unbounded(v) v_stateCategory = Modia.XD - + push!(x_info, Modia.StateElementInfo( v_name, v_julia_name, v_der_x_name, v_der_x_julia_name, v_stateCategory, v_unit, v_startOrInit, v_fixed, - v_nominal, v_unbounded)) + v_nominal, v_unbounded)) end # Handle systems with only algebraic variables, by introducing a dummy @@ -1530,13 +1530,13 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} "Added a dummy differential equation der(_dummy_x) = -_dummy_x, _dummy_x(t0) = 0") end push!(eq.equationInfo.x_info, Modia.StateElementInfo( - "_dummy_x", :(), "der(_dummy_x)", :(), XD, "", 0.0, true, NaN, false)) + "_dummy_x", :(), "der(_dummy_x)", :(), XD, "", 0.0, true, NaN, false)) end =# - - # Finalize equationInfo + + # Finalize equationInfo initEquationInfo!(eq.equationInfo) - + # Print ODE states if logStates println("\nSelected ODE states: ") diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 6477121..d881182 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -192,7 +192,7 @@ simulate!(ssTest, stopTime=1.0, log=false, logStates=true, 1.0/T;;], C=[0.4 0.4;], x_init=[0.2,0.4])), # two states - requiredFinalStates = [1.98786636233743, 1.9892145443000466]) + requiredFinalStates = [1.98786636233743, 1.9892145443000466]) plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) end \ No newline at end of file From 2d945e3647c98ee39742af31723ae4c125cf75e7 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 1 May 2022 14:30:34 +0200 Subject: [PATCH 09/63] Fixed issue (removed function invokelatest_getDerivatives!(..) replaced by function derivatives!(..)) --- src/SimulateAndPlot.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index a33567a..2191432 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -561,7 +561,7 @@ function linearize!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; # Function that shall be linearized function modelToLinearize!(der_x, x) - invokelatest_getDerivatives!(der_x, x, m, m.options.startTime) + derivatives!(der_x, x, m, m.options.startTime) return nothing end From 1eec128eb516dc3ea43139bc3f7a6a7652b5d7bb Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 1 May 2022 14:49:39 +0200 Subject: [PATCH 10/63] Fixed issue (equationInfo.nxVisible not correctly set in some situations) --- src/EquationAndStateInfo.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index d904fb6..f5c0038 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -893,6 +893,13 @@ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex += xi_info.length end eqInfo.nx = startIndex - 1 + + nxVisible = 0 + for i = 1:eqInfo.nxVisibleLength + xi_info = x_info[i] + nxVisible += x_info[i].length + end + eqInfo.nxVisible = nxVisible return initialStateVector(eqInfo, FloatType) end From a020d0034ed8dd30bc4488168379f4ba4245db70 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Mon, 2 May 2022 17:43:30 +0200 Subject: [PATCH 11/63] Removed explicit deepCopy of vectors before addToResult(..), because deepCopy is performed now on all arguments of addToResult(..) --- Project.toml | 2 +- src/CodeGeneration.jl | 23 +++++++++++------------ test/TestLinearSystems.jl | 3 ++- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Project.toml b/Project.toml index 7eac0a0..0e6436b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ authors = ["Hilding Elmqvist ", "Martin Otter "] name = "Modia" uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e" -version = "0.8.4-dev" +version = "0.9.0-dev" [compat] DataFrames = "1" diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 0a4036c..d638be0 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1732,14 +1732,16 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati push!(code_pre, :( _m.nextPre[$i] = $preName )) end - # Code for deepcopy of vectors with pre-allocated memory - code_copy = Expr[] - for leq_tuple in equationInfo.linearEquations - x_vec_julia_names = leq_tuple[2] - for name in x_vec_julia_names - push!(code_copy, :( $name = deepcopy($name) )) - end - end + # Code for deepcopy of vectors with pre-allocated memory (no longer needed, since deepCopy of everything inside addToResult!) + #code_copy = Expr[] + #for leq_tuple in equationInfo.linearEquations + # x_vec_julia_names = leq_tuple[2] + # for name in x_vec_julia_names + # push!(code_copy, :( $name = deepcopy($name) )) + # end + #end + # if _m.storeResult + # $(code_copy...) # Generate code of the function # temporarily removed: _m.time = $TimeType(Modia.getValue(_time)) @@ -1760,10 +1762,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati $(code_pre...) if _m.storeResult - Modia.TimerOutputs.@timeit _m.timer "Modia addToResult!" begin - $(code_copy...) - Modia.addToResult!(_m, $(variables...)) - end + Modia.TimerOutputs.@timeit _m.timer "Modia addToResult!" Modia.addToResult!(_m, $(variables...)) end return nothing end diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index d881182..8c9837f 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -176,7 +176,7 @@ end T = 0.2; SSTest = Model( ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), # one state - equations = :[ss.u = 2.0, + equations = :[ss.u = [2.0], y = ss.y[1]] ) @@ -193,6 +193,7 @@ simulate!(ssTest, stopTime=1.0, log=false, logStates=true, C=[0.4 0.4;], x_init=[0.2,0.4])), # two states requiredFinalStates = [1.98786636233743, 1.9892145443000466]) +Modia.printResultInfo(ssTest) plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) end \ No newline at end of file From a1d9700b85e59719fe62df6895b3ef8c6ebe01da Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Mon, 2 May 2022 18:49:05 +0200 Subject: [PATCH 12/63] Remove some very time consuming tests --- test/TestUnitAsString.jl | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/test/TestUnitAsString.jl b/test/TestUnitAsString.jl index a083f68..5d91353 100644 --- a/test/TestUnitAsString.jl +++ b/test/TestUnitAsString.jl @@ -102,18 +102,21 @@ FirstOrder4 = FirstOrder1 | Map(k = (2.0 ± 0.1)u"m/s" , x = Var(init = (0.3 ± FirstOrder5 = FirstOrder1 | Map(k = normal(2.0, 0.1/3), x = Var(init = normal(0.3, 0.1/3))) FirstOrder6 = FirstOrder1 | Map(k = normal(2.0, 0.1/3)u"m/s", x = Var(init = normal(0.3, 0.1/3)u"m/s")) -firstOrder1 = @instantiateModel(FirstOrder1, logCode=logCode) -firstOrder2 = @instantiateModel(FirstOrder2, logCode=logCode) -firstOrder3 = @instantiateModel(FirstOrder3, logCode=logCode, FloatType=Measurements.Measurement{Float64}) -firstOrder4 = @instantiateModel(FirstOrder4, logCode=logCode, FloatType=Measurements.Measurement{Float64}) -firstOrder5 = @instantiateModel(FirstOrder5, logCode=logCode, FloatType=StaticParticles{Float64,nparticles}) -firstOrder6 = @instantiateModel(FirstOrder6, logCode=logCode, FloatType=StaticParticles{Float64,nparticles}) - -simulate!(firstOrder1) -simulate!(firstOrder2) -simulate!(firstOrder3) -simulate!(firstOrder4) -simulate!(firstOrder5) -simulate!(firstOrder6) +if false + # Remove tests, to drastically reduce the time for the test + firstOrder1 = @instantiateModel(FirstOrder1, logCode=logCode) + firstOrder2 = @instantiateModel(FirstOrder2, logCode=logCode) + firstOrder3 = @instantiateModel(FirstOrder3, logCode=logCode, FloatType=Measurements.Measurement{Float64}) + firstOrder4 = @instantiateModel(FirstOrder4, logCode=logCode, FloatType=Measurements.Measurement{Float64}) + firstOrder5 = @instantiateModel(FirstOrder5, logCode=logCode, FloatType=StaticParticles{Float64,nparticles}) + firstOrder6 = @instantiateModel(FirstOrder6, logCode=logCode, FloatType=StaticParticles{Float64,nparticles}) + + simulate!(firstOrder1) + simulate!(firstOrder2) + simulate!(firstOrder3) + simulate!(firstOrder4) + simulate!(firstOrder5) + simulate!(firstOrder6) +end end \ No newline at end of file From 946dbbc95143a82169eab82561437c8da2e5dd10 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 4 May 2022 09:36:06 +0200 Subject: [PATCH 13/63] Call stateInfoFunction(..) only if there is no constructor call + remove "nominal" column from logStates output, since nominal has no effect currently. --- src/CodeGeneration.jl | 5 +++-- src/EvaluateParameters.jl | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index d638be0..011263e 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1135,13 +1135,14 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti if m.options.logStates # List init/start values - x_table = DataFrames.DataFrame(state=String[], init=Any[], unit=String[], nominal=Float64[]) + x_table = DataFrames.DataFrame(state=String[], init=Any[], unit=String[]) #, nominal=String[]) for xe_info in m.equationInfo.x_info xe_init = get_xe(m.x_start, xe_info) if hasParticles(xe_init) xe_init = string(minimum(xe_init)) * " .. " * string(maximum(xe_init)) end - push!(x_table, (xe_info.x_name, xe_init, xe_info.unit, xe_info.nominal)) + # xe_nominal = isnan(xe_info.nominal) ? "" : xe_info.nominal + push!(x_table, (xe_info.x_name, xe_init, xe_info.unit)) #, xe_nominal)) end show(stdout, x_table; allrows=true, allcols=true, rowlabel = Symbol("#"), summary=false, eltypes=false) println("\n") diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 767a731..bb0b86c 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -333,15 +333,17 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl end end - if !isnothing(stateInfoFunction) - # Call: stateInfoFunction(model, FloatType, Timetype, buildDict, path) - # (1) Generate an instance of subModel and store it in buildDict[path] - # (2) Define subModel states and store them in xxx - Core.eval(modelModule, :($stateInfoFunction($current, $FloatType, $TimeType, $buildDict, $eqInfo, $path))) - end - if isnothing(constructor) - return current # (; current...) + if !isnothing(stateInfoFunction) + # Call: stateInfoFunction(model, FloatType, Timetype, buildDict, path) + # (1) Generate an instance of subModel and store it in buildDict[path] + # (2) Define subModel states and store them in xxx + Core.eval(modelModule, :($stateInfoFunction($current, $FloatType, $TimeType, $buildDict, $eqInfo, $path))) + if log + println(" 13: +++ Instantiated $path: $stateInfoFunction called to define hidden states\n\n") + end + end + return current else if usePath obj = Core.eval(modelModule, :(FloatType = $FloatType; $constructor(; path = $path, $current...))) @@ -349,7 +351,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl obj = Core.eval(modelModule, :(FloatType = $FloatType; $constructor(; $current...))) end if log - println(" 13: +++ Instantiated $path: typeof(obj) = ", typeof(obj), ", obj = ", obj, "\n\n") + println(" 14: +++ Instantiated $path: typeof(obj) = ", typeof(obj), ", obj = ", obj, "\n\n") end return obj end From 471dfeabaad64b631e62dad92e19cc36f7c9d9f7 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 11 May 2022 16:28:30 +0200 Subject: [PATCH 14/63] renamed _stateInfoFunction to _instantiateFunction --- src/CodeGeneration.jl | 3 +++ src/EvaluateParameters.jl | 30 +++++++++++++++--------------- src/Modia.jl | 4 ++-- test/TestLinearSystems.jl | 14 +++++++------- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 011263e..371ed70 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -398,6 +398,9 @@ mutable struct SimulationModel{FloatType,TimeType} if isnothing(evaluatedParameters) return nothing end + # Resize linear equation systems if dimensions of vector valued tearing variables changed + # resizeLinearEquations!(m, m.options.log) + x_start = updateEquationInfo!(equationInfo, FloatType) nx = length(x_start) nextPrevious = deepcopy(previous) diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index bb0b86c..1c96132 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -172,10 +172,10 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl end current = OrderedDict{Symbol,Any}() # should be Map() - # Determine, whether "parameters" has a ":_constructor" or "_stateInfoFunction" key and handle this specially - constructor = nothing - stateInfoFunction = nothing - usePath = false + # Determine, whether "parameters" has a ":_constructor" or "_instantiateFunction" key and handle this specially + constructor = nothing + instantiateFunction = nothing + usePath = false if haskey(parameters, :_constructor) # For example: obj = (_class = :Par, _constructor = :(Modia3D.Object3D), _path = true, kwargs...) # or: rev = (_constructor = (_class = :Par, value = :(Modia3D.ModiaRevolute), _path=true), kwargs...) @@ -192,13 +192,13 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl end end - elseif haskey(parameters, :_stateInfoFunction) - # For example: obj = (_stateInfoFunction = Par(functionName = :(stateInfoLinearStateSpaceSystem)) - _stateInfoFunction = parameters[:_stateInfoFunction] - if haskey(_stateInfoFunction, :functionName) - stateInfoFunction = _stateInfoFunction[:functionName] + elseif haskey(parameters, :_instantiateFunction) + # For example: obj = (_instantiateFunction = Par(functionName = :(instantiateLinearStateSpace!)) + _instantiateFunction = parameters[:_instantiateFunction] + if haskey(_instantiateFunction, :functionName) + instantiateFunction = _instantiateFunction[:functionName] else - @warn "Model $path has key :_stateInfoFunction but its value has no key :functionName" + @warn "Model $path has key :_instantiateFunction but its value has no key :functionName" end elseif haskey(parameters, :value) @@ -213,7 +213,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl if log println(" 2: ... key = $k, value = $v") end - if k == :_constructor || k == :_stateInfoFunction || k == :_path || (k == :_class && !isnothing(constructor)) + if k == :_constructor || k == :_instantiateFunction || k == :_path || (k == :_class && !isnothing(constructor)) if log println(" 3: ... key = $k") end @@ -334,13 +334,13 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl end if isnothing(constructor) - if !isnothing(stateInfoFunction) - # Call: stateInfoFunction(model, FloatType, Timetype, buildDict, path) + if !isnothing(instantiateFunction) + # Call: instantiateFunction(model, FloatType, Timetype, buildDict, path) # (1) Generate an instance of subModel and store it in buildDict[path] # (2) Define subModel states and store them in xxx - Core.eval(modelModule, :($stateInfoFunction($current, $FloatType, $TimeType, $buildDict, $eqInfo, $path))) + Core.eval(modelModule, :($instantiateFunction($current, $FloatType, $TimeType, $buildDict, $eqInfo, $path))) if log - println(" 13: +++ Instantiated $path: $stateInfoFunction called to define hidden states\n\n") + println(" 13: +++ Instantiated $path: $instantiateFunction called to instantiate sub-model and define hidden states\n\n") end end return current diff --git a/src/Modia.jl b/src/Modia.jl index 0d29cde..9b92067 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -9,8 +9,8 @@ Main module of Modia. module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory -const Version = "0.8.4-dev" -const Date = "2022-05-01" +const Version = "0.9.0-dev" +const Date = "2022-05-11" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 8c9837f..9f96a36 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -52,8 +52,8 @@ plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) ``` """ LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace!), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated - _stateInfoFunction = Par(functionName = :(stateInfoLinearStateSpace!)), # Called once after new A,B,C values are merged - kwargs...) + _instantiateFunction = Par(functionName = :(instantiateLinearStateSpace!)), # Called once after new A,B,C values are merged + kwargs...) mutable struct LinearStateSpaceStruct{FloatType} path::String # Path name of instance @@ -136,12 +136,12 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: end -function stateInfoLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, - buildDict::OrderedCollections.OrderedDict{String,Any}, - eqInfo::Modia.EquationInfo, - path::String)::Nothing +function instantiateLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, + buildDict::OrderedCollections.OrderedDict{String,Any}, + eqInfo::Modia.EquationInfo, + path::String)::Nothing # Called during evaluation of the parameters (before initialization) - #println("... 3: stateInfoLinearStateSpace! called for $path with model = $model") + #println("... 3: instantiateLinearStateSpace! called for $path with model = $model") lsBuild::LinearStateSpaceBuild{FloatType} = buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) @assert(size(ls.A,2) == size(ls.A,1)) From 300dbc1df24955ad7cc75f0c9ae5c2293a3d5723 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Thu, 12 May 2022 06:47:35 +0200 Subject: [PATCH 15/63] SimulationModel(...): Constructor splitted so that first a partially instantiated SimulationModel is generated that is passed to propagateEvaluateAndInstantiate!(..) for _instantiateFunction(..). --- src/CodeGeneration.jl | 167 ++++++++++++++++++++++---------------- src/EvaluateParameters.jl | 52 ++++++------ src/Modia.jl | 3 +- test/TestLinearSystems.jl | 10 +-- 4 files changed, 128 insertions(+), 104 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 371ed70..ade6e4b 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -296,6 +296,7 @@ end - variableNames: A vector of variable names. A name can be a Symbol or a String. """ mutable struct SimulationModel{FloatType,TimeType} + # Available before propagateEvaluateAndInstantiate!(..) called (= partiallyInstantedModel) modelModule::Module modelName::String buildDict::OrderedDict{String,Any} @@ -309,20 +310,15 @@ mutable struct SimulationModel{FloatType,TimeType} eventHandler::EventHandler{FloatType,TimeType} vSolvedWithInitValuesAndUnit::OrderedDict{String,Any} # Dictionary of (names, init values with units) for all explicitly solved variables with init-values defined - parameters::OrderedDict{Symbol,Any} - evaluatedParameters::OrderedDict{Symbol,Any} previous::AbstractVector # previous[i] is the value of previous(...., i) - nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) previous_names::Vector{String} # previous_names[i] is the name of previous-variable i previous_dict::OrderedDict{String,Int} # previous_dict[name] is the index of previous-variable name pre::AbstractVector - nextPre::AbstractVector pre_names::Vector{String} pre_dict::OrderedDict{String,Int} hold::AbstractVector - nextHold::AbstractVector hold_names::Vector{String} hold_dict::OrderedDict{String,Int} @@ -334,13 +330,6 @@ mutable struct SimulationModel{FloatType,TimeType} time::TimeType nGetDerivatives::Int # Number of getDerivatives! calls nf::Int # Number of getDerivatives! calls from integrator (without zero-crossing calls) - x::Vector{FloatType} # Reference of x-vector passed to getDerivatives!(..) - x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nxFixedLength+i] - x_start::Vector{FloatType} # States x before first event iteration (before initialization) - x_init::Vector{FloatType} # States x after initialization (and before integrator is started) - der_x_visible::Vector{FloatType} # Derivatives of states x or x_init that correspond to visible states - der_x_hidden::Vector{FloatType} # Derivatives of states x or x_init that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) - der_x_full::Vector{FloatType} # Derivatives of states x (needed in DAE mode) odeIntegrator::Bool # = true , if ODE integrator used # = false, if DAE integrator used @@ -348,30 +337,51 @@ mutable struct SimulationModel{FloatType,TimeType} algorithmName::Union{String,Missing} # Name of integration algorithm as string (used in default-heading of plot) addEventPointsDueToDEBug::Bool # = true, if event points are explicitly stored for Sundials integrators, due to bug in DifferentialEquations # (https://github.com/SciML/Sundials.jl/issues/309) + success::Bool # = true, if after first outputs!(..) call and no error was triggered + # = false, either before first outputs!(..) call or at first outputs!(..) after init!(..) and + # an error was triggered and simulate!(..) should be returned with nothing. + unitless::Bool # = true, if simulation is performed without units. + result_info::OrderedDict{String,ResultInfo} # key : Full path name of result variables # value: Storage location and index into the storage. result_vars::AbstractVector # result_vars[ti][j] is result of variable with index j at time instant ti result_x::Union{Any,Missing} # Return value of DifferentialEquations.solve(..) (is a struct) result_der_x::Vector{Vector{FloatType}} # result_der_x[ti][j] is der_x[j] at time instant ti - success::Bool # = true, if after first outputs!(..) call and no error was triggered - # = false, either before first outputs!(..) call or at first outputs!(..) after init!(..) and - # an error was triggered and simulate!(..) should be returned with nothing. - unitless::Bool # = true, if simulation is performed without units. + + parameters::OrderedDict{Symbol,Any} + + # Available after propagateEvaluateAndInstantiate!(..) called + evaluatedParameters::OrderedDict{Symbol,Any} + nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) + nextPre::AbstractVector + nextHold::AbstractVector + x::Vector{FloatType} # Reference of x-vector passed to getDerivatives!(..) + x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nxFixedLength+i] + x_start::Vector{FloatType} # States x before first event iteration (before initialization) + x_init::Vector{FloatType} # States x after initialization (and before integrator is started) + der_x_visible::Vector{FloatType} # Derivatives of states x or x_init that correspond to visible states + der_x_hidden::Vector{FloatType} # Derivatives of states x or x_init that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) + der_x_full::Vector{FloatType} # Derivatives of states x (needed in DAE mode) function SimulationModel{FloatType,TimeType}(modelModule, modelName, buildDict, getDerivatives!, equationInfo, x_startValues, previousVars, preVars, holdVars, parameterDefinition, variableNames; - unitless=true, + unitless::Bool=true, nz::Int = 0, nAfter::Int = 0, vSolvedWithInitValuesAndUnit::AbstractDict = OrderedDict{String,Any}(), vEliminated::Vector{Int} = Int[], vProperty::Vector{Int} = Int[], var_name::Function = v -> nothing) where {FloatType,TimeType} - # Construct result dictionary - result_info = OrderedDict{String, ResultInfo}() + # Construct data structure for linear equations + linearEquations = Modia.LinearEquations{FloatType}[] + for leq in equationInfo.linearEquations + push!(linearEquations, Modia.LinearEquations{FloatType}(leq...)) + end + vSolvedWithInitValuesAndUnit2 = OrderedDict{String,Any}( [(string(key),vSolvedWithInitValuesAndUnit[key]) for key in keys(vSolvedWithInitValuesAndUnit)] ) + # Build previous-arrays previous = Vector{Any}(missing, length(previousVars)) previous_names = string.(previousVars) @@ -387,36 +397,59 @@ mutable struct SimulationModel{FloatType,TimeType} hold_names = string.(holdVars) hold_dict = OrderedDict{String,Int}(zip(hold_names, 1:length(holdVars))) - # Construct parameter values that are copied into the code - #parameterValues = [eval(p) for p in values(parameters)] - #@show typeof(parameterValues) - #@show parameterValues - parameters = deepcopy(parameterDefinition) + # Initialize execution flags + eventHandler = EventHandler{FloatType,TimeType}(nz=nz, nAfter=nAfter) + eventHandler.initial = true + isInitial = true + storeResult = false + solve_leq = true + nGetDerivatives = 0 + nf = 0 + odeIntegrator = true + daeCopyInfo = LinearEquationsCopyInfoForDAEMode[] + algorithmName = missing + addEventPointsDueToDEBug = false + success = false + + # Result data structure + result_info = OrderedDict{String, ResultInfo}() + result_vars = Tuple[] + result_x = missing + result_der_x = Vector{FloatType}[] - # Determine x_start and previous values - evaluatedParameters = propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitless, modelModule, parameters, equationInfo, previous_dict, previous, pre_dict, pre, hold_dict, hold) + parameters = deepcopy(parameterDefinition) + obj = new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!, + equationInfo, linearEquations, eventHandler, + vSolvedWithInitValuesAndUnit2, + previous, previous_names, previous_dict, + pre, pre_names, pre_dict, + hold, hold_names, hold_dict, + isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, + odeIntegrator, daeCopyInfo, algorithmName, addEventPointsDueToDEBug, success, unitless, + result_info, result_vars, result_x, result_der_x, parameters) + + evaluatedParameters = propagateEvaluateAndInstantiate!(obj, log=false) if isnothing(evaluatedParameters) return nothing end + obj.evaluatedParameters = evaluatedParameters + obj.nextPrevious = deepcopy(previous) + obj.nextPre = deepcopy(pre) + obj.nextHold = deepcopy(hold) + # Resize linear equation systems if dimensions of vector valued tearing variables changed # resizeLinearEquations!(m, m.options.log) - - x_start = updateEquationInfo!(equationInfo, FloatType) - nx = length(x_start) - nextPrevious = deepcopy(previous) - nextPre = deepcopy(pre) - nextHold = deepcopy(hold) - #@show equationInfo.nx - #@show nx - - # Provide storage for x_vec - x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.nxVisibleLength)] - # Construct data structure for linear equations - linearEquations = Modia.LinearEquations{FloatType}[] - for leq in equationInfo.linearEquations - push!(linearEquations, Modia.LinearEquations{FloatType}(leq...)) - end + obj.x_start = updateEquationInfo!(equationInfo, FloatType) + nx = length(obj.x_start) + + # Provide storage for x_vec and utility vectors + obj.x = zeros(FloatType,0) + obj.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.nxVisibleLength)] + obj.x_init = zeros(FloatType,nx) + obj.der_x_visible = zeros(FloatType,equationInfo.nxVisible) + obj.der_x_hidden = zeros(FloatType,nx-equationInfo.nxVisible) + obj.der_x_full = zeros(FloatType,nx) # Define result # Store x and der_x @@ -448,26 +481,7 @@ mutable struct SimulationModel{FloatType,TimeType} end end - - # Initialize execution flags - eventHandler = EventHandler{FloatType,TimeType}(nz=nz, nAfter=nAfter) - eventHandler.initial = true - isInitial = true - storeResult = false - solve_leq = true - nGetDerivatives = 0 - nf = 0 - - new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!, - equationInfo, linearEquations, eventHandler, - vSolvedWithInitValuesAndUnit2, parameters, evaluatedParameters, - previous, nextPrevious, previous_names, previous_dict, - pre, nextPre, pre_names, pre_dict, - hold, nextHold, hold_names, hold_dict, - isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, zeros(FloatType,0), - x_vec, x_start, zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), - zeros(FloatType,nx), true, LinearEquationsCopyInfoForDAEMode[], - missing, false, result_info, Tuple[], missing, Vector{FloatType}[], false, unitless) + return obj end @@ -486,21 +500,32 @@ mutable struct SimulationModel{FloatType,TimeType} solve_leq = true nGetDerivatives = 0 nf = 0 + odeIntegrator = true + daeCopyInfo = LinearEquationsCopyInfoForDAEMode[] + algorithmName = missing + addEventPointsDueToDEBug = false + success = false nx = m.equationInfo.nx - new(m.modelModule, m.modelName, deepcopy(m.buildDict), TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), m.options, m.getDerivatives!, m.equationInfo, linearEquations, + new(m.modelModule, m.modelName, deepcopy(m.buildDict), TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), m.options, m.getDerivatives!, m.equationInfo, linearEquations, eventHandler, - m.vSolvedWithInitValuesAndUnit, deepcopy(m.parameters), deepcopy(m.evaluatedParameters), - deepcopy(m.previous), deepcopy(m.nextPrevious), m.previous_names, m.previous_dict, - deepcopy(m.pre), deepcopy(m.nextPre), m.pre_names, m.pre_dict, - deepcopy(m.hold), deepcopy(m.nextHold), m.hold_names, m.hold_dict, - isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, zeros(FloatType,0), deepcopy(m.x_vec), + m.vSolvedWithInitValuesAndUnit, + deepcopy(m.previous), m.previous_names, m.previous_dict, + deepcopy(m.pre), m.pre_names, m.pre_dict, + deepcopy(m.hold), m.hold_names, m.hold_dict, + isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, + true, LinearEquationsCopyInfoForDAEMode[], + odeIntegrator, daeCopyInfo, addEventPointsDueToDEBug, success, m.unitless, + m.result_info, Tuple[], missing, Vector{FloatType}[], + deepcopy(m.parameters), deepcopy(m.evaluatedParameters), + deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), + zeros(FloatType,0), deepcopy(m.x_vec), convert(Vector{FloatType}, m.x_start), zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), - zeros(FloatType,nx), true, LinearEquationsCopyInfoForDAEMode[], - missing, false, m.result_info, Tuple[], missing, Vector{FloatType}[], false, m.unitless) + zeros(FloatType,nx)) end end + # Default constructors SimulationModel{FloatType}(args...; kwargs...) where {FloatType} = SimulationModel{FloatType,FloatType}(args...; kwargs...) @@ -1092,7 +1117,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters if length(m.options.merge) > 0 m.parameters = mergeModels(m.parameters, m.options.merge) - m.evaluatedParameters = propagateEvaluateAndInstantiate!(FloatType, TimeType, m.buildDict, m.unitless, m.modelModule, m.parameters, m.equationInfo, m.previous_dict, m.previous, m.pre_dict, m.pre, m.hold_dict, m.hold) + m.evaluatedParameters = propagateEvaluateAndInstantiate!(m) if isnothing(m.evaluatedParameters) return false end diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 1c96132..f3de9d7 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -50,10 +50,9 @@ appendKey(path, key) = path == "" ? string(key) : path * "." * string(key) """ - map = propagateEvaluateAndInstantiate!(FloatType, unitless::Bool, modelModule::Module, parameters, - eqInfo::Modia.EquationInfo; log=false) + map = propagateEvaluateAndInstantiate!(partiallyInstantiatedModel::SimulationModel; log=false) -Recursively traverse the hierarchical collection `parameters` and perform the following actions: +Recursively traverse the hierarchical collection `partiallyInstantiatedModel.parameters` and perform the following actions: - Propagate values. - Evaluate expressions in the context of `modelModule`. @@ -61,10 +60,10 @@ Recursively traverse the hierarchical collection `parameters` and perform the fo - Return the evaluated `parameters` if successfully evaluated, and otherwise return nothing, if an error occurred (an error message was printed). """ -function propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitless::Bool, modelModule, parameters, eqInfo, previous_dict, previous, pre_dict, pre, hold_dict, hold; log=false) - removeHiddenStates(eqInfo) - x_found = fill(false, length(eqInfo.x_info)) - map = propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitless, modelModule, parameters, eqInfo, x_found, previous_dict, previous, pre_dict, pre, hold_dict, hold, [], ""; log=log) +function propagateEvaluateAndInstantiate!(m::SimulationModel{FloatType,TimeType}; log=false) where {FloatType,TimeType} + removeHiddenStates(m.equationInfo) + x_found = fill(false, length(m.equationInfo.x_info)) + map = propagateEvaluateAndInstantiate2!(m, m.parameters, x_found, [], ""; log=log) if isnothing(map) return nothing @@ -82,8 +81,8 @@ function propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitle missingInitValues = false namesOfMissingValues = "" first = true - for (name,index) in previous_dict - if ismissing(previous[index]) + for (name,index) in m.previous_dict + if ismissing(m.previous[index]) missingInitValues = true if first first = false @@ -95,8 +94,8 @@ function propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitle # Check that all pre values are set: first = true - for (name,index) in pre_dict - if ismissing(pre[index]) + for (name,index) in m.pre_dict + if ismissing(m.pre[index]) missingInitValues = true if first first = false @@ -108,8 +107,8 @@ function propagateEvaluateAndInstantiate!(FloatType, TimeType, buildDict, unitle # Check that all hold values are set: first = true - for (name,index) in hold_dict - if ismissing(hold[index]) + for (name,index) in m.hold_dict + if ismissing(m.hold[index]) missingInitValues = true if first first = false @@ -164,9 +163,8 @@ function changeDotToRef(ex) end -function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitless::Bool, modelModule, parameters, eqInfo::Modia.EquationInfo, x_found::Vector{Bool}, - previous_dict, previous, pre_dict, pre, hold_dict, hold, - environment, path::String; log=false) +function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType}, parameters, x_found::Vector{Bool}, + environment, path::String; log=false) where {FloatType,TimeType} if log println("\n 1: !!! instantiate objects of $path: ", parameters) end @@ -176,6 +174,9 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl constructor = nothing instantiateFunction = nothing usePath = false + modelModule = m.modelModule + eqInfo = m.equationInfo + if haskey(parameters, :_constructor) # For example: obj = (_class = :Par, _constructor = :(Modia3D.Object3D), _path = true, kwargs...) # or: rev = (_constructor = (_class = :Par, value = :(Modia3D.ModiaRevolute), _path=true), kwargs...) @@ -253,8 +254,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl println(" 7: ... key = $k, v = $v") end # For example: k = (a = 2.0, b = :(2*Lx)) - value = propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitless, modelModule, v, eqInfo, x_found, previous_dict, previous, pre_dict, pre, hold_dict, hold, - vcat(environment, [current]), appendKey(path, k); log=log) + value = propagateEvaluateAndInstantiate2!(m, v, x_found, vcat(environment, [current]), appendKey(path, k); log=log) if log println(" 8: ... key = $k, value = $value") end @@ -282,7 +282,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl end end subv = Core.eval(modelModule, subv) - if unitless && eltype(subv) <: Number + if m.unitless && eltype(subv) <: Number # Remove unit subv = stripUnit(subv) end @@ -321,14 +321,14 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl # end #end - elseif haskey(previous_dict, full_key) - previous[ previous_dict[full_key] ] = current[k] + elseif haskey(m.previous_dict, full_key) + m.previous[ m.previous_dict[full_key] ] = current[k] - elseif haskey(pre_dict, full_key) - pre[ pre_dict[full_key] ] = current[k] + elseif haskey(m.pre_dict, full_key) + m.pre[ m.pre_dict[full_key] ] = current[k] - elseif haskey(hold_dict, full_key) - hold[ hold_dict[full_key] ] = current[k] + elseif haskey(m.hold_dict, full_key) + m.hold[ m.hold_dict[full_key] ] = current[k] end end end @@ -338,7 +338,7 @@ function propagateEvaluateAndInstantiate2!(FloatType, TimeType, buildDict, unitl # Call: instantiateFunction(model, FloatType, Timetype, buildDict, path) # (1) Generate an instance of subModel and store it in buildDict[path] # (2) Define subModel states and store them in xxx - Core.eval(modelModule, :($instantiateFunction($current, $FloatType, $TimeType, $buildDict, $eqInfo, $path))) + Core.eval(modelModule, :($instantiateFunction($m, $current, $path))) if log println(" 13: +++ Instantiated $path: $instantiateFunction called to instantiate sub-model and define hidden states\n\n") end diff --git a/src/Modia.jl b/src/Modia.jl index 9b92067..5ced68d 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -164,9 +164,10 @@ include("EquationAndStateInfo.jl") include("StateSelection.jl") include("ModelCollections.jl") -include("EvaluateParameters.jl") include("EventHandler.jl") include("CodeGeneration.jl") +include("EvaluateParameters.jl") + # include("GenerateGetDerivatives.jl") include("Synchronous.jl") include("SimulateAndPlot.jl") diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 9f96a36..111d225 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -136,18 +136,16 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: end -function instantiateLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, - buildDict::OrderedCollections.OrderedDict{String,Any}, - eqInfo::Modia.EquationInfo, - path::String)::Nothing +function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationModel{FloatType,TimeType}, + model::AbstractDict, path::String)::Nothing where {FloatType,TimeType} # Called during evaluation of the parameters (before initialization) #println("... 3: instantiateLinearStateSpace! called for $path with model = $model") - lsBuild::LinearStateSpaceBuild{FloatType} = buildDict[path] + lsBuild::LinearStateSpaceBuild{FloatType} = partiallyInstantiatedModel.buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) @assert(size(ls.A,2) == size(ls.A,1)) @assert(size(ls.B,2) == lsBuild.nu) @assert(size(ls.C,1) == lsBuild.ny) - ls.ix = Modia.addState(eqInfo, path*".x", path*".der(x)", ls.x_init) + ls.ix = Modia.addState(partiallyInstantiatedModel.equationInfo, path*".x", path*".der(x)", ls.x_init) lsBuild.ls = ls return nothing end From f95a0b13daffda32a099af0d15e4688c1ec5667d Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Thu, 12 May 2022 18:01:37 +0200 Subject: [PATCH 16/63] Copy x into m.x_hidden instead of using m.x = , since x_hidden an derx_hidden have the same element indices. --- src/CodeGeneration.jl | 70 ++++++++++++++++++++----------------- src/EquationAndStateInfo.jl | 56 ++++++++++++++--------------- src/EvaluateParameters.jl | 5 ++- src/EventHandler.jl | 10 +++++- src/StateSelection.jl | 2 +- test/TestLinearSystems.jl | 14 ++++---- 6 files changed, 86 insertions(+), 71 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index ade6e4b..3b44c8c 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -355,11 +355,12 @@ mutable struct SimulationModel{FloatType,TimeType} nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) nextPre::AbstractVector nextHold::AbstractVector - x::Vector{FloatType} # Reference of x-vector passed to getDerivatives!(..) - x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nxFixedLength+i] + + x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nx_infoFixed+i] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) der_x_visible::Vector{FloatType} # Derivatives of states x or x_init that correspond to visible states + x_hidden::Vector{FloatType} # A copy of the states x that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) der_x_hidden::Vector{FloatType} # Derivatives of states x or x_init that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) der_x_full::Vector{FloatType} # Derivatives of states x (needed in DAE mode) @@ -436,19 +437,17 @@ mutable struct SimulationModel{FloatType,TimeType} obj.nextPrevious = deepcopy(previous) obj.nextPre = deepcopy(pre) obj.nextHold = deepcopy(hold) - - # Resize linear equation systems if dimensions of vector valued tearing variables changed - # resizeLinearEquations!(m, m.options.log) obj.x_start = updateEquationInfo!(equationInfo, FloatType) nx = length(obj.x_start) - + nxHidden = nx-equationInfo.nxVisible + # Provide storage for x_vec and utility vectors - obj.x = zeros(FloatType,0) - obj.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nxFixedLength+1:length(equationInfo.nxVisibleLength)] + obj.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_infoFixed+1:length(equationInfo.nx_infoVisible)] obj.x_init = zeros(FloatType,nx) obj.der_x_visible = zeros(FloatType,equationInfo.nxVisible) - obj.der_x_hidden = zeros(FloatType,nx-equationInfo.nxVisible) + obj.x_hidden = zeros(FloatType, nxHidden) + obj.der_x_hidden = zeros(FloatType, nxHidden) obj.der_x_full = zeros(FloatType,nx) # Define result @@ -561,29 +560,30 @@ end export copyState! """ - copyState!(m::SimulationModel, x_index::Int, xi) + copyState!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, xi::Vector{FloatType}) -Copy state of m.equationInfo.x_info[x_index] from m.x into pre-allocated vector xi. +Copy state of m.equationInfo.x_info[x_infoIndex] from m.x_hidden into pre-allocated vector xi. """ -function copyState!(m::SimulationModel{FloatType,TimeType}, x_index::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} - @assert(length(xi) == m.equationInfo.x_info[x_index].length) - startIndex = m.equationInfo.x_info[x_index].startIndex - 1 +function copyState!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} + @assert(length(xi) == m.equationInfo.x_info[x_infoIndex].length) + startIndex = m.equationInfo.x_info[x_infoIndex].startIndex - m.equationInfo.nxVisible - 1 for i = 1:length(xi) - xi[i] = m.x[startIndex+i] + xi[i] = m.x_hidden[startIndex+i] end return nothing end """ - set_hiddenStateDerivative!(m::SimulationModel, x_index, der_x) + set_hiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, der_x::Vector{FloatType}) -Copy hidden state derivative der_x of m.equationInfo.x_info[x_index] into full state derivative vector +Copy hidden state derivative der_x of m.equationInfo.x_info[x_infoIndex] into m.der_x_hidden. """ -function set_hiddenStateDerivative!(m::SimulationModel, x_index::Int, der_x)::Nothing - @assert(length(der_x) == m.equationInfo.x_info[x_index].length) +function set_hiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, der_x::Vector{FloatType})::Nothing where {FloatType,TimeType} + ix_info = m.equationInfo.x_info[x_infoIndex] + @assert(length(der_x) == ix_info.length) #println("set_hiddenStateDerivative!: x_index = $x_index, der_x = $der_x") - startIndex = m.equationInfo.x_info[x_index].startIndex - m.equationInfo.nxVisible - 1 + startIndex = ix_info.startIndex - m.equationInfo.nxVisible - 1 for i = 1:length(der_x) m.der_x_hidden[startIndex+i] = der_x[i] end @@ -1071,15 +1071,19 @@ invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing = TimerOutputs.@tim eqInfo = m.equationInfo x_vec = m.x_vec j = 0 - for i in eqInfo.nxFixedLength+1:eqInfo.nxVisibleLength + for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible j += 1 xe = eqInfo.x_info[i] x_vec[j] .= x[xe.startIndex:(xe.startIndex+xe.length-1)] end end empty!(m.der_x_visible) + j::Int = 0 + for i in m.equationInfo.nxVisible+1:length(x) + j += 1 + m.x_hidden[j] = x[i] + end m.der_x_hidden .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 - m.x = x Base.invokelatest(m.getDerivatives!, x, m, t) @assert(length(m.der_x_visible) + length(m.der_x_hidden) == length(x)) @@ -1117,23 +1121,23 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters if length(m.options.merge) > 0 m.parameters = mergeModels(m.parameters, m.options.merge) - m.evaluatedParameters = propagateEvaluateAndInstantiate!(m) - if isnothing(m.evaluatedParameters) + evaluatedParameters = propagateEvaluateAndInstantiate!(m) + if isnothing(evaluatedParameters) return false end - - # Resize linear equation systems if dimensions of vector valued tearing variables changed - resizeLinearEquations!(m, m.options.log) + m.evaluatedParameters = evaluatedParameters # Resize state vector memory m.x_start = updateEquationInfo!(m.equationInfo, FloatType) - nx = length(m.x_start) + nx = length(m.x_start) + nxHidden = nx - m.equationInfo.nxVisible resize!(m.x_init, nx) resize!(m.der_x_visible, m.equationInfo.nxVisible) - resize!(m.der_x_hidden , nx - m.equationInfo.nxVisible) + resize!(m.x_hidden , nxHidden) + resize!(m.der_x_hidden , nxHidden) resize!(m.der_x_full , nx) eqInfo = m.equationInfo - m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nxFixedLength+1:eqInfo.nxVisibleLength] + m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible] end # Initialize auxiliary arrays for event iteration @@ -1670,7 +1674,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati push!(code_der_x, :( Modia.appendVariable!(_m.der_x_visible, -_x[1]) )) else i1 = 1 - for i in 1:equationInfo.nxFixedLength + for i in 1:equationInfo.nx_infoFixed xe = x_info[i] x_name = xe.x_name_julia # x_name = Meta.parse("m."*xe.x_name) @@ -1703,7 +1707,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati end i1 = 0 - for i in equationInfo.nxFixedLength+1:equationInfo.nxVisibleLength + for i in equationInfo.nx_infoFixed+1:equationInfo.nx_infoVisible # x-element is a dynamic vector (length can change before initialization) xe = x_info[i] x_name = xe.x_name_julia @@ -1716,7 +1720,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati end end - for i in 1:equationInfo.nxVisibleLength + for i in 1:equationInfo.nx_infoVisible xe = equationInfo.x_info[i] der_x_name = xe.der_x_name_julia if hasUnits diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index f5c0038..406bf70 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -682,7 +682,7 @@ end nz = 0, x_info = StateElementInfo[], nx = -1, - nxFixedLength = nx, + nx_infoFixed = -1, residualCategories = ResidualCategory[], linearEquations = Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}[], vSolvedWithFixedTrue = String[], @@ -729,10 +729,10 @@ mutable struct EquationInfo linearEquations::Vector{Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}} vSolvedWithFixedTrue::Vector{String} nx::Int # = length(x) or -1 if not yet known - nxVisible::Int # = number of visible x-elements or -1 if not yet known - nxFixedLength::Int # x_info[1:nxFixedLength] are states with fixed length (does not change after compilation) or -1 if not yet known - nxVisibleLength::Int # x_info[1:nxVisibleLength] are states that are visible in getDerivatives!(..) or -1 if not yet known - # x_info[nxVisibleLength+1:end] are states defined in functions that are not visible in getDerivatives!(..) + nxVisible::Int # = number of visible x-elements (so x[1:nxVisible] are visible states) or -1 if not yet known + nx_infoFixed::Int # x_info[1:nx_infoFixed] are states with fixed length (does not change after compilation) or -1 if not yet known + nx_infoVisible::Int # x_info[1:nx_infoVisible] are states that are visible in getDerivatives!(..) or -1 if not yet known + # x_info[nx_infoVisible+1:end] are states defined in functions that are not visible in getDerivatives!(..) #x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] # # or empty vector, if not yet known. x_dict::OrderedCollections.OrderedDict{String,Int} # x_dict[x_name] returns the index of x_name with respect to x_info @@ -750,14 +750,14 @@ EquationInfo(; status = MANUAL, residualCategories = ResidualCategory[], linearEquations = Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}[], vSolvedWithFixedTrue = String[], - nxFixedLength = -1, - nxVisibleLength = -1, + nx_infoFixed = -1, + nx_infoVisible = -1, defaultParameterAndStartValues::Union{AbstractDict,Nothing} = nothing, ResultType = nothing, ResultTypeHasFloatType = false) = EquationInfo(status, ode, nz, x_info, residualCategories, linearEquations, vSolvedWithFixedTrue, -1, -1, - nxFixedLength, nxVisibleLength, + nx_infoFixed, nx_infoVisible, OrderedCollections.OrderedDict{String,Int}(), OrderedCollections.OrderedDict{String,Int}(), defaultParameterAndStartValues, @@ -781,7 +781,7 @@ function initEquationInfo!(eqInfo::EquationInfo)::Nothing end eqInfo.nx = startIndex - 1 eqInfo.nxVisible = eqInfo.nx - eqInfo.nxVisibleLength = length(eqInfo.x_info) + eqInfo.nx_infoVisible = length(eqInfo.x_info) return nothing end @@ -792,7 +792,7 @@ end Return initial state vector `Vector{FloatType}` with stripped units. """ function initialStateVector(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} - x_start = fill(FloatType(0), eqInfo.nx) + x_start = zeros(FloatType, eqInfo.nx) startIndex = 1 for xe_info in eqInfo.x_info if xe_info.scalar @@ -818,12 +818,12 @@ Remove all hidden (non-visible) states from `eqInfo`. """ function removeHiddenStates(eqInfo::EquationInfo)::Nothing if eqInfo.nx > eqInfo.nxVisible - for i = eqInfo.nxVisibleLength+1:length(eqInfo.x_info) + for i = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) xi_info = eqInfo.x_info[i] delete!(eqInfo.x_dict , xi_info.x_name) delete!(eqInfo.der_x_dict, xi_info.der_x_name) end - resize!(eqInfo.x_info, eqInfo.nxVisibleLength) + resize!(eqInfo.x_info, eqInfo.nx_infoVisible) eqInfo.nx = eqInfo.nxVisible end return nothing @@ -831,13 +831,13 @@ end """ - xindex = addState(eqInfo::EquationInfo, - x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; - stateCategory::StateCategory = XD, - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false)::Int where {FloatType} + x_infoIndex = addState(eqInfo::EquationInfo, + x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; + stateCategory::StateCategory = XD, + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false)::Int where {FloatType} Add new state to model and return its index (new state info is stored in eqInfo.x_info[xindex]). """ @@ -855,10 +855,10 @@ function addState(eqInfo::EquationInfo, x_name::String, der_x_name::String, star xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), stateCategory, unit, startOrInit, fixed, nominal, unbounded) push!(eqInfo.x_info, xi_info) - ix = length(eqInfo.x_info) - eqInfo.x_dict[x_name] = ix - eqInfo.der_x_dict[der_x_name] = ix - return ix + x_infoIndex = length(eqInfo.x_info) + eqInfo.x_dict[x_name] = x_infoIndex + eqInfo.der_x_dict[der_x_name] = x_infoIndex + return x_infoIndex end @@ -869,7 +869,7 @@ Set eqInfo.x_dict, eqInfo.der_x_dict, eqInfo.nx and eqInfo.x_info[:].startIndex and return initial state vector x_start """ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} - nxFixedLength = eqInfo.nxFixedLength + nx_infoFixed = eqInfo.nx_infoFixed x_info = eqInfo.x_info if length(x_info) == 0 # Handle systems with only algebraic variables, by introducing a dummy @@ -879,14 +879,14 @@ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex = 1 eqInfo.x_dict["_dummy_x"] = 1 eqInfo.der_x_dict["der(_dummy_x)"] = 1 - elseif nxFixedLength == 0 + elseif nx_infoFixed == 0 startIndex = 1 else - xi_info = x_info[nxFixedLength] + xi_info = x_info[nx_infoFixed] startIndex = xi_info.startIndex + xi_info.length end - for i = nxFixedLength+1:length(x_info) + for i = nx_infoFixed+1:length(x_info) xi_info = x_info[i] xi_info.length = length(xi_info.startOrInit) xi_info.startIndex = startIndex @@ -895,7 +895,7 @@ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa eqInfo.nx = startIndex - 1 nxVisible = 0 - for i = 1:eqInfo.nxVisibleLength + for i = 1:eqInfo.nx_infoVisible xi_info = x_info[i] nxVisible += x_info[i].length end diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index f3de9d7..99fce68 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -126,6 +126,9 @@ function propagateEvaluateAndInstantiate!(m::SimulationModel{FloatType,TimeType} return nothing end + # Resize linear equation systems if dimensions of vector valued tearing variables changed + resizeLinearEquations!(m, m.options.log) + #if length(x_start_missing) > 0 # printstyled("Model error: ", bold=true, color=:red) # printstyled("Missing start/init values for variables: ", x_start_missing, @@ -301,7 +304,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType xe_info = eqInfo.x_info[j] x_value = current[k] len = hasParticles(x_value) ? 1 : length(x_value) - if j <= eqInfo.nxFixedLength && len != xe_info.length + if j <= eqInfo.nx_infoFixed && len != xe_info.length printstyled("Model error: ", bold=true, color=:red) printstyled("Length of ", xe_info.x_name, " shall be changed from ", xe_info.length, " to $len\n", diff --git a/src/EventHandler.jl b/src/EventHandler.jl index 16ea96b..fe6d1e5 100644 --- a/src/EventHandler.jl +++ b/src/EventHandler.jl @@ -68,6 +68,9 @@ mutable struct EventHandler{FloatType,TimeType} # For state events: zEps::FloatType # Epsilon for zero-crossing hysteresis nz::Int # Number of event indicators + nzVisible::Int # Number of event indicators defined in visible model equations + # More event indicators can be defined by objects that are not visible in the generated code, i.e. nz >= nzVisible + # These event indicators are defined in propagateEvaluateAndInstantiate!(..) via _instantiateFunction(..) z::Vector{FloatType} # Vector of event indicators (zero crossings). If one of z[i] passes # zero, that is beforeEvent(z[i])*z[i] < 0, an event is triggered # (allocated during instanciation according to nz). @@ -88,7 +91,7 @@ mutable struct EventHandler{FloatType,TimeType} zEps = FloatType(1e-10) new(floatmax(TimeType), logEvents, 0, 0, 0, 0, convert(TimeType,0), false, false, false, false, false, false, false, false, false, floatmax(TimeType), floatmax(TimeType), - true, NoRestart, false, false, zEps, nz, ones(FloatType,nz), fill(false, nz), nAfter, fill(false,nAfter), + true, NoRestart, false, false, zEps, nz, nz, ones(FloatType,nz), fill(false, nz), nAfter, fill(false,nAfter), fill(convert(TimeType,0),nClock), Vector{Any}(undef, nSample)) end end @@ -126,6 +129,11 @@ function reinitEventHandler(eh::EventHandler{FloatType,TimeType}, stopTime::Time eh.z .= convert(FloatType, 0) eh.after .= false + if eh.nz > eh.nzVisible + resize!(eh.z, eh.nzVisible) + resize!(eh.zPositive, eh.nzVisible) + eh.nz = eh.nzVisible + end return nothing end diff --git a/src/StateSelection.jl b/src/StateSelection.jl index be866b0..1ec3dbd 100644 --- a/src/StateSelection.jl +++ b/src/StateSelection.jl @@ -1500,7 +1500,7 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} push!(x_vec_fixed , v_fixed) end end - eq.equationInfo.nxFixedLength = length(x_info) + eq.equationInfo.nx_infoFixed = length(x_info) for (i,v) in enumerate(x_vec) v_startOrInit = x_vec_startOrInit[i] v_fixed = x_vec_fixed[i] diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 111d225..5364e9c 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -56,8 +56,8 @@ LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace kwargs...) mutable struct LinearStateSpaceStruct{FloatType} - path::String # Path name of instance - ix::Int # Index with respect to equationInfo.x_info + path::String # Path name of instance + x_infoIndex::Int # Index with respect to equationInfo.x_info A::Matrix{FloatType} B::Matrix{FloatType} C::Matrix{FloatType} @@ -126,7 +126,7 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: u = Var(input = true, start = u_zeros), y = Var(output = true, start = y_zeros), equations = :[ - ls = getLinearStateSpace!(instantiatedModel, $pathAsString) + ls = openLinearStateSpace!(instantiatedModel, $pathAsString) y = computeOutputs!(instantiatedModel, ls) success = computeStateDerivatives!(instantiatedModel, ls, u)]) @@ -145,15 +145,15 @@ function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationMode @assert(size(ls.A,2) == size(ls.A,1)) @assert(size(ls.B,2) == lsBuild.nu) @assert(size(ls.C,1) == lsBuild.ny) - ls.ix = Modia.addState(partiallyInstantiatedModel.equationInfo, path*".x", path*".der(x)", ls.x_init) + ls.x_infoIndex = Modia.addState(partiallyInstantiatedModel.equationInfo, path*".x", path*".der(x)", ls.x_init) lsBuild.ls = ls return nothing end -function getLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} +function openLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls - copyState!(instantiatedModel, ls.ix, ls.x) + copyState!(instantiatedModel, ls.x_infoIndex, ls.x) return ls end @@ -166,7 +166,7 @@ function computeStateDerivatives!(instantiatedModel, ls, u)::Bool # ls.derx .= ls.A*ls.x + ls.B*u mul!(ls.derx, ls.A, ls.x) mul!(ls.derx, ls.B, u, 1.0, 1.0) - Modia.set_hiddenStateDerivative!(instantiatedModel, ls.ix, ls.derx) + Modia.set_hiddenStateDerivative!(instantiatedModel, ls.x_infoIndex, ls.derx) return true end From 53ae3f3ed2e87875159e9359f3d6a06b6e5f1cc3 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 13 May 2022 15:33:14 +0200 Subject: [PATCH 17/63] Some improvements; propagateEvaluateAndInstantiate!(..): Better error message, if core.eval(..) fails, e.g. due to a wrong user input. --- src/CodeGeneration.jl | 14 +++++--- src/EquationAndStateInfo.jl | 4 +-- src/EvaluateParameters.jl | 68 ++++++++++++++++++++++++++++--------- src/EventHandler.jl | 22 +++++++----- 4 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 3b44c8c..b5cc773 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1036,12 +1036,16 @@ getTime(m::SimulationModel) = m.time Add nz new zero crossing functions and return the start index with respect to instantiatedModel.eventHandler.z. """ -function addZeroCrossings(m::SimulationModel, nz::Int)::Int +function addZeroCrossings(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} eh = m.eventHandler zStartIndex = eh.nz + 1 eh.nz += nz resize!(eh.z, eh.nz) resize!(eh.zPositive, eh.nz) + for i = zStartIndex:eh.nz + eh.z[i] = convert(F, 1.0) + eh.zPositive[i] = false + end return zStartIndex end @@ -1115,7 +1119,7 @@ If initialization is successful return true, otherwise false. function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,TimeType} emptyResult!(m) eh = m.eventHandler - reinitEventHandler(eh, m.options.stopTime, m.options.logEvents) + reinitEventHandler!(eh, m.options.stopTime, m.options.logEvents) eh.firstInitialOfAllSegments = true # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters @@ -1573,13 +1577,13 @@ end """ - resizeLinearEquations!(instantiatedModel) + resizeLinearEquations!(partiallyInstantiatedModel, evaluatedParameters, log::Bool) Inspect all linear equations inside the instantiatedModel and resize the internal storage, of the length of vector-valued elements of the iteration variables has changed due to changed parameter values. """ -function resizeLinearEquations!(m::SimulationModel{FloatType}, log::Bool)::Nothing where {FloatType} +function resizeLinearEquations!(m::SimulationModel{FloatType,TimeType}, evaluatedParameters, log::Bool)::Nothing where {FloatType,TimeType} for (i,leq) in enumerate(m.linearEquations) nx_vec = length(leq.x_names) - leq.nx_fixedLength if nx_vec > 0 @@ -1587,7 +1591,7 @@ function resizeLinearEquations!(m::SimulationModel{FloatType}, log::Bool)::Nothi for i = leq.nx_fixedLength+1:length(leq.x_names) # Length of element is determined by start or init value xi_name = leq.x_names[i] - xi_param = get_value(m.evaluatedParameters, xi_name) + xi_param = get_value(evaluatedParameters, xi_name) if ismissing(xi_param) @error "resizeLinearEquations!(instantiatedModel,$i): $xi_name is not part of the evaluated parameters." end diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 406bf70..5e1ec5b 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -812,11 +812,11 @@ end """ - removeHiddenStates(eqInfo::EquationInfo) + removeHiddenStates!(eqInfo::EquationInfo) Remove all hidden (non-visible) states from `eqInfo`. """ -function removeHiddenStates(eqInfo::EquationInfo)::Nothing +function removeHiddenStates!(eqInfo::EquationInfo)::Nothing if eqInfo.nx > eqInfo.nxVisible for i = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) xi_info = eqInfo.x_info[i] diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 99fce68..e050daf 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -8,6 +8,30 @@ Recursively instantiate dependent objects and propagate value in hierarchical Na =# +function getConstructorAsString(path, constructor, parameters):String + str = "" + for (key,value) in parameters + skey = string(key) + if length(skey) > 0 && skey[1] != '_' + if str != "" + str = str*", " + end + if typeof(value) == Symbol + svalue = ":" * string(value) + else + svalue = string(value) + end + str = str * skey * "=" * svalue + end + end + if isnothing(path) + str = string(constructor) * "(" * str * ")" + else + str = path * " = " * string(constructor) * "(" * str * ")" + end + return str +end + using OrderedCollections: OrderedDict @@ -61,7 +85,9 @@ Recursively traverse the hierarchical collection `partiallyInstantiatedModel.par return nothing, if an error occurred (an error message was printed). """ function propagateEvaluateAndInstantiate!(m::SimulationModel{FloatType,TimeType}; log=false) where {FloatType,TimeType} - removeHiddenStates(m.equationInfo) + removeHiddenStates!(m.equationInfo) + removeHiddenCrossingFunctions!(m.eventHandler) + x_found = fill(false, length(m.equationInfo.x_info)) map = propagateEvaluateAndInstantiate2!(m, m.parameters, x_found, [], ""; log=log) @@ -126,9 +152,13 @@ function propagateEvaluateAndInstantiate!(m::SimulationModel{FloatType,TimeType} return nothing end + if isnothing(map) + return nothing + end + # Resize linear equation systems if dimensions of vector valued tearing variables changed - resizeLinearEquations!(m, m.options.log) - + resizeLinearEquations!(m, map, m.options.log) + #if length(x_start_missing) > 0 # printstyled("Model error: ", bold=true, color=:red) # printstyled("Missing start/init values for variables: ", x_start_missing, @@ -179,7 +209,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType usePath = false modelModule = m.modelModule eqInfo = m.equationInfo - + if haskey(parameters, :_constructor) # For example: obj = (_class = :Par, _constructor = :(Modia3D.Object3D), _path = true, kwargs...) # or: rev = (_constructor = (_class = :Par, value = :(Modia3D.ModiaRevolute), _path=true), kwargs...) @@ -234,7 +264,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType # or: k = (_class = :Par, value = :(bar.frame0)) -> k = ref(bar.frame0) if log println(" 4: v[:value] = ", v[:value], ", typeof(v[:value]) = ", typeof(v[:value])) - println(" vcat(environment, [current]) = ", vcat(environment, [current])) + #println(" vcat(environment, [current]) = ", vcat(environment, [current])) end subv = subst(v[:value], vcat(environment, [current]), modelModule) if log @@ -341,22 +371,28 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType # Call: instantiateFunction(model, FloatType, Timetype, buildDict, path) # (1) Generate an instance of subModel and store it in buildDict[path] # (2) Define subModel states and store them in xxx - Core.eval(modelModule, :($instantiateFunction($m, $current, $path))) if log - println(" 13: +++ Instantiated $path: $instantiateFunction called to instantiate sub-model and define hidden states\n\n") + println(" 13: +++ Instantiated $path: $instantiateFunction will be called to instantiate sub-model and define hidden states\n\n") end - end + Core.eval(modelModule, :($instantiateFunction($m, $current, $path))) + end return current else - if usePath - obj = Core.eval(modelModule, :(FloatType = $FloatType; $constructor(; path = $path, $current...))) - else - obj = Core.eval(modelModule, :(FloatType = $FloatType; $constructor(; $current...))) - end - if log - println(" 14: +++ Instantiated $path: typeof(obj) = ", typeof(obj), ", obj = ", obj, "\n\n") + try + if usePath + obj = Core.eval(modelModule, :(FloatType = $FloatType; $constructor(; path = $path, $current...))) + else + obj = Core.eval(modelModule, :(FloatType = $FloatType; $constructor(; $current...))) + end + if log + println(" 14: +++ Instantiated $path: typeof(obj) = ", typeof(obj), ", obj = ", obj, "\n\n") + end + return obj + catch + str = getConstructorAsString(path, constructor, parameters) + printstyled("\nError in model $(m.modelName) when instantiating\n$str\n", bold=true, color=:red) + Base.rethrow() end - return obj end end diff --git a/src/EventHandler.jl b/src/EventHandler.jl index fe6d1e5..ce9f231 100644 --- a/src/EventHandler.jl +++ b/src/EventHandler.jl @@ -101,7 +101,17 @@ end #EventHandler{FloatType}(; kwargs...) where {FloatType} = EventHandler{FloatType,Float64}(; kwargs...) -function reinitEventHandler(eh::EventHandler{FloatType,TimeType}, stopTime::TimeType, logEvents::Bool)::Nothing where {FloatType,TimeType} +function removeHiddenCrossingFunctions!(eh::EventHandler{FloatType,TimeType})::Nothing where {FloatType,TimeType} + if eh.nz > eh.nzVisible + resize!(eh.z, eh.nzVisible) + resize!(eh.zPositive, eh.nzVisible) + eh.nz = eh.nzVisible + end + return nothing +end + + +function reinitEventHandler!(eh::EventHandler{FloatType,TimeType}, stopTime::TimeType, logEvents::Bool)::Nothing where {FloatType,TimeType} eh.logEvents = logEvents eh.nZeroCrossings = 0 eh.nRestartEvents = 0 @@ -126,14 +136,10 @@ function reinitEventHandler(eh::EventHandler{FloatType,TimeType}, stopTime::Time eh.restart = Restart eh.newEventIteration = false eh.firstEventIteration = true - eh.z .= convert(FloatType, 0) + eh.z .= convert(FloatType, 1.0) + eh.zPositive .= false eh.after .= false - - if eh.nz > eh.nzVisible - resize!(eh.z, eh.nzVisible) - resize!(eh.zPositive, eh.nzVisible) - eh.nz = eh.nzVisible - end + return nothing end From 77a99719d70819185b9acf4902a41f72f91b5846 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 13 May 2022 19:03:19 +0200 Subject: [PATCH 18/63] Bug fix: signalNames(instantiatedModel) returns now the names in the result; better error messages in propagateEvaluateAndInstantiate!(..) --- docs/src/index.md | 7 +++++++ src/EvaluateParameters.jl | 5 +++++ src/SimulateAndPlot.jl | 16 +++------------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 4d244b2..7b26eb1 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -36,6 +36,13 @@ functionalities of these packages. ## Release Notes +### Version 0.9.0-dev + +** Bug fixes + +- `signalNames(instantiatedModel)` did sometimes not show the signal names in the result (is now fixed). + + ### Version 0.8.3 - Bug fix: Parameters that are Numbers, but not AbstractFloats, and have no unit defined, diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index e050daf..4add4b8 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -18,8 +18,13 @@ function getConstructorAsString(path, constructor, parameters):String end if typeof(value) == Symbol svalue = ":" * string(value) + elseif typeof(value) <: AbstractDict + svalue = "..." # Do not show dictionaries, since too much output, especially due to pointers to Object3Ds else svalue = string(value) + if length(svalue) > 20 + svalue = svalue[1:20] * "..." # Restrict the length of the output + end end str = str * skey * "=" * svalue end diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 2191432..ddaab1a 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -603,22 +603,12 @@ end """ - signalNames(instantiatedModel) + names = signalNames(instantiatedModel::Modia.SimulationModel) Return the variable names (parameters, time-varying variables) of an -[`@instantiateModel`](@ref) that can be accessed and can be used for plotting. +[`@instantiateModel`](@ref) that are present in the result (e.g. can be accessed for plotting). """ -function ModiaResult.signalNames(m::SimulationModel) - #if m.save_x_in_solution - # names = ["time"] - # append!(names, collect( keys(m.equationInfo.x_dict) )) - #else - all_names = get_names(m.evaluatedParameters) - append!(all_names, setdiff(collect( keys(m.result_info) ), all_names) ) - #end - sort!(all_names) - return all_names -end +ModiaResult.signalNames(m::SimulationModel) = collect(keys(m.result_info)) #= From cd9cda2eddb78e39387de49df2f282aaa6a96b9d Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 17 May 2022 09:04:39 +0200 Subject: [PATCH 19/63] - Cleanup, especially of EquationInfo - The initial state vector was not always correctly filled with start/init values of the model (is now fixed). - signalNames(..) did sometimes not show the correct signal names available in the result (is now fixed). - Parameters are no longer seen as part of the result (e.g. signalNames(..) does not return parameters). - Parameters can be accessed with new functions: hasParameter, getParameter, getEvaluatedParameter, showParameter, showEvaluatedParameter - More tests in Modia/test/TestLinearSystems.jl - Replacing "using Test" by "using Modia.Test" in the test models. - @showModel: Number arrays are printed in a nicer way. - Docu Modia/Functions improved --- docs/src/Functions.md | 121 +++-- docs/src/index.md | 144 +++--- docs/src/tutorial/Simulation.md | 2 +- src/CodeGeneration.jl | 153 +++--- src/EquationAndStateInfo.jl | 486 +++++++----------- src/EvaluateParameters.jl | 9 +- src/ModelCollections.jl | 16 +- src/Modia.jl | 14 +- src/ModiaLang.jl | 7 +- src/SimulateAndPlot.jl | 79 ++- src/StateSelection.jl | 19 +- test/TestFilterCircuit.jl | 20 +- test/TestFirstOrder2.jl | 3 +- test/TestHeatTransfer.jl | 2 +- test/TestLinearEquations.jl | 2 +- test/TestLinearSystems.jl | 90 +++- test/TestParameter.jl | 2 +- test/TestStateSelection.jl | 2 +- test/TestTwoInertiasAndIdealGear.jl | 2 +- test/TestTwoInertiasAndIdealGearWithUnits.jl | 2 +- ...asAndIdealGearWithUnitsAndUncertainties.jl | 2 +- 21 files changed, 622 insertions(+), 555 deletions(-) diff --git a/docs/src/Functions.md b/docs/src/Functions.md index 70de554..00ad0a8 100644 --- a/docs/src/Functions.md +++ b/docs/src/Functions.md @@ -25,50 +25,97 @@ simulate! linearize! ``` +## Parameters/Init/Start -## Results and Plotting +```@meta +CurrentModule = Modia +``` + +The following functions are provided to inquire values of *parameters* and of +*init/start* values before and after *evaluation*: + +| Functions | Description | +|:----------------------------------|:--------------------------------------------------------| +| [`hasParameter`](@ref) | Return true, if a parameter/init/start name is known | +| [`getParameter`](@ref) | Return value of a parameter/init/start name | +| [`getEvaluatedParameter`](@ref) | Return value of an evaluated parameter/init/start name | +| [`getLastValue`](@ref) | Return last available value of a variable name | +| [`showParameters`](@ref) | Print the parameters and the init/start values | +| [`showEvaluatedParameters`](@ref) | Print the evaluated parameters and init/start values | + + +```@docs +hasParameter +getParameter +getEvaluatedParameter +getLastValue +showParameters +showEvaluatedParameters +``` + + +## Results + +```@meta +CurrentModule = Modia +``` -The simulation result of a model `instantiatedModel` supports the abstract interface -[ModiaResult](https://modiasim.github.io/ModiaResult.jl/stable/index.html) and +The simulation result of a model `instantiatedModel` supports the functions of +[ModiaResult](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html) and exports them, so the functions can be accessed without prefixing them with `Modia`. -The following functions are provided (for details see -[Functions of ModiaResult](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#Functions-of-ModiaResult)): + +The following functions are provided to access **Modia results** +(use `ìnstantiatedModel` as argument `result`, e.g. `printResultInfo(instantiatedModel)`): + +| Functions | Description | +|:---------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------| +| [`printResultInfo` ](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.printResultInfo) | Print info of the result on stdout. | +| [`resultInfo`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.resultInfo) | Return info about the result as [DataFrame](https://github.com/JuliaData/DataFrames.jl) table | +| [`rawSignal`](https://modiasim.github.io/ModiaResult.jl/stable/AbstractInterface.html#ModiaResult.rawSignal) | Return raw signal data given the signal name. | +| [`getPlotSignal`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.getPlotSignal) | Return signal data prepared for a plot package. | +| [`signalNames`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.signalNames) | Return all signal names. | +| [`timeSignalName`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.timeSignalName) | Return the name of the time signal. | +| [`hasOneTimeSignal`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.hasOneTimeSignal) | Return true if one time signal present. | +| [`hasSignal`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.hasSignal) | Return true if a signal name is known. | +| [`getLastValue`](@ref) | Return last available value of variable name | +| [`defaultHeading`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.defaultHeading`) | Return default heading of a result. | + + +## Plotting ```@meta CurrentModule = Modia ``` -| Functions | Description | -|:---------------------------------|:--------------------------------------------------| -| `@usingModiaPlot` | Expands into `using ModiaPlot_` | -| `usePlotPackage` | Define the plot package to be used. | -| `usePreviousPlotPackage` | Define the previously defined plot package to be used. | -| `currentPlotPackage` | Return name defined with `usePlotPackage` | -| `resultInfo` | Return info about the result as [DataFrame](https://github.com/JuliaData/DataFrames.jl) table | -| `printResultInfo` | Print info of the result on stdout. | -| `rawSignal` | Return raw signal data given the signal name. | -| `getPlotSignal` | Return signal data prepared for a plot package. | -| `defaultHeading` | Return default heading of a result. | -| `signalNames` | Return all signal names. | -| `timeSignalName` | Return the name of the time signal. | -| `hasOneTimeSignal` | Return true if one time signal present. | -| `hasSignal` | Return true if a signal name is known. | - - -The following functions are available after `ENV["MODIA_PLOT"] = XXX` or -`@usingModiaPlot(XXX)` have been executed -(for details see -[Functions of Plot Package](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#Functions-of-Plot-Package)): - - -| Functions | Description | -|:-------------------|:----------------------------------------------------------| -| `plot` | Plot simulation results in multiple diagrams/figures. | -| `saveFigure` | Save figure in different formats on file. | -| `closeFigure` | Close one figure | -| `closeAllFigures` | Close all figures | -| `showFigure` | Show figure in window (only GLMakie, WGLMakie) | +The simulation result of a model `instantiatedModel` supports the functions of +[ModiaResult](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html) and +exports them, so the functions can be accessed without prefixing them with `Modia`. + +The following functions are provided to **define/inquire the current plot package**: + +| Functions | Description | +|:-------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------| +| [`@usingModiaPlot`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.@usingModiaPlot) | Expands into `using ModiaPlot_` | +| [`usePlotPackage`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.usePlotPackage) | Define the plot package to be used. | +| [`usePreviousPlotPackage`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.usePreviousPlotPackage) | Define the previously defined plot package to be used. | +| [`currentPlotPackage`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.currentPlotPackage) | Return name defined with `usePlotPackage` | +The following functions are available after + +1. `ENV["MODIA_PLOT"] = XXX` (e.g. in startup.jl file) or + `@usingModiaPlot(XXX)` has been executed (XXX = "PyPlot", "GLMakie", "WGLMakie", "CairoMakie", "NoPlot" or "SilentNoPlot") and +2. `@usingModiaPlot` has been called, + +to **plot with the currently defined plot package** +(use `ìnstantiatedModel` as argument `result`, e.g. `plot(instantiatedModel, ...)`): + +| Functions | Description | +|:----------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------| +| [`plot`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.plot) | Plot simulation results in multiple diagrams/figures. | +| [`saveFigure`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.saveFigure) | Save figure in different formats on file. | +| [`closeFigure`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.closeFigure) | Close one figure | +| [`closeAllFigures`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.closeAllFigures) | Close all figures | +| [`showFigure`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.showFigure) | Show figure in window (only GLMakie, WGLMakie) | A Modia variable `a.b.c` is identified by a String key `"a.b.c"`. The legends/labels of the plots are automatically constructed by the @@ -93,6 +140,10 @@ generates the following plot: ## PathPlanning +```@meta +CurrentModule = Modia +``` + There are some pre-defined functions to define reference paths ```@docs diff --git a/docs/src/index.md b/docs/src/index.md index 7b26eb1..ae88ca7 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -24,13 +24,13 @@ julia> ]add ModiaPlot_PyPlot # if plotting with PyPlot desired add ModiaPlot_CairoMakie # if plotting with CairoMakie desired ``` -Note, Modia reexports the following definitions +Note, Modia reexports the following definitions - `using Unitful` - `using DifferentialEquations` - and exports functions `CVODE_BDF` and `IDA` of [Sundials.jl](https://github.com/SciML/Sundials.jl). -As a result, it is usually sufficient to have `using Modia` in a model to utilize the relevant +As a result, it is usually sufficient to have `using Modia` in a model to utilize the relevant functionalities of these packages. @@ -38,30 +38,57 @@ functionalities of these packages. ### Version 0.9.0-dev +- New functions `hasParameter, getParameter, getEvaluatedParameter, showParameter, showEvaluatedParameter` to + get parameter/init/start values by name (e.g. `getEvaluatedParameter(instantiatedModel, "a.b.c")`) or + show all parameters. For details see the [function docu](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html). + +- Docu improved (e.g. links to utility functions documentation added) + + ** Bug fixes -- `signalNames(instantiatedModel)` did sometimes not show the signal names in the result (is now fixed). +- The initial state vector was not always correctly filled with start/init values of the model (is now fixed). +- `signalNames(instantiatedModel)` did sometimes not show the correct signal names available in the result (is now fixed). + + +**Non-backwards compatible changes** + +- Parameters are no longer seen as part of the result (since parameters can be complex internal datastructures, e.g. for Modia3D). + Therefore, they are no longer available in result access functions (`printResultInfo, signalNames, rawSignal, getPlotSignal, plot, ...`). + Instead, they can be accessed via new functions `hasParameter, parameter, evaluatedParameter, showParameter, showEvaluatedParameter`. + +- The result data structure is now constructed with `deepcopy(..)` of every involved result variable. + Previously, for some result variables just the variable reference was stored. + The effect is that if previously a complex internal data structure was incorporated into the result data structure, + then it was present just once. Now, a deepcopy of the data structure is stored at every time instant. + Note, a variable `v` (especially, a complex internal data structure) is not stored in the result if defined as + `v = Var(hideResult=true)`. + In some rare cases, `deepcopy(..)` gives an error (if module variables are, for whatever reason, tried to be copied). + Such variables `v` need to be declared with `v = Var(hideResult=true)`, in order that this error does not appear + (and these variables are then not stored in the result). + +- Internal constructor `SimulationModel(..)`: Unused argument x_startValues removed. ### Version 0.8.3 -- Bug fix: Parameters that are Numbers, but not AbstractFloats, and have no unit defined, +- Bug fix: Parameters that are Numbers, but not AbstractFloats, and have no unit defined, e.g. a Bool or an Int parameter, are no longer converted to FloatType in the generated Code. - + ### Version 0.8.2 - New exported functions - modelToJSON(model; expressionsAsStrings=true) - JSONToModel(json) - - writeModel(filename, model; log=true) + - writeModel(filename, model; log=true) - readModel(filename; log=true) writeModel saves the model in JSON format on file and readModel reads the model from a JSON file. - `Modia/examples/ServoSystem.jl` enhanced, so that the hierarchical model with units is first stored in JSON format on file, then the model is read from file, a parameter is modified, and then the model is passed to @instantiateModel(..). - + - `@instantiateModel(...)`: - `@instantiateModel(..., logCode=true, ...)` provides now correct unit type casts for scalars. - `@instantiateModel(..., saveCodeOnFile=fileName, ...)` stores the generated code on file `fileName`. @@ -78,8 +105,8 @@ functionalities of these packages. - Memory allocation reduced if states or tearing variables are SVectors. - Improved casting and checking of types in the generated code - (see new test model Modia/test/TestUnitAsString.jl). - + (see new test model Modia/test/TestUnitAsString.jl). + - Moved ModiaBase.Symbolic.makeDerVar from ModiaBase to new file `Modia/src/Symbolic.jl` (because makeDerVar needs FloatType for generating type-stable code and FloatType is available in Modia but not in ModiaBase). @@ -87,9 +114,9 @@ functionalities of these packages. **Bug fixes** -- Fixed issue with unit on macOS (exponents had been displayed as Unicode superscripts when converting +- Fixed issue with unit on macOS (exponents had been displayed as Unicode superscripts when converting the unit to a string, leading to errors in the further processing). - + - Hide result only if `Var(hideResult=true)` (previously, hideResult=false was treated as true). - `Modia/models/Rotational.jl`: Change some Int to Float64 values, because errors occured in some situations. @@ -99,7 +126,7 @@ functionalities of these packages. - Missing file Modia/test/TestLinearEquations.jl added. -### Version 0.8.0 +### Version 0.8.0 **Non-backwards** compatible changes @@ -116,14 +143,14 @@ Details of the changes: - ModiaLang#main 0.11.3 and ModiaLang#development merged into Modia 0.7.0 resulting in the new Modia version 0.8.0 (hereby history of both ModiaLang and of Modia is preserved). - + - Modia3D is removed from Modia (so when a model is using Modia3D, the package must be explicitly imported and is no longer automatically imported from Modia). - Require ModiaBase 0.10 (where EquationAndStateInfo.jl and StateSelection.jl are removed and added to Modia, in order that only references to Modia are in the generated code and no longer references to ModiaBase). - + ## Old Release Notes (until 28.2.2022) @@ -136,46 +163,46 @@ Details of the changes: - Equations can only be defined with key `equations` and no other key (still, expressions can be associated with one variable, such as `b = Var(:(2*a))`). In versions 0.6.0 and before, equations could be associated with any key. - -- The merge operator `|` appends the expression vectors of `equations`, so + +- The merge operator `|` appends the expression vectors of `equations`, so `m1 | m2` basically appends the vector of `m2.equations` to the vector of `m1.equations`. - In versions 0.6.0 and before, the merge operator did not handle `equations` specially, + In versions 0.6.0 and before, the merge operator did not handle `equations` specially, and therefore `m1 | m2` replaced `m1.equations` by `m2.equations`. -- Parameter values in the code are now type cast to the type of the parameter value from the +- Parameter values in the code are now type cast to the type of the parameter value from the `@instantiatedModel(..)` call. The benefit is that access of parameter values in the code is type stable and operations with the parameter value are more efficient and at run-time no memory is allocated. Existing models can no longer be simulated, if parameter values provided via `simulate!(.., merge=xx)` are not type compatible to their definition. For example, an error is thrown if the @instantedModel(..) uses a Float64 value and the `simulate!(.., merge=xx)` uses a `Measurement{Float64}` value for the same parameter - -- Operator `buildModia3D(..)` as used in Modia3D models is removed. Instead, the new constructor - `Model3D(..)` must be used at the top level of a Modia3D definition. It is now possible to define - several, independent multibody systems (currently, only one of them can have animation and animation export). - + +- Operator `buildModia3D(..)` as used in Modia3D models is removed. Instead, the new constructor + `Model3D(..)` must be used at the top level of a Modia3D definition. It is now possible to define + several, independent multibody systems (currently, only one of them can have animation and animation export). + - `Var(init=[...])` or `Var(start=[..])` of FreeMotion joints must be defined as `Var(init=SVector{3,Float64}(..))` or `Var(start=SVector{3,Float64}(..))`. - Otherwise, errors occur during compilation. + Otherwise, errors occur during compilation. + - Other changes - Documentation (especially tutorial) adapted to the new version. - Examples and test models (Modia/examples, Modia/tests) adapted to the new version, especially to the non-backwards compatible changes. - + - For further changes of equation-based models, see the release notes of [ModiaLang 0.11.0](https://github.com/ModiaSim/ModiaLang.jl/releases/tag/v0.11.0). - For further changes of Modia3D models, see the release notes of [Modia3D 0.9.0](https://github.com/ModiaSim/Modia3D.jl/releases/tag/v0.9.0). - + #### Version 0.6.1 This version was erronously released as 0.6.1. Since it contains non-backwards compatible changes with respect to 0.6.0, this is wrong and should have been released as version 0.7.0. -- See release notes of [ModiaLang](https://github.com/ModiaSim/ModiaLang.jl/releases/tag/v0.11.0) and +- See release notes of [ModiaLang](https://github.com/ModiaSim/ModiaLang.jl/releases/tag/v0.11.0) and of [Modia3D](https://github.com/ModiaSim/Modia3D.jl/releases/tag/v0.9.0). - Project.toml and Manifest.toml updated due to new versions of Modia3D and ModiaLang @@ -218,10 +245,10 @@ changes with respect to 0.6.0, this is wrong and should have been released as ve - @instantiateModel(..): `Var(hideResult=true)` is no longer ignored if present in a sub-component. -- simulate!(..): Unnecessary evaluation of the parameters dictionary is avoided +- simulate!(..): Unnecessary evaluation of the parameters dictionary is avoided (if merge = missing, nothing or has no elements). - + #### Version 0.11.2 - Minor (efficiency) improvement if states are SVectors. @@ -238,37 +265,37 @@ changes with respect to 0.6.0, this is wrong and should have been released as ve #### Version 0.11.0 - + Non-backwards compatible changes -- Equations can only be defined with key `equations` and no other key. +- Equations can only be defined with key `equations` and no other key. -- Parameter values in the code are now type cast to the type of the parameter value from the +- Parameter values in the code are now type cast to the type of the parameter value from the `@instantiatedModel(..)` call. The benefit is that access of parameter values in the code is type stable and operations with the parameter value are more efficient and at run-time no memory is allocated. Existing models can no longer be simulated, if parameter values provided via `simulate!(.., merge=xx)` are not type compatible to their definition. For example, an error is thrown if the @instantedModel(..) uses a Float64 value and the `simulate!(.., merge=xx)` uses a `Measurement{Float64}` value for the same parameter - + Other changes -- Hierarchical names in function calls supported (e.g. `a.b.c.fc(..)`). +- Hierarchical names in function calls supported (e.g. `a.b.c.fc(..)`). - Functions can return multiple values, e.g. `(tau1,tau2) = generalizedForces(derw1, derw2)`. - Support for StaticArrays variables (the StaticArrays feature is kept in the generated AST). For an example, see `ModiaLang/test/TestArrays.jl`. - + - Support for Array variables (especially of state and tearing variables) where the dimension can change after `@instantiateModel(..)`. For examples, see `ModiaLang/test/TestArrays.jl` and `TestMultiReturningFunction10.jl`. - + - New keyword `Var(hideResult=true)` removes variable from the result (has no effect on states, derivative of states and parameters). For an example, see `ModiaLang/test/TestMultiReturningFunction10.jl` - New feature of @instantiatedModel(..): If a Model(..) has key `:_buildFunction`, call this function to merge additional code to the model. For details see the docu of function buildSubModels! in ModiaLang.jl. - For examples, see `ModiaLang/test/TestMultiReturningFunction10.jl` and + For examples, see `ModiaLang/test/TestMultiReturningFunction10.jl` and constructor `Model3D(..)` in `Modia3D/src/ModiaInterface/model3D.jl` and `Modia3D/src/ModiaInterface/buildModia3D.jl`. - Generalized connection semantics. @@ -279,27 +306,27 @@ Other changes - New option `logProgress=false` in function `simulate!(..)` to print current simulation time every 5s (cpu-time). - If tolerance is too small, a warning is prented and it is automatically enlarged to a meaningful value (e.g. tolerance = 1e-8 is not useful if `FloatType=Float32`) - - Logging improved: If log=true or logTiming=true, then timing, memory allocation and compilation time is - reported for initialization (ths includes compilation of the generated getDerivatives(..) function). - The remaining log shows cpu-time and memory allocation **without** initialization + - Logging improved: If log=true or logTiming=true, then timing, memory allocation and compilation time is + reported for initialization (ths includes compilation of the generated getDerivatives(..) function). + The remaining log shows cpu-time and memory allocation **without** initialization (and without the resources needed to compile getDerivatives(..)). - Prefix messages of the timers with "ModiaLang" or "DifferentialEquations" to more clearly see the origin of a message in the timer log. -- Large speedup of symbolic transformation, if function depends on many input (and output) arguments +- Large speedup of symbolic transformation, if function depends on many input (and output) arguments (includes new operator `implicitDependency(..)`). - Included DAE-Mode in solution of linear equation system (if DAE integrator is used and all unknowns of a linear equation system are part of the DAE states, solve the linear equation system during continuous integration - via DAE solver (= usually large simulation speed-up, for larger linear equation systems) - + via DAE solver (= usually large simulation speed-up, for larger linear equation systems) + Bug fixes - If unitless=true, units in instantiatedModel.evaluatedParameters are removed. - The unit macro is kept in the generated code and is no longer expanded. For example, `u"N"`, is kept in the code that is displayed with `logCode=true` (previously, this was expanded and the unit was displayed in the code as `N` which is not correct Julia code). - + - Function `ModiaLang.firstInitialOfAllSegments(..)` now correctly returns true for the first call of the getDerivatives function during the simulation. @@ -358,11 +385,11 @@ Bug fixes #### Version 0.8.5 -- simulate!(..): +- simulate!(..): - Trigger an error, if simulation is not successful (retcode is neither :Default nor :Success nor :Terminate) - Use RightRootFind for zero crossings (improves state events based on new DifferentialEquations option) - New keyword argument requiredFinalStates_atol=0.0. - - Improve docu (e.g. add return argument solution). + - Improve docu (e.g. add return argument solution). - Show correct integrator name QBDF in simulation log (instead of QNDF) - Raise an error, if (relative) tolerance is too small for FloatType - Use FloatType for zero crossing hysteresis, instead of Float64 @@ -371,7 +398,7 @@ Bug fixes - Support of MonteCarloMeasurements with units + new test model TestLinearEquationSystemWithUnitsAndMonteCarlo.jl - Fixing and activating the deactivated test TestTwoInertiasAndIdealGearWithUnitsAndMonteCarlo.jl. - + #### Version 0.8.4 @@ -400,19 +427,19 @@ Bug fixes (previously, the generated code for unitless=false was wrong, if the tearing variable was a derivative, since the unit was not taken into account). -- simulate!(..): +- simulate!(..): - Support DAE integrators, especially IDA() from Sundials. - New keyword `useRecursiveFactorizationUptoSize=0`: Linear equation systems A*v=b are solved with - [RecursiveFactorization.jl](https://github.com/YingboMa/RecursiveFactorization.jl) instead of + [RecursiveFactorization.jl](https://github.com/YingboMa/RecursiveFactorization.jl) instead of the default `lu!(..)` and `ldiv!(..)`, if `length(v) <= useRecursiveFactorizationUptoSize`. According to `RecursiveFactorization.jl` docu, it is faster as `lu!(..)` with OpenBLAS, - for `length(v) <= 500` (typically, more as a factor of two). + for `length(v) <= 500` (typically, more as a factor of two). Since there had been some cases where `lu!(..)!` was successful, but `RecursiveFactorization.jl` failed due to a singular system, the default is to use `lu!(..)!`. - - If log=true, sizes of linear equation systems are listed, as well as whether + - If log=true, sizes of linear equation systems are listed, as well as whether RecursiveFactorization.jl is used for the respective system. - + - Test for RecursiveFactorization.jl added in TestTwoInertiasAndIdealGear.jl - Some test models corrected (since leading to errors with the above changes). @@ -443,12 +470,12 @@ Bug fixes - New small model libraries Translational.jl and PathPlanning.jl added. - Result storage changed: `sol = simulate!(...)` calls internally `sol = solve(..)` from DifferentialEquations.jl. `sol` contains time and the states at the communication time grid and at events. This is now kept in simulate(..), so the return value of simulate!(..) can be exactly used as if `solve(..)` would have been used directly. -- The plot(..) command now supports the following underlying plot packages: +- The plot(..) command now supports the following underlying plot packages: [PyPlot](https://github.com/JuliaPy/PyPlot.jl), [GLMakie](https://github.com/JuliaPlots/GLMakie.jl), [WGLMakie](https://github.com/JuliaPlots/WGLMakie.jl), and [CairoMakie](https://github.com/JuliaPlots/CairoMakie.jl). - It is also possible to select `NoPlot`, to ignore `plot(..)` calls + It is also possible to select `NoPlot`, to ignore `plot(..)` calls or `SilenNoPlot` to ignore `plot(..)` calls silently. The latter is useful for `runtests.jl`. Note, often [PyPlot](https://github.com/JuliaPy/PyPlot.jl) is the best choice. @@ -456,12 +483,12 @@ Changes that are **not backwards compatible** to version 0.7.x: - Models are OrderedDicts and no longer NamedTuples. -- simulate!(..): +- simulate!(..): - If FloatType=Float64 and no algorithm is defined, then Sundials.CVODE\_BDF() is used instead of the default algorithm of DifferentialEquations as in 0.7. The reason is that Modia models are usually large and expensive to evaluate and have often stiff parts, so that multi-step methods are often by far the best choice. CVODE_BDF() seems to be a good choice in many applications - (another algorithm should be used, if there are many events, highly oscillatory vibrations, or if all states are non-stiff). + (another algorithm should be used, if there are many events, highly oscillatory vibrations, or if all states are non-stiff). - The default value of `stopTime` is equal to `startTime` (which has a default value of 0.0 s), and is no longer 1.0 s. - Plotting is defined slightly differently (`@useModiaPlot`, instead of `using ModiaPlot`). @@ -482,7 +509,7 @@ Changes that are **not backwards compatible** to version 0.7.x: #### Version 0.7.1 - Variable constructor `Var(...)` introduced. For example: - `v = input | Var(init = 1.2u"m")`. + `v = input | Var(init = 1.2u"m")`. - Functions are called in the scope where macro `@instantiateModel` is called. @@ -511,4 +538,3 @@ Changes that are **not backwards compatible** to version 0.7.x: - [Martin Otter](https://rmc.dlr.de/sr/en/staff/martin.otter/), [DLR - Institute of System Dynamics and Control](https://www.dlr.de/sr/en). - \ No newline at end of file diff --git a/docs/src/tutorial/Simulation.md b/docs/src/tutorial/Simulation.md index b1896e8..f145cb5 100644 --- a/docs/src/tutorial/Simulation.md +++ b/docs/src/tutorial/Simulation.md @@ -85,7 +85,7 @@ used on the return argument `sol` of `simulate!`. ## 3.4 Plotting A short overview of the most important plot commands is given in -section [Results and Plotting](@ref) +section [Plotting](@ref) ## 3.5 State selection (DAEs) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index b5cc773..4e2dad1 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -354,18 +354,21 @@ mutable struct SimulationModel{FloatType,TimeType} evaluatedParameters::OrderedDict{Symbol,Any} nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) nextPre::AbstractVector - nextHold::AbstractVector - - x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element equationInfo.x_info[equationInfo.nx_infoFixed+i] + nextHold::AbstractVector + + x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element + # equationInfo.x_info[equationInfo.nx_infoFixed+i:equationInfo.nx_infoVisible] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) der_x_visible::Vector{FloatType} # Derivatives of states x or x_init that correspond to visible states + # This vector is filled with derivatives of visible states with appendVariable!(m.der_x_visible, ...) calls, + # including derivatives of x_vec[i] x_hidden::Vector{FloatType} # A copy of the states x that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) der_x_hidden::Vector{FloatType} # Derivatives of states x or x_init that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) der_x_full::Vector{FloatType} # Derivatives of states x (needed in DAE mode) - function SimulationModel{FloatType,TimeType}(modelModule, modelName, buildDict, getDerivatives!, equationInfo, x_startValues, + function SimulationModel{FloatType,TimeType}(modelModule, modelName, buildDict, getDerivatives!, equationInfo, previousVars, preVars, holdVars, parameterDefinition, variableNames; unitless::Bool=true, @@ -438,12 +441,12 @@ mutable struct SimulationModel{FloatType,TimeType} obj.nextPre = deepcopy(pre) obj.nextHold = deepcopy(hold) - obj.x_start = updateEquationInfo!(equationInfo, FloatType) + obj.x_start = initialStateVector!(equationInfo, FloatType) nx = length(obj.x_start) nxHidden = nx-equationInfo.nxVisible - + # Provide storage for x_vec and utility vectors - obj.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_infoFixed+1:length(equationInfo.nx_infoVisible)] + obj.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_infoFixed+1:equationInfo.nx_infoVisible] obj.x_init = zeros(FloatType,nx) obj.der_x_visible = zeros(FloatType,equationInfo.nxVisible) obj.x_hidden = zeros(FloatType, nxHidden) @@ -506,8 +509,9 @@ mutable struct SimulationModel{FloatType,TimeType} success = false nx = m.equationInfo.nx - new(m.modelModule, m.modelName, deepcopy(m.buildDict), TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), m.options, m.getDerivatives!, m.equationInfo, linearEquations, - eventHandler, + new(m.modelModule, m.modelName, deepcopy(m.buildDict), TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), deepcopy(m.options), m.getDerivatives!, + deepcopy(m.equationInfo), deepcopy(linearEquations), + deepcopy(eventHandler), m.vSolvedWithInitValuesAndUnit, deepcopy(m.previous), m.previous_names, m.previous_dict, deepcopy(m.pre), m.pre_names, m.pre_dict, @@ -517,7 +521,7 @@ mutable struct SimulationModel{FloatType,TimeType} odeIntegrator, daeCopyInfo, addEventPointsDueToDEBug, success, m.unitless, m.result_info, Tuple[], missing, Vector{FloatType}[], deepcopy(m.parameters), deepcopy(m.evaluatedParameters), - deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), + deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), zeros(FloatType,0), deepcopy(m.x_vec), convert(Vector{FloatType}, m.x_start), zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), zeros(FloatType,nx)) @@ -557,37 +561,37 @@ function get_xinfo(m::SimulationModel, x_index::Int)::Tuple{Int, Int, String} return (ibeg, iend, xinfo.unit) end -export copyState! """ - copyState!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, xi::Vector{FloatType}) + copyFromHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{FloatType}) -Copy state of m.equationInfo.x_info[x_infoIndex] from m.x_hidden into pre-allocated vector xi. +Copy state from `m` at index `x_hidden_startIndex` into pre-allocated vector `xi`. """ -function copyState!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} - @assert(length(xi) == m.equationInfo.x_info[x_infoIndex].length) - startIndex = m.equationInfo.x_info[x_infoIndex].startIndex - m.equationInfo.nxVisible - 1 - for i = 1:length(xi) - xi[i] = m.x_hidden[startIndex+i] - end +@inline function copyFromHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} + copyto!(xi, 1, m.x_hidden, x_hidden_startIndex, length(xi)) return nothing end """ - set_hiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, der_x::Vector{FloatType}) + scalar_x_hidden = getScalarHiddenState(m::SimulationModel, x_hidden_startIndex::Int) -Copy hidden state derivative der_x of m.equationInfo.x_info[x_infoIndex] into m.der_x_hidden. +Return scalar hidden state scalar_x_hidden = m.x_hidden[x_hidden_startIndex]. """ -function set_hiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_infoIndex::Int, der_x::Vector{FloatType})::Nothing where {FloatType,TimeType} - ix_info = m.equationInfo.x_info[x_infoIndex] - @assert(length(der_x) == ix_info.length) - #println("set_hiddenStateDerivative!: x_index = $x_index, der_x = $der_x") - startIndex = ix_info.startIndex - m.equationInfo.nxVisible - 1 - for i = 1:length(der_x) - m.der_x_hidden[startIndex+i] = der_x[i] - end - #println("m.der_x_hidden = ", m.der_x_hidden) +getScalarHiddenState(m::SimulationModel, x_hidden_startIndex::Int) = m.x_hidden[x_hidden_startIndex] + + +""" + copyToHiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, der_x::Union{FloatType,Vector{FloatType}}) + +Copy hidden state derivative `der_x` into `m` starting at index `x_hidden_startIndex`. +""" +@inline function copyToHiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, der_x::FloatType)::Nothing where {FloatType,TimeType} + m.der_x_hidden[x_hidden_startIndex] = der_x + return nothing +end +@inline function copyToHiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, der_x::Vector{FloatType})::Nothing where {FloatType,TimeType} + copyto!(m.der_x_hidden, x_hidden_startIndex, der_x, 1, length(der_x)) return nothing end @@ -741,20 +745,22 @@ end """ - get_lastValue(model::SimulationModel, name::String; unit=true) + getLastValue(model::SimulationModel, name::String; unit=true) Return the last stored value of variable `name` from `model`. If `unit=true` return the value with its unit, otherwise with stripped unit. If `name` is not known or no result values yet available, an info message is printed and the function returns `nothing`. + +`name` can be a time-varying variable or a parameter. """ -function get_lastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit::Bool=true) where {FloatType,TimeType} +function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit::Bool=true) where {FloatType,TimeType} if haskey(m.result_info, name) # Time varying variable stored in m.result_xxx resInfo = m.result_info[name] if ismissing(m.result_x) || length(m.result_x.t) == 0 - @info "get_lastValue(model,\"$name\"): No results yet available." + @info "getLastValue(model,\"$name\"): No results yet available." return nothing end @@ -795,7 +801,7 @@ function get_lastValue(m::SimulationModel{FloatType,TimeType}, name::String; uni value = convert(FloatType, 0) else - error("Bug in get_lastValue(...), name = $name, resInfo.store = $resInfo.store.") + error("Bug in getLastValue(...), name = $name, resInfo.store = $resInfo.store.") end if resInfo.negate @@ -806,13 +812,14 @@ function get_lastValue(m::SimulationModel{FloatType,TimeType}, name::String; uni # Parameter stored in m.evaluatedParameters value = get_value(m.evaluatedParameters, name) if ismissing(value) - @info "get_lastValue: $name is not known and is ignored." + @info "getLastValue: $name is not known and is ignored." return nothing; end end return value end +get_lastValue(m, name; unit=true) = getLastValue(m, name, unit=unit) """ @@ -1062,35 +1069,33 @@ get_xe(x, xe_info) = xe_info.length == 1 ? x[xe_info.startIndex] : x[xe_info.sta #end import Printf -invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing = TimerOutputs.@timeit m.timer "Modia getDerivatives!" begin - if m.options.logProgress && m.cpuLast != UInt64(0) - cpuNew = time_ns() - if (cpuNew - m.cpuLast) * 1e-9 > 5.0 - m.cpuLast = cpuNew - Printf.@printf(" progress: integrated up to time = %.3g s (in cpu-time = %.3g s)\n", t, (cpuNew-m.cpuFirst)*1e-9) +function invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing + TimerOutputs.@timeit m.timer "Modia getDerivatives!" begin + if m.options.logProgress && m.cpuLast != UInt64(0) + cpuNew = time_ns() + if (cpuNew - m.cpuLast) * 1e-9 > 5.0 + m.cpuLast = cpuNew + Printf.@printf(" progress: integrated up to time = %.3g s (in cpu-time = %.3g s)\n", t, (cpuNew-m.cpuFirst)*1e-9) + end end - end - if length(m.x_vec) > 0 - # copy vector-valued x-elements from x to m.x_vec - eqInfo = m.equationInfo - x_vec = m.x_vec - j = 0 - for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible - j += 1 - xe = eqInfo.x_info[i] - x_vec[j] .= x[xe.startIndex:(xe.startIndex+xe.length-1)] + if length(m.x_vec) > 0 + # copy vector-valued x-elements from x to m.x_vec + eqInfo = m.equationInfo + x_vec = m.x_vec + j = 1 + for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible + xe = eqInfo.x_info[i] + copyto!(x_vec[j], 1, x, xe.startIndex, xe.length) + j += 1 + end end - end - empty!(m.der_x_visible) - j::Int = 0 - for i in m.equationInfo.nxVisible+1:length(x) - j += 1 - m.x_hidden[j] = x[i] - end - m.der_x_hidden .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 - Base.invokelatest(m.getDerivatives!, x, m, t) + copyto!(m.x_hidden, 1, x, m.equationInfo.nxVisible+1, m.equationInfo.nxHidden) + empty!(m.der_x_visible) + m.der_x_hidden .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 + Base.invokelatest(m.getDerivatives!, x, m, t) - @assert(length(m.der_x_visible) + length(m.der_x_hidden) == length(x)) + @assert(length(m.der_x_visible) + length(m.der_x_hidden) == length(x)) + end return nothing end @@ -1124,15 +1129,15 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters if length(m.options.merge) > 0 + removeHiddenStates!(m.equationInfo) + removeHiddenCrossingFunctions!(m.eventHandler) m.parameters = mergeModels(m.parameters, m.options.merge) evaluatedParameters = propagateEvaluateAndInstantiate!(m) if isnothing(evaluatedParameters) return false end m.evaluatedParameters = evaluatedParameters - - # Resize state vector memory - m.x_start = updateEquationInfo!(m.equationInfo, FloatType) + m.x_start = initialStateVector!(m.equationInfo, FloatType) nx = length(m.x_start) nxHidden = nx - m.equationInfo.nxVisible resize!(m.x_init, nx) @@ -1226,7 +1231,7 @@ function check_vSolvedWithInitValuesAndUnit(m::SimulationModel)::Bool tolerance = m.options.tolerance for (name, valueBefore) in m.vSolvedWithInitValuesAndUnit - valueAfterInit = get_lastValue(m, name, unit=false) + valueAfterInit = getLastValue(m, name, unit=false) valueBeforeInit = stripUnit.(valueBefore) if !isnothing(valueAfterInit) && abs(valueBeforeInit - valueAfterInit) >= max(abs(valueBeforeInit),abs(valueAfterInit),0.01*tolerance)*tolerance push!(names, name) @@ -1350,16 +1355,9 @@ Copy der_x_visible and der_x_hidden to der_x (der_x .= [der_x_visible, der_x_hid if length(der_x_hidden) == 0 der_x .= der_x_visible else - @inbounds begin - @assert(length(der_x) == length(der_x_visible) + length(der_x_hidden)) - for i = 1:length(der_x_visible) - der_x[i] = der_x_visible[i] - end - istart = length(der_x_visible) - for i = 1:length(der_x_hidden) - der_x[istart+i] = der_x_hidden[i] - end - end + @assert(length(der_x) == length(der_x_visible) + length(der_x_hidden)) + unsafe_copyto!(der_x, 1, der_x_visible, 1, length(der_x_visible)) + unsafe_copyto!(der_x, length(der_x_visible)+1, der_x_hidden, 1, length(der_x_hidden)) end return nothing end @@ -1373,6 +1371,7 @@ DifferentialEquations callback function to get the derivatives. function derivatives!(der_x, x, m, t) m.nf += 1 invokelatest_getDerivatives_without_der_x!(x, m, t) + #println("t = $t, m.der_x_hidden = ", m.der_x_hidden) copyDerivatives!(der_x, m.der_x_visible, m.der_x_hidden) return nothing end @@ -1522,9 +1521,7 @@ function zeroCrossings!(z, x, t, integrator)::Nothing invokelatest_getDerivatives_without_der_x!(x, m, t) m.solve_leq = true eh.crossing = false - for i = 1:eh.nz - z[i] = eh.z[i] - end + copyto!(z, eh.z) #println("... t = $t, z = $z") #println("... time = ", t, ", z = ", z) return nothing diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 5e1ec5b..139a98e 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -17,11 +17,7 @@ export ResidualCategory, FD, FC_ALG, FC_LOW_HIGH, FC_MUE export LinearEquations -export EquationInfo, StateElementInfo, update_equationInfo!, get_stateNames, get_x_table -export initialStateVector, updateEquationInfo! - -export EquationInfoStatus, MANUAL, CODE_GENERATION, SOLVER_MODEL - +export EquationInfo, StateElementInfo, get_stateNames, get_x_table """ @@ -159,7 +155,7 @@ mutable struct LinearEquations{FloatType <: Real} @assert(length(x_names) > 0) @assert(length(x_names) == length(x_lengths)) nx = sum(x_lengths) - @assert(nx > 0) + @assert(nx >= 0) useRecursiveFactorization = nx <= useRecursiveFactorizationUptoSize # Allocate value storage for vector elements @@ -507,47 +503,13 @@ function LinearEquationsIteration!(leq::LinearEquations{FloatType}, isInitial::B end - -""" - @enum EquationInfoStatus - -Status of an EquationInfo instance: - -- `MANUAL`: Is defined manually. The following variables in x_info::Vector{StateElementInfo} - are **not** defined: - x_names_julia, der_x_names_julia, length, unit, startIndex, nx. - With function [`update_equationInfo!`](@ref), the variables length, unit, startIndex - in x_info::Vector{StateElementInfo} are computed, as well as nx. - -- `CODE_GENERATION`: Is constructed during code generation with getSortedAndSolvedAST(..). - The following variables in x_info::Vector{StateElementInfo} - are **not** defined: startIndex, nx. - With function [`update_equationInfo!`](@ref), the variables startIndex - in x_info::Vector{StateElementInfo} are computed, as well as nx. - -- `SOLVER_MODEL`: Is used during simulation in a SolverModel. With function - [`update_equationInfo!`](@ref), missing variables are constructed depending - on the information given with `MANUAL` or `CODE_GENERATION` and the actual - modelValues instance (here unit and length information is available). -""" -@enum EquationInfoStatus MANUAL=1 CODE_GENERATION SOLVER_MODEL - - - """ - xe_info = StateElementInfo(...) + xe_info = StateElementInfo(x_name, x_name_julia, der_x_name, der_x_name_julia, + stateCategory, unit, startOrInit, fixed, nominal, unbounded; + startIndex=-1) Return an instance of the mutable struct `StateElementInfo` that defines the information -for one element of the state vector. There are three constructors: - -- Default constructor (all variables under section Arguments are given; - used to write/read the complete information). - -- All variables under section Arguments are given with exception of startIndex - (used for `EquationInfoStatus = CODE_GENERATION`). - -- StateElementInfo(x_name, der_x_name, stateCategory; fixed=nothing, nominal=NaN, unbounded=false) - (used for `EquationInfoStatus = MANUAL`): +for one element of the state vector. # Arguments - x_name: Name of x-element or "" if no name (if stateCatebory = XLAMBDA or XMUE) @@ -558,17 +520,16 @@ for one element of the state vector. There are three constructors: - der_x_name_julia: Julia name of der_x-element in getDerivatives!/getResiduals! function or "" if not needed (since no code generation). - stateCategory::StateCategory: Category of the state -- length: length of x-element (or -1 if not yet known) - unit: unit of XD, XALG (x_name) or XLAMBDA, XMUE (der_x_name) or "" if not yet known) +- startOrInit: Start or init value (scalar or vector) - fixed: false (= guess value) or true (= not changed by initialization). Only relevant for ode=false, otherwise ignored. -- nominal: Nominal value (NaN if determined via start value) +- nominal: Nominal value (NaN if determined via startOrInit value) - unbounded: false or true -- startIndex: start index of x-element with respect to x-vector - or -1 if not yet known. +- startIndex: = -1, if not yet known. If hidden state, startIndex with respect to x_hidden. """ mutable struct StateElementInfo - x_name::String # Modia name of x-element or "" if no name (for ) + x_name::String # Modia name of x-element or "" if no name x_name_julia # Julia name of x-element in getDerivatives! function # or "", if not needed (since no code generation). der_x_name::String # Modia name of der_x-element or "" if either "der(x_name)" or if no name, @@ -587,32 +548,23 @@ mutable struct StateElementInfo # = false, if length of value is determined before initialization scalar::Bool # = true, if scalar # = false, if vector - length::Int # length of x-element - startIndex::Int # start index of element with respect to x-vector (if fixedLength=true) - # or with respect to x_vec-vector (if fixedLength=false) + length::Int # length of x-element or -1 if not yet known + startIndex::Int # start index of state with respect to x-vector or -1 if not yet known + x_hidden_startIndex::Int # start index of hidden state with respect to x_hidden vector + # or -1, if it is no hidden state (for a hidden state, x_hidden_startIndex + # is consistently set when it is added via addHiddenState(..)). end # Constructor for code-generation StateElementInfo(x_name, x_name_julia, der_x_name, der_x_name_julia, - stateCategory, unit, startOrInit, fixed, nominal, unbounded) = StateElementInfo( + stateCategory, unit, startOrInit, fixed, nominal, unbounded; + startIndex = -1, x_hidden_startIndex=-1) = StateElementInfo( x_name, x_name_julia, der_x_name, der_x_name_julia, - stateCategory, unit, startOrInit, fixed, nominal, unbounded, + stateCategory, unit, deepcopy(startOrInit), fixed, nominal, unbounded, isFixedLengthStartOrInit(startOrInit, x_name), !(startOrInit isa AbstractArray), - startOrInit isa Nothing ? 1 : length(startOrInit), -1) - - -# Constructor for reading StateElementInfo after code-generation (x_name_julia and der_x_name_julia are not included -#StateElementInfo(x_name, der_x_name, -# stateCategory, unit, startOrInit, fixed, nominal, unbounded) = StateElementInfo( -# x_name, :(), der_x_name, :(), -# stateCategory, unit, startOrInit, fixed, nominal, unbounded, -1) - -# Constructor for manually generated equation info. -#StateElementInfo(x_name, der_x_name, stateCategory=XD; fixed=false, nominal=NaN, unbounded=false) = -# StateElementInfo(x_name, :(), der_x_name, :(), stateCategory, "", nothing, fixed, nominal, unbounded, -1) - + startOrInit isa Nothing ? 1 : length(startOrInit), startIndex, x_hidden_startIndex) function Base.show(io::IO, xe_info::StateElementInfo) print(io, "Modia.StateElementInfo(") @@ -634,6 +586,7 @@ function Base.show(io::IO, xe_info::StateElementInfo) print(io, ",", xe_info.scalar) print(io, ",", xe_info.length) print(io, ",", xe_info.startIndex) + print(io, ",", xe_info.x_hidden_startIndex) print(io, ")") return nothing end @@ -660,116 +613,94 @@ function get_x_table(x_info::Vector{StateElementInfo}) end -""" - nx = stateVectorLength(x_info::Vector{StateElementInfo}) - -Return the length of the state vector -""" -function stateVectorLength(x_info::Vector{StateElementInfo})::Int - nx = 0 - for xe_info in x_info - nx += xe_info.length - end - return nx -end - - +@enum EquationInfoStatus EquationInfo_Instantiated EquationInfo_Initialized_Before_Code_Generation EquationInfo_After_All_States_Are_Known """ - eqInfo = EquationInfo(; - status = MANUAL, - ode = true, - nz = 0, - x_info = StateElementInfo[], - nx = -1, - nx_infoFixed = -1, - residualCategories = ResidualCategory[], - linearEquations = Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}[], - vSolvedWithFixedTrue = String[], - defaultParameterAndStartValues = nothing, - ResultType = nothing, - ResultTypeHasFloatType = false) - -Return instance `eqInfo` that defines the information for the equation system. + eqInfo = EquationInfo() -# Arguments -- status::EquationInfoStatus: Defines the variables that have a value. -- ode: = true if ODE-interface (`getDerivatives!`), - = false if DAE-interface (`getResiduals!`). -- nz: Number of zero crossing functions. -- x_info: Vector of StateElementInfo elements provding info for every x-element -- residualCategories: If ode=true, length(residualCategories) = 0. - If ode=false: residualCategories[i] is the `ResidualCategory`](@ref) of x-element "i". -- `linearEquations::Vector{Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}}`: - linearEquations[i] defines a - Modia.LinearEquations system, where the first tuple value - is a vector of the names of the unknowns, - the second tuple value is a vector of the Julia names of the vector-valued elements, - the third tuple value is a vector with the lengths of the unknowns, - the fourth tuple value is the number of residuals and the fifth tuple value - defines whether the coefficient matrix A - has only constant entries (=true) or not (=false). -- `vSolvedWithFixedTrue::Vector{String}`: Vector of variables that are computed - from other variables and have `fixed=true`. During initialization - it is checked whether the calculated values and the start values of - these variables agree. If this is not the case, an error is triggered. -- `defaultParameterAndStartValues`: Dictionary of default paramter and default start values. -- `ResultType::AbstractModelValues`: ModelValues type that shall be used for the result generation - (= ModelValues struct without parameters). -- `ResultTypeHasFloatType::Bool`: = false, if `ResultType` is not parameterized. - = true, if `ResultType` has parameter `FloatType`. +Return initial instance `eqInfo` that defines the information for the model equations +(especially, states and linear equation systems). """ mutable struct EquationInfo - status::EquationInfoStatus - ode::Bool # = true if ODE model interface, otherwise DAE model interface + status::EquationInfoStatus # Defines which information is consistent in EquationInfo + ode::Bool # = true if ODE-interface (`getDerivatives!`), + # = false if DAE-interface (`getResiduals!`). nz::Int # Number of crossing functions - x_info::Vector{StateElementInfo} + x_info::Vector{StateElementInfo} # Vector of StateElementInfo elements provding info for every x-element residualCategories::Vector{ResidualCategory} # If ode=true, length(residualCategories) = 0 # If ode=false, residualCategories[j] is the ResidualCategory of residual[j] linearEquations::Vector{Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}} - vSolvedWithFixedTrue::Vector{String} + # linearEquations[i] defines a + # Modia.LinearEquations system, where the first tuple value + # is a vector of the names of the unknowns, + # the second tuple value is a vector of the Julia names of the vector-valued elements, + # the third tuple value is a vector with the lengths of the unknowns, + # the fourth tuple value is the number of residuals and the fifth tuple value + # defines whether the coefficient matrix A + # has only constant entries (=true) or not (=false). + vSolvedWithFixedTrue::Vector{String} # Vector of variables that are computed + # from other variables and have `fixed=true`. During initialization + # it is checked whether the calculated values and the start values of + # these variables agree. If this is not the case, an error is triggered. nx::Int # = length(x) or -1 if not yet known + # This variable is updated once all states are known. nxVisible::Int # = number of visible x-elements (so x[1:nxVisible] are visible states) or -1 if not yet known + # This variable is updated once all states are known. + nxHidden::Int # = number of hidden x-elements (x[nxVisible+1:nxVisible+nxHidden]. + # This variable is always updated consistently via function addHiddenState!(..) + # (nxHidden=0, if there are no hidden states yet). nx_infoFixed::Int # x_info[1:nx_infoFixed] are states with fixed length (does not change after compilation) or -1 if not yet known nx_infoVisible::Int # x_info[1:nx_infoVisible] are states that are visible in getDerivatives!(..) or -1 if not yet known # x_info[nx_infoVisible+1:end] are states defined in functions that are not visible in getDerivatives!(..) #x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] # # or empty vector, if not yet known. - x_dict::OrderedCollections.OrderedDict{String,Int} # x_dict[x_name] returns the index of x_name with respect to x_info - der_x_dict::OrderedCollections.OrderedDict{String,Int} # der_x_dict[der_x_name] returns the index of der_x_name with respect to x_info - defaultParameterAndStartValues::Union{AbstractDict,Nothing} - ResultType - ResultTypeHasFloatType::Bool + x_dict::OrderedCollections.OrderedDict{String,Int} # x_dict[x_name] returns the index of x_name with respect to x_info + der_x_dict::OrderedCollections.OrderedDict{String,Int} # der_x_dict[der_x_name] returns the index of der_x_name with respect to x_info + defaultParameterAndStartValues::Union{AbstractDict,Nothing} # Dictionary of default parameter and default start values. + + function EquationInfo() + ode = true + nz = 0 + x_info = StateElementInfo[] + residualCategories = ResidualCategory[] + linearEquations = Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}[] + vSolvedWithFixedTrue = String[] + nx = -1 + nxVisible = -1 + nxHidden = 0 + nx_infoFixed = -1 + nx_infoVisible = -1 + x_dict = OrderedCollections.OrderedDict{String,Int}() + der_x_dict = OrderedCollections.OrderedDict{String,Int}() + defaultParameterAndStartValues = nothing + new(EquationInfo_Instantiated, ode, nz, x_info, residualCategories, linearEquations, vSolvedWithFixedTrue, + nx, nxVisible, nxHidden, nx_infoFixed, nx_infoVisible, x_dict, der_x_dict, + defaultParameterAndStartValues) + end end -EquationInfo(; status = MANUAL, - ode = true, - nz = 0, - x_info = StateElementInfo[], - residualCategories = ResidualCategory[], - linearEquations = Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}[], - vSolvedWithFixedTrue = String[], - nx_infoFixed = -1, - nx_infoVisible = -1, - defaultParameterAndStartValues::Union{AbstractDict,Nothing} = nothing, - ResultType = nothing, - ResultTypeHasFloatType = false) = EquationInfo(status, ode, nz, x_info, - residualCategories, linearEquations, - vSolvedWithFixedTrue, -1, -1, - nx_infoFixed, nx_infoVisible, - OrderedCollections.OrderedDict{String,Int}(), - OrderedCollections.OrderedDict{String,Int}(), - defaultParameterAndStartValues, - ResultType, ResultTypeHasFloatType) +""" + initEquationInfo!(eqInfo::EquationInfo, nx_infoFixed) +Initialize `eqInfo` before code generation. +`nx_infoFixed` are the number of states with fixed length (do not change after compilation). -""" - initEquationInfo!(eqInfo::EquationInfo) +The following variables get a consistent value: + +``` +eqInfo.x_dict[x_name] = ..., +eqInfo.der_x_dict[der_x_name] = ..., +eqInfo.nx, eqInfo.nxVisible, +eqInfo.nx_infoFixed, eqInfo.nx_infoVisible, +eqInfo.x_info[:].startIndex. +``` -Set eqInfo.x_dict, eqInfo.der_x_dict, eqInfo.nx and eqInfo.x_info[:].startIndex +This function must be called before hidden states are set (eqInfo.nxHidden=0). """ -function initEquationInfo!(eqInfo::EquationInfo)::Nothing +function initEquationInfo!(eqInfo::EquationInfo, nx_infoFixed::Int)::Nothing + @assert(eqInfo.status == EquationInfo_Instantiated) + @assert(eqInfo.nxHidden == 0) x_dict = eqInfo.x_dict der_x_dict = eqInfo.der_x_dict startIndex = 1 @@ -781,33 +712,55 @@ function initEquationInfo!(eqInfo::EquationInfo)::Nothing end eqInfo.nx = startIndex - 1 eqInfo.nxVisible = eqInfo.nx + eqInfo.nx_infoFixed = nx_infoFixed eqInfo.nx_infoVisible = length(eqInfo.x_info) + + eqInfo.status = EquationInfo_Initialized_Before_Code_Generation return nothing end """ - x_init = initialStateVector(eqInfo::EquationInfo, FloatType) - -Return initial state vector `Vector{FloatType}` with stripped units. -""" -function initialStateVector(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} - x_start = zeros(FloatType, eqInfo.nx) - startIndex = 1 - for xe_info in eqInfo.x_info - if xe_info.scalar - if !(xe_info.startOrInit isa Nothing) - x_start[startIndex] = FloatType(ustrip(xe_info.startOrInit)) - startIndex += 1 - end - else - for i = 1:xe_info.length - x_start[startIndex] = FloatType(ustrip(xe_info.startOrInit[i])) - startIndex += 1 - end - end + x_hidden_startIndex = addHiddenState!( + eqInfo::EquationInfo, + x_name::String, + der_x_name::String, + startOrInit; # Scalar or Vector + stateCategory::StateCategory = XD, + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false) + +Add new hidden state to model and return its index with respect to x_hidden, der_x_hidden. +The state is stored at place m.x_hidden[x_hidden_startIndex:x_hidden_startIndex+length(startOrInit)-1]. +""" +function addHiddenState!( + eqInfo::EquationInfo, + x_name::String, + der_x_name::String, + startOrInit; + stateCategory::StateCategory = XD, + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false)::Int + @assert(eqInfo.status == EquationInfo_Initialized_Before_Code_Generation) + if haskey(eqInfo.x_dict, x_name) || + haskey(eqInfo.der_x_dict, der_x_name) + error("Trying to add hidden state x_name=$x_name, der_x_name=$der_x_name but one or both names are already in use!") end - return x_start + + x_hidden_startIndex = eqInfo.nxHidden+1 + xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), + stateCategory, unit, startOrInit, fixed, nominal, unbounded, + x_hidden_startIndex = x_hidden_startIndex) + push!(eqInfo.x_info, xi_info) + x_infoIndex = length(eqInfo.x_info) + eqInfo.x_dict[x_name] = x_infoIndex + eqInfo.der_x_dict[der_x_name] = x_infoIndex + eqInfo.nxHidden += length(startOrInit) + return x_hidden_startIndex end @@ -817,6 +770,7 @@ end Remove all hidden (non-visible) states from `eqInfo`. """ function removeHiddenStates!(eqInfo::EquationInfo)::Nothing + @assert(eqInfo.status == EquationInfo_After_All_States_Are_Known) if eqInfo.nx > eqInfo.nxVisible for i = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) xi_info = eqInfo.x_info[i] @@ -826,59 +780,29 @@ function removeHiddenStates!(eqInfo::EquationInfo)::Nothing resize!(eqInfo.x_info, eqInfo.nx_infoVisible) eqInfo.nx = eqInfo.nxVisible end + eqInfo.nxHidden = 0 + eqInfo.status = EquationInfo_Initialized_Before_Code_Generation return nothing end """ - x_infoIndex = addState(eqInfo::EquationInfo, - x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; - stateCategory::StateCategory = XD, - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false)::Int where {FloatType} - -Add new state to model and return its index (new state info is stored in eqInfo.x_info[xindex]). -""" -function addState(eqInfo::EquationInfo, x_name::String, der_x_name::String, startOrInit::Vector{FloatType}; - stateCategory::StateCategory = XD, - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false)::Int where {FloatType} - if haskey(eqInfo.x_dict, x_name) || - haskey(eqInfo.der_x_dict, der_x_name) - error("Trying to add hidden state x_name=$x_name, der_x_name=$der_x_name but one or both names are already in use!") - end - - xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), - stateCategory, unit, startOrInit, fixed, nominal, unbounded) - push!(eqInfo.x_info, xi_info) - x_infoIndex = length(eqInfo.x_info) - eqInfo.x_dict[x_name] = x_infoIndex - eqInfo.der_x_dict[der_x_name] = x_infoIndex - return x_infoIndex -end + x_start = initialStateVector!(eqInfo::EquationInfo, FloatType)::Vector{FloatType} +The function updates `eqInfo` (e.g. sets eqInfo.nx, eqInfo.nxVisible) and returns the initial state vector x_start. +This function must be called, after all states are known (after calling propagateEvaluateAndInstantiate!(..)). """ - x_start = updateEquationInfo!(eqInfo::EquationInfo, FloatType) - -Set eqInfo.x_dict, eqInfo.der_x_dict, eqInfo.nx and eqInfo.x_info[:].startIndex -and return initial state vector x_start -""" -function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} +function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} + @assert(eqInfo.status == EquationInfo_Initialized_Before_Code_Generation) nx_infoFixed = eqInfo.nx_infoFixed - x_info = eqInfo.x_info + x_info = eqInfo.x_info + if length(x_info) == 0 # Handle systems with only algebraic variables, by introducing a dummy # differential equation der_x[1] = -x[1], with state name _dummy_x - push!(x_info, Modia.StateElementInfo( - "_dummy_x", :(), "der(_dummy_x)", :(), XD, "", 0.0, true, NaN, false)) + addHiddenState!(eqInfo, "_dummy_x", "der(_dummy_x)", FloatType(0.0)) startIndex = 1 - eqInfo.x_dict["_dummy_x"] = 1 - eqInfo.der_x_dict["der(_dummy_x)"] = 1 elseif nx_infoFixed == 0 startIndex = 1 else @@ -886,28 +810,49 @@ function updateEquationInfo!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex = xi_info.startIndex + xi_info.length end - for i = nx_infoFixed+1:length(x_info) + # Set startIndex for visible states where the size was not fixed before code generation + for i = nx_infoFixed+1:eqInfo.nx_infoVisible xi_info = x_info[i] xi_info.length = length(xi_info.startOrInit) xi_info.startIndex = startIndex startIndex += xi_info.length end - eqInfo.nx = startIndex - 1 - - nxVisible = 0 - for i = 1:eqInfo.nx_infoVisible + eqInfo.nxVisible = startIndex - 1 + + # Set startIndex for hidden states + for i = eqInfo.nx_infoVisible+1:length(x_info) xi_info = x_info[i] - nxVisible += x_info[i].length + xi_info.length = length(xi_info.startOrInit) + xi_info.startIndex = startIndex + startIndex += xi_info.length end - eqInfo.nxVisible = nxVisible - - return initialStateVector(eqInfo, FloatType) -end + eqInfo.nx = startIndex - 1 + @assert(eqInfo.nx == eqInfo.nxVisible + eqInfo.nxHidden) + # Construct x_start + x_start = zeros(FloatType, eqInfo.nx) + startIndex = 1 + for xe_info in eqInfo.x_info + if xe_info.scalar + if isnothing(xe_info.startOrInit) + x_name = xe_info.x_name + @warn "State $x_name has no start or init value defined. Using start value = 0.0." + else + @assert(length(xe_info.startOrInit) == 1) + x_start[startIndex] = FloatType(ustrip(xe_info.startOrInit)) + end + startIndex += 1 + else + xe_start = Vector{FloatType}(ustrip(xe_info.startOrInit)) + @assert(length(xe_start) == xe_info.length) + copyto!(x_start, startIndex, xe_start, 1, length(xe_start)) + startIndex += length(xe_start) + end + end -get_x_startIndexAndLength(eqInfo::EquationInfo, name::String) = begin - xe_info = eqInfo.x_info[ eqInfo.x_dict[name] ] - (xe_info.startIndex, xe_info.length) + @assert(eqInfo.nx == startIndex - 1) + eqInfo.status = EquationInfo_After_All_States_Are_Known + return x_start end @@ -926,7 +871,6 @@ function Base.show(io::IO, eqInfo::EquationInfo; indent=4) indentation2 = repeat(" ", 2*indent) indentation3 = repeat(" ", 3*indent) println(io, "Modia.EquationInfo(") - println(io, indentation2, "status = Modia.", eqInfo.status, ",") println(io, indentation2, "ode = ", eqInfo.ode, ",") if eqInfo.nz > 0 println(io, indentation2, "nz = ", eqInfo.nz, ",") @@ -973,8 +917,14 @@ function Base.show(io::IO, eqInfo::EquationInfo; indent=4) show(io, eqInfo.vSolvedWithFixedTrue) end - if eqInfo.nx > 0 - print(io, ",\n", indentation2, "nx = ", eqInfo.nx) + if eqInfo.nx >= 0 + nx = eqInfo.nx + nxVisible = eqInfo.nxVisible + nxHidden = eqInfo.nxHidden + nx_infoFixed = eqInfo.nx_infoFixed + nx_infoVisible = eqInfo.nx_infoVisible + print(io, ",\n", indentation2, "nx = $nx, nxVisible = $nxVisible, nxHidden = $nxHidden") + print(io, ",\n", indentation2, "nx_infoFixed = $nx_infoFixed, nx_infoVisible = $nx_infoVisible") end if !isnothing(eqInfo.defaultParameterAndStartValues) @@ -982,17 +932,6 @@ function Base.show(io::IO, eqInfo::EquationInfo; indent=4) show(io, eqInfo.defaultParameterAndStartValues, indent=12, finalLineBreak=false) end - if !isnothing(eqInfo.ResultType) - print(io, ",\n", indentation2, "ResultType = ") - show(io, eqInfo.ResultType) - - if eqInfo.ResultTypeHasFloatType - print(io, ",\n", indentation2, "ResultTypeHasFloatType = ") - show(io, eqInfo.ResultTypeHasFloatType) - end - end - - println(io, "\n", indentation, ")") return nothing end @@ -1025,68 +964,3 @@ function get_xNames(eqInfo::EquationInfo)::Vector{String} end return xNames end - - - -#= -""" - update_equationInfo!(eqInfo::EquationInfo) - -Update equationInfo as needed for [`EquationInfoStatus`](@ref)` = SOLVER_MODEL`. -""" -function update_equationInfo!(eqInfo::EquationInfo, modelValues::Modia.AbstractModelValues)::Nothing - x_info = eqInfo.x_info - - if eqInfo.status == MANUAL - # Determine length and unit - count = 0 - for xi_info in x_info - if xi_info.x_name != "" # XD or XALG - (component,name) = Modia.get_modelValuesAndName(modelValues, xi_info.x_name) - elseif xi_info.der_x_name != "" # XLAMBDA or XMUE - (component,name) = Modia.get_modelValuesAndName(modelValues, xi_info.der_x_name) - else - # Pure algebraic with dummy equation der(x) = -x, x(0) = 0 - xi_info.length = 1 - count = count+1 - continue - end - - xi_type = fieldtype(typeof(component), name) - xi_numberType = Modia.numberType(xi_type) - xi_info.unit = replace(string(unit(xi_numberType)), " " => "*") - xi_info.length = Base.length(xi_type) # Base.length(::Type{<:Number})=1 is defined in Modia, since not defined in Base - end - if count == 1 && length(x_info) > 1 || count > 1 - error("Error in update_equationInfo!: x_info is wrong.\n", - "x_info = $x_info") - end - end - - # Set startIndex in x_info and compute nx - startIndex = 1 - for xi_info in x_info - xi_info.startIndex = startIndex - startIndex += xi_info.length - end - nx = startIndex - 1 - eqInfo.nx = nx - - # Set x_infoByIndex::Vector{Int} - eqInfo.x_infoByIndex = zeros(Int,nx) - i1 = 0 - i2 = 0 - for (i,xi_info) in enumerate(x_info) - i1 = xi_info.startIndex - i2 = i1 + xi_info.length - 1 - for j = i1:i2 - eqInfo.x_infoByIndex[j] = i - end - end - - eqInfo.status = SOLVER_MODEL - - return nothing -end -=# - diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 4add4b8..c45d5b4 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -90,9 +90,6 @@ Recursively traverse the hierarchical collection `partiallyInstantiatedModel.par return nothing, if an error occurred (an error message was printed). """ function propagateEvaluateAndInstantiate!(m::SimulationModel{FloatType,TimeType}; log=false) where {FloatType,TimeType} - removeHiddenStates!(m.equationInfo) - removeHiddenCrossingFunctions!(m.eventHandler) - x_found = fill(false, length(m.equationInfo.x_info)) map = propagateEvaluateAndInstantiate2!(m, m.parameters, x_found, [], ""; log=log) @@ -252,7 +249,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType if log println(" 2: ... key = $k, value = $v") end - if k == :_constructor || k == :_instantiateFunction || k == :_path || (k == :_class && !isnothing(constructor)) + if k == :_constructor || k == :_buildFunction || k == :_buildOption || k == :_instantiateFunction || k == :_path || (k == :_class && !isnothing(constructor)) if log println(" 3: ... key = $k") end @@ -379,7 +376,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType if log println(" 13: +++ Instantiated $path: $instantiateFunction will be called to instantiate sub-model and define hidden states\n\n") end - Core.eval(modelModule, :($instantiateFunction($m, $current, $path))) + Core.eval(modelModule, :($instantiateFunction($m, $current, $path, log=$log))) end return current else @@ -395,7 +392,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType return obj catch str = getConstructorAsString(path, constructor, parameters) - printstyled("\nError in model $(m.modelName) when instantiating\n$str\n", bold=true, color=:red) + printstyled("\nError in model $(m.modelName) when instantiating\n $str\n", bold=true, color=:red) Base.rethrow() end end diff --git a/src/ModelCollections.jl b/src/ModelCollections.jl index d744e3d..9f256a2 100644 --- a/src/ModelCollections.jl +++ b/src/ModelCollections.jl @@ -74,14 +74,18 @@ function showModel(m::OrderedDict, level=0) for e in v.args println(" "^(level+1), e) end - println(" "^level, "]") + println(" "^level, "]") elseif typeof(v) <: AbstractArray - println(" "^level, k, " = [") - for e in v - print(" "^(level+1)) - showModel(e, level+1) + if eltype(v) <: Number + println(" "^level, k, " = ", v) + else + println(" "^level, k, " = [") + for e in v + print(" "^(level+1)) + showModel(e, level+1) + end + println(" "^level, "]") end - println(" "^level, "]") elseif k != :_class #println(" "^level, k, " = ", stringifyDefinition(v), ",") print(" "^level, k, " = ") diff --git a/src/Modia.jl b/src/Modia.jl index 5ced68d..a795bfa 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-05-11" +const Date = "2022-05-17" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -48,8 +48,10 @@ export simulate!, linearize!, get_result export @usingModiaPlot, usePlotPackage, usePreviousPlotPackage, currentPlotPackage export resultInfo, printResultInfo, rawSignal, getPlotSignal, defaultHeading export signalNames, timeSignalName, hasOneTimeSignal, hasSignal +export hasParameter, getParameter, getEvaluatedParameter +export showParameters, showEvaluatedParameters -export SimulationModel, measurementToString, get_lastValue +export SimulationModel, measurementToString, get_lastValue, getLastValue export positive, negative, previous, edge, after, reinit, pre export initial, terminal, isInitial, isTerminal, initLinearEquationsIteration! export get_xNames @@ -160,6 +162,14 @@ quantity(numberType, numberUnit::Unitful.FreeUnits) = Quantity{numberType, dimen quantityTypes(::Type{Unitful.Quantity{T,D,U}}) where {T,D,U} = (T,D,U) +""" + str = modelPathAsString(modelPath::Union{Expr,Symbol,Nothing}) + +Return modelPath of submodel as string. +""" +modelPathAsString(modelPath::Union{Expr,Symbol,Nothing}) = isnothing(modelPath) ? "" : string(modelPath) + + include("EquationAndStateInfo.jl") include("StateSelection.jl") diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index d6b591c..c7c1c5b 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -723,12 +723,10 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # convertedStartValues = convert(Vector{FloatType}, [ustrip(v) for v in startValues]) # ustrip.(value) does not work for MonteCarloMeasurements # @show mappedParameters - x_startValues = nothing # deprecated, is no longer used; just temporarily kept for backwards compatibility - # = initialStateVector(equationInfo, FloatType) - + # println("Build SimulationModel") - model = @timeit to "build SimulationModel" SimulationModel{FloatType,TimeType}(modelModule, name, buildDict, getDerivatives, equationInfo, x_startValues, previousVars, preVars, holdVars, + model = @timeit to "build SimulationModel" SimulationModel{FloatType,TimeType}(modelModule, name, buildDict, getDerivatives, equationInfo, previousVars, preVars, holdVars, mappedParameters, extraResults; vSolvedWithInitValuesAndUnit, vEliminated, vProperty, var_name = (v)->string(unknownsWithEliminated[v]), @@ -738,7 +736,6 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod if logExecution println("\nExecute getDerivatives") # @show startValues - #derx = deepcopy(x_startValues) # deepcopy(convertedStartValues) # To get the same type as for x (deepcopy is needed for MonteCarloMeasurements) println("First executions of getDerivatives") @timeit to "execute getDerivatives" try #@time Base.invokelatest(getDerivatives, derx, x_startValues, model, convert(TimeType, 0.0)) diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index ddaab1a..1031f07 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -95,16 +95,18 @@ The simulation results are stored in `instantiatedModel` and can be plotted with `plot(instantiatedModel, ...)` and the result values can be retrieved with `rawSignal(..)` or `getPlotSignal(..)`. `printResultInfo(instantiatedModel)` prints information about the signals in the result file. -For more details, see chapter [Results and Plotting](@ref)). +For more details, see sections [Parameters/Init/Start](@ref), [Results](@ref), [Plotting](@ref). -The (optional) return argument `solution` is the return argument from `DifferentialEquations.solve(..)` and +The return argument `solution` is the return argument from `DifferentialEquations.solve(..)` and therefore all post-processing functionality from `DifferentialEqautions.jl` can be used. Especially, - solution.t[i] # time-instant at storage point i (solution.t[end] = stopTime) - solution.u[i] # states at storage point i -A simulation run can be aborted with ` C` (SIGINT). +A simulation run can be aborted with ` C` (SIGINT), provided `using PyPlot` or `import PyPlot` was +not called before (the signals in Python module matplotlib.pyplot intervene with Julias signals, see +[PyPlot.jl issue 305](https://github.com/JuliaPy/PyPlot.jl/issues/305)). -# Optional Arguments +# Optional ArgumentsS - `merge`: Define parameters and init/start values that shall be merged with the previous values stored in `model`, before simulation is started. If, say, an init value `phi = Var(init=1.0)` @@ -303,7 +305,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end else # ODE integrator - m.odeIntegrator = true + m.odeIntegrator = true TimerOutputs.@timeit m.timer "DifferentialEquations.ODEProblem" problem = DifferentialEquations.ODEProblem{true}(derivatives!, m.x_init, tspan, m) end @@ -478,8 +480,6 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me return solution end -#get_x_startIndexAndLength(m::SimulationModel, name) = Modia.get_x_startIndexAndLength(m.equationInfo, name) - #--------------------------------------------------------------------- # Linearization @@ -589,7 +589,7 @@ ModiaResult.hasOneTimeSignal(m::SimulationModel) = true """ hasSignal(instantiatedModel, name::AbstractString) -Return true if parameter or time-varying variable `name` (for example `name = "a.b.c"`) +Return true if time-varying variable `name` (for example `name = "a.b.c"`) is defined in the instantiateModel that can be accessed and can be used for plotting. """ ModiaResult.hasSignal(m::SimulationModel, name::AbstractString) = begin @@ -601,11 +601,66 @@ ModiaResult.hasSignal(m::SimulationModel, name::AbstractString) = begin end +""" + hasParameter(instantiatedModel, name::AbstractString) + +Return true if parameter `name` (for example `name = "a.b.c"`) +is defined in the instantiateModel. +""" +hasParameter(m::SimulationModel, name::AbstractString) = begin + if isnothing(m) || ismissing(m) || ismissing(m.result_x) || ismissing(m.result_vars) || ismissing(m.result_der_x) + return false + end + !ismissing(get_value(m.evaluatedParameters, name)) +end + + +""" + getParameter(instantiatedModel, name::AbstractString) + +Return the value of parameter or init/start value `name` (for example `name = "a.b.c"`). +If `name` is not known, `missing` is returned. +""" +getParameter(m::SimulationModel, name::AbstractString) = get_value(m.parameters, name) + + +""" + getEvaluatedParameter(instantiatedModel, name::AbstractString) + +Return the value of evaluated parameter or init/start value `name` (for example `name = "a.b.c"`). +If `name` is not known, `missing` is returned. +""" +getEvaluatedParameter(m::SimulationModel, name::AbstractString) = get_value(m.evaluatedParameters, name) + + +""" + showParameters(instantiatedModel) + +Print the parameters and the init/start values. +""" +function showParameters(m::SimulationModel)::Nothing + parameters = m.parameters + @showModel parameters + return nothing +end + + +""" + showEvaluatedParameters(instantiatedModel) + +Print the evaluated parameters and the evaluated init/start values. +""" +function showEvaluatedParameters(m::SimulationModel)::Nothing + evaluatedParameters = m.evaluatedParameters + @showModel evaluatedParameters + return nothing +end + """ names = signalNames(instantiatedModel::Modia.SimulationModel) -Return the variable names (parameters, time-varying variables) of an +Return the names of the time-varying variables of an [`@instantiateModel`](@ref) that are present in the result (e.g. can be accessed for plotting). """ ModiaResult.signalNames(m::SimulationModel) = collect(keys(m.result_info)) @@ -625,6 +680,12 @@ function ChainRules.rrule(::typeof(ResultView), v, i) end =# +""" + (timeSignal, signal, signalType) = ModiaResult.rawSignal(instantiatedModel, name) + (timeSignal, signal, signalType) = Modia.rawSignal( instantiatedModel, name) + +Get raw signal of result from an instantiated model of Modia. +""" function ModiaResult.rawSignal(m::SimulationModel, name::AbstractString) tsig = m.result_x.t if !m.unitless diff --git a/src/StateSelection.jl b/src/StateSelection.jl index 1ec3dbd..9890079 100644 --- a/src/StateSelection.jl +++ b/src/StateSelection.jl @@ -582,7 +582,7 @@ mutable struct EquationGraph TearingSetup(Gunknowns,length(Arev)), Int[], Int[], Int[], Int[], Int[], Int[], Int[], Int[], Int[], Int[], Vector{Int}[Int[], Int[], Int[], Int[], Int[], Int[]], fill(false, length(Arev)), - Modia.EquationInfo(status=Modia.CODE_GENERATION), + Modia.EquationInfo(), fill(0, length(B)), TearedEquations[], fill(0, length(B)), Vector{Expr}(undef, length(B)), Expr[], Expr[]) end @@ -1500,7 +1500,7 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} push!(x_vec_fixed , v_fixed) end end - eq.equationInfo.nx_infoFixed = length(x_info) + nx_infoFixed = length(x_info) for (i,v) in enumerate(x_vec) v_startOrInit = x_vec_startOrInit[i] v_fixed = x_vec_fixed[i] @@ -1521,21 +1521,8 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} v_nominal, v_unbounded)) end - # Handle systems with only algebraic variables, by introducing a dummy - # differential equation der_x[1] = -x[1]. - #= - if length(ODE_states) == 0 - if log - println("Model has only algebraic variables.\n", - "Added a dummy differential equation der(_dummy_x) = -_dummy_x, _dummy_x(t0) = 0") - end - push!(eq.equationInfo.x_info, Modia.StateElementInfo( - "_dummy_x", :(), "der(_dummy_x)", :(), XD, "", 0.0, true, NaN, false)) - end - =# - # Finalize equationInfo - initEquationInfo!(eq.equationInfo) + initEquationInfo!(eq.equationInfo, nx_infoFixed) # Print ODE states if logStates diff --git a/test/TestFilterCircuit.jl b/test/TestFilterCircuit.jl index 5063c8a..d95912f 100644 --- a/test/TestFilterCircuit.jl +++ b/test/TestFilterCircuit.jl @@ -2,7 +2,7 @@ module TestFilterCircuit using Modia @usingModiaPlot -using Test +using Modia.Test setLogMerge(false) @@ -24,26 +24,26 @@ filterCircuit = @instantiateModel(FilterCircuit) simulate!(filterCircuit, Tsit5(), stopTime = 10, merge = Map(R = Map(R = 5u"Ω"), C = Map(v = 3.0u"V")), logParameters = true, logStates = true, requiredFinalStates = [7.424843902110655]) - +Modia.printResultInfo(filterCircuit) # Test access functions @testset "Test variable access functions (TestFilterCircuit.jl)" begin currentNames = signalNames(filterCircuit) - requiredNames = String["C.C", "C.i", "C.n.i", "C.n.v", "C.p.i", "C.p.v", "C.v", "R.R", "R.i", "R.n.i", "R.n.v", "R.p.i", "R.p.v", "R.v", "V.V", "V.i", "V.n.i", "V.n.v", "V.p.i", "V.p.v", "V.v", "der(C.v)", "ground.p.i", "ground.p.v", "time"] + requiredNames = String["C.i", "C.n.i", "C.n.v", "C.p.i", "C.p.v", "C.v", "R.i", "R.n.i", "R.n.v", "R.p.i", "R.p.v", "R.v", "V.i", "V.n.i", "V.n.v", "V.p.i", "V.p.v", "V.v", "der(C.v)", "ground.p.i", "ground.p.v", "time"] @test sort!(currentNames) == sort!(requiredNames) @test hasSignal(filterCircuit, "R.v") @test hasSignal(filterCircuit, "C.n.v") - @test hasSignal(filterCircuit, "R.R") + @test hasParameter(filterCircuit, "R.R") @test hasSignal(filterCircuit, "ground.p.i") @test hasSignal(filterCircuit, "R.p.vv") == false - @test isapprox(get_lastValue(filterCircuit, "R.v") , 2.5751560978893453u"V" ) - @test isapprox(get_lastValue(filterCircuit, "C.n.v"), 0.0u"V") - @test isapprox(get_lastValue(filterCircuit, "R.R") , 5.0u"Ω") - @test isapprox(get_lastValue(filterCircuit, "ground.p.i"), 0.0) + @test isapprox(getLastValue(filterCircuit, "R.v") , 2.5751560978893453u"V" ) + @test isapprox(getLastValue(filterCircuit, "C.n.v"), 0.0u"V") + @test isapprox(getEvaluatedParameter(filterCircuit, "R.R") , 5.0u"Ω") + @test isapprox(getLastValue(filterCircuit, "ground.p.i"), 0.0) end # Test plotting of variables, zero variables, parameters -plot(filterCircuit, [("R.v", "C.v"), ("R.R", "ground.p.i")], figure=1) +plot(filterCircuit, [("R.v", "C.v"), "ground.p.i"], figure=1) # Simulate with lower precision @@ -51,7 +51,7 @@ filterCircuitLow = @instantiateModel(FilterCircuit, unitless=true, FloatType = F simulate!(filterCircuitLow, RK4(), adaptive=false, stopTime=10.0, interval=0.01, merge = Map(R = Map(R = 5.0), C = Map(v = 3.0)), # merge = Map(R = Map(R = 5u"Ω"), C = Map(v = 3.0u"V")), requiredFinalStates = Float32[7.4248414]) -plot(filterCircuitLow, [("R.v", "C.v"), ("R.R", "ground.p.i")], figure=2) +plot(filterCircuitLow, [("R.v", "C.v"), "ground.p.i"], figure=2) # Simulate with DAE integrator diff --git a/test/TestFirstOrder2.jl b/test/TestFirstOrder2.jl index 38acc3e..56f9a2e 100644 --- a/test/TestFirstOrder2.jl +++ b/test/TestFirstOrder2.jl @@ -2,7 +2,7 @@ module TestFirstOrder2 using Modia @usingModiaPlot -using Test +using Modia.Test # using RuntimeGeneratedFunctions # RuntimeGeneratedFunctions.init(@__MODULE__) @@ -68,6 +68,7 @@ simulate!(firstOrder3, Tsit5(), stopTime = 10u"hr") plot(firstOrder3, [("u", "x"), "der(x)"], figure=2) # Test all options +println("\n... Test all options of @instantiateModel(..)") firstOrder3b = @instantiateModel(FirstOrder3, evaluateParameters=true, log=true, logModel=true, logDetails=true, logStateSelection=true, logCode=true, logExecution=true, logCalculations=true, logTiming=true) diff --git a/test/TestHeatTransfer.jl b/test/TestHeatTransfer.jl index e871d54..e903da9 100644 --- a/test/TestHeatTransfer.jl +++ b/test/TestHeatTransfer.jl @@ -2,7 +2,7 @@ module TestHeatTransfer using Modia @usingModiaPlot -using Test +using Modia.Test include("$(Modia.path)/models/HeatTransfer.jl") diff --git a/test/TestLinearEquations.jl b/test/TestLinearEquations.jl index d232bb8..9765a7c 100644 --- a/test/TestLinearEquations.jl +++ b/test/TestLinearEquations.jl @@ -3,7 +3,7 @@ """ module TestLinearEquations -using Test +using Modia.Test using Modia using Modia.TimerOutputs diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 5364e9c..14399f8 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -3,6 +3,8 @@ module TestLinearSystems using Modia using Modia.OrderedCollections using Modia.LinearAlgebra +using Modia.StaticArrays +using Modia.Test @usingModiaPlot """ @@ -37,7 +39,7 @@ SSTest = Model( y = ss.y[1]] ) -ssTest = @instantiateModel(SSTest, logCode=true) +ssTest = @instantiateModel(SSTest, logCode=false) simulate!(ssTest, stopTime=1.0, log=true, logStates=true) plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) @@ -56,15 +58,15 @@ LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace kwargs...) mutable struct LinearStateSpaceStruct{FloatType} - path::String # Path name of instance - x_infoIndex::Int # Index with respect to equationInfo.x_info + path::String # Path name of instance + x_hidden_startIndex::Int A::Matrix{FloatType} B::Matrix{FloatType} C::Matrix{FloatType} x_init::Vector{FloatType} # Initial values of states y::Vector{FloatType} # Internal memory for y x::Vector{FloatType} # Internal memory for x - derx::Vector{FloatType} # Internal memory for derx + der_x::Vector{FloatType} # Internal memory for der(x) function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, x_init::Union{AbstractVector,Nothing}=nothing, @@ -100,6 +102,8 @@ mutable struct LinearStateSpaceBuild{FloatType} function LinearStateSpaceBuild{FloatType}(path::String, nu::Int, ny::Int) where {FloatType} #println("... 2: LinearStateSpaceBuild called with path = $path") + @assert(nu >= 0) + @assert(ny >= 0) new(path,nu,ny,nothing) end end @@ -109,7 +113,7 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: buildDict::OrderedCollections.OrderedDict{String,Any}, path::Union{Expr,Symbol,Nothing}) # Called from @instantiatedModel, during instantiation of the model. - pathAsString = isnothing(path) ? "" : string(path) + pathAsString = Modia.modelPathAsString(path) #println("... 1: buildLinearStateSpace! called for path = ", pathAsString) # Determine nu,ny from model @@ -137,15 +141,17 @@ end function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationModel{FloatType,TimeType}, - model::AbstractDict, path::String)::Nothing where {FloatType,TimeType} + model::AbstractDict, path::String; log=false)::Nothing where {FloatType,TimeType} # Called during evaluation of the parameters (before initialization) - #println("... 3: instantiateLinearStateSpace! called for $path with model = $model") + if log + println("instantiateLinearStateSpace! called for $path with model = $model") + end lsBuild::LinearStateSpaceBuild{FloatType} = partiallyInstantiatedModel.buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) @assert(size(ls.A,2) == size(ls.A,1)) @assert(size(ls.B,2) == lsBuild.nu) @assert(size(ls.C,1) == lsBuild.ny) - ls.x_infoIndex = Modia.addState(partiallyInstantiatedModel.equationInfo, path*".x", path*".der(x)", ls.x_init) + ls.x_hidden_startIndex = Modia.addHiddenState!(partiallyInstantiatedModel.equationInfo, path*".x", "der("*path*".x)", ls.x_init) lsBuild.ls = ls return nothing end @@ -153,7 +159,7 @@ end function openLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls - copyState!(instantiatedModel, ls.x_infoIndex, ls.x) + Modia.copyFromHiddenState!(instantiatedModel, ls.x_hidden_startIndex, ls.x) return ls end @@ -163,10 +169,10 @@ function computeOutputs!(instantiatedModel, ls) end function computeStateDerivatives!(instantiatedModel, ls, u)::Bool - # ls.derx .= ls.A*ls.x + ls.B*u - mul!(ls.derx, ls.A, ls.x) - mul!(ls.derx, ls.B, u, 1.0, 1.0) - Modia.set_hiddenStateDerivative!(instantiatedModel, ls.x_infoIndex, ls.derx) + # ls.der_x .= ls.A*ls.x + ls.B*u + mul!(ls.der_x, ls.A, ls.x) + mul!(ls.der_x, ls.B, u, 1.0, 1.0) + Modia.copyToHiddenStateDerivative!(instantiatedModel, ls.x_hidden_startIndex, ls.der_x) return true end @@ -180,7 +186,7 @@ SSTest = Model( ssTest = @instantiateModel(SSTest, logCode=true) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, requiredFinalStates = [1.987867388853733]) -#Modia.printResultInfo(ssTest) +Modia.printResultInfo(ssTest) plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, @@ -194,4 +200,60 @@ simulate!(ssTest, stopTime=1.0, log=false, logStates=true, Modia.printResultInfo(ssTest) plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) + +println("\n... Test init vectors of scalars, fixed-size, variable-size, hidden-size vectors") + +T = 0.2 + +SSTest2 = Model( + submodel = Model( ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), + x1 = Var(init = 1.1), + x3 = Var(init = SVector{3}(0.5, 0.6, 0.7)), + x4 = Var(init = [0.8, 0.9]), + equations = :[ der(x1) = -x1 + der(x2) = -x2 + der(x3) = -x3 + der(x4) = -x4 ]), + ss = LinearStateSpace(A=[-1/T 0.0; + 0.0 -1/T], + B=[1.0/T; + 1.0/T;;], + C=[0.4 0.4;], + x_init=[0.3,0.4]), + equations = :[ss.u = [2.0], submodel.ss.u = [2.1], + y1 = ss.y[1], y2 = submodel.ss.y[1]] + ) +ssTest2 = @instantiateModel(SSTest2, logCode=false) +simulate!(ssTest2, stopTime=1.0, log=true, logStates=true) +printResultInfo(ssTest2) + +plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), + ("submodel.ss.u", "ss.u", "y1", "y2"), + ("der(submodel.ss.x)", "der(submodel.x1)", "der(submodel.x2)", "der(submodel.x3)", "der(submodel.x4)", "der(ss.x)")], figure=3) + +simulate!(ssTest2, stopTime=1.0, log=false, logStates=true, + merge = Map(submodel = Map(x4 = [0.85]), + ss = LinearStateSpace(A=[-1/T 0.0 0.0; + 0.0 -1/T 0.0; + 0.0 0.0 -1/T], + B=[1.0/T; + 1.0/T; + 1.0/T;;], + C=[0.5 0.5 0.5;], + x_init=[0.35,0.45,0.55])) + ) +printResultInfo(ssTest2) + +println("\n... Check functions for parameters and signals") +showParameters( ssTest2) +showEvaluatedParameters(ssTest2) +@test hasParameter( ssTest2, "submodel.ss.A") +@test getParameter( ssTest2, "ss.x_init") == [0.35,0.45,0.55] +@test getEvaluatedParameter(ssTest2, "ss.x_init") == [0.35,0.45,0.55] +@test getLastValue( ssTest2, "ss.x_init") == [0.35,0.45,0.55] + +plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), + ("submodel.ss.u", "ss.u", "y1", "y2"), + ("der(submodel.ss.x)", "der(submodel.x1)", "der(submodel.x2)", "der(submodel.x3)", "der(submodel.x4)", "der(ss.x)")], figure=4, maxLegend=12) + end \ No newline at end of file diff --git a/test/TestParameter.jl b/test/TestParameter.jl index 88bbd9b..ba8b79f 100644 --- a/test/TestParameter.jl +++ b/test/TestParameter.jl @@ -2,7 +2,7 @@ module TestParameter using Modia @usingModiaPlot -using Test +using Modia.Test include("$(Modia.path)/models/Blocks.jl") diff --git a/test/TestStateSelection.jl b/test/TestStateSelection.jl index ec575be..9f7c17b 100644 --- a/test/TestStateSelection.jl +++ b/test/TestStateSelection.jl @@ -1,7 +1,7 @@ module TestStateSelection using Modia -using Test +using Modia.Test function checkStateSelection(model, x_names, linearEquations=[]) # Check names of the states diff --git a/test/TestTwoInertiasAndIdealGear.jl b/test/TestTwoInertiasAndIdealGear.jl index a5fc42e..ec0ccad 100644 --- a/test/TestTwoInertiasAndIdealGear.jl +++ b/test/TestTwoInertiasAndIdealGear.jl @@ -2,7 +2,7 @@ module TestTwoInertiasAndIdealGear using Modia @usingModiaPlot -using Test +using Modia.Test TwoInertiasAndIdealGearTooManyInits = Model( J1 = 0.0025, diff --git a/test/TestTwoInertiasAndIdealGearWithUnits.jl b/test/TestTwoInertiasAndIdealGearWithUnits.jl index bbb62bc..6e66e6b 100644 --- a/test/TestTwoInertiasAndIdealGearWithUnits.jl +++ b/test/TestTwoInertiasAndIdealGearWithUnits.jl @@ -2,7 +2,7 @@ module TestTwoInertiasAndIdealGearWithUnits using Modia @usingModiaPlot -using Test +using Modia.Test TwoInertiasAndIdealGearWithUnits = Model( J1 = 0.0025u"kg*m^2", diff --git a/test/TestTwoInertiasAndIdealGearWithUnitsAndUncertainties.jl b/test/TestTwoInertiasAndIdealGearWithUnitsAndUncertainties.jl index 059e47d..1a40b00 100644 --- a/test/TestTwoInertiasAndIdealGearWithUnitsAndUncertainties.jl +++ b/test/TestTwoInertiasAndIdealGearWithUnitsAndUncertainties.jl @@ -50,7 +50,7 @@ println("\n... Numeric linearization with Float64") println(IOContext(stdout, :error_digits=>15), "A2 = ", A2, ", x2 = ", x2) #= DoubleFloats not defined -using Test +using Modia.Test println("\n... Numeric linearization with Double64") using DoubleFloats twoInertiasAndIdealGear2 = SimulationModel{Measurement{Double64}}(twoInertiasAndIdealGear) From bc507156e0a45ddb9f2e3f82760a7e0565c5466b Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 17 May 2022 09:09:45 +0200 Subject: [PATCH 20/63] Tiny docu error fixed --- docs/src/Functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/Functions.md b/docs/src/Functions.md index 00ad0a8..a614d93 100644 --- a/docs/src/Functions.md +++ b/docs/src/Functions.md @@ -103,7 +103,7 @@ The following functions are provided to **define/inquire the current plot packag The following functions are available after 1. `ENV["MODIA_PLOT"] = XXX` (e.g. in startup.jl file) or - `@usingModiaPlot(XXX)` has been executed (XXX = "PyPlot", "GLMakie", "WGLMakie", "CairoMakie", "NoPlot" or "SilentNoPlot") and + `usePlotPackage(XXX)` has been executed (XXX = "PyPlot", "GLMakie", "WGLMakie", "CairoMakie", "NoPlot" or "SilentNoPlot") and 2. `@usingModiaPlot` has been called, to **plot with the currently defined plot package** @@ -125,7 +125,7 @@ names and units of the variables. Example: using Modia @usingModiaPlot -instantiatedModel = @instantiatedModel(...) +instantiatedModel = @instantiateModel(...) simulate!(instantiatedModel, ...) plot(instantiatedModel, [ ("phi", "r") ("phi", "phi2", "w"); From ff4a7635e498e4703a8ac410d3d6e7c53644d31d Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 17 May 2022 17:32:42 +0200 Subject: [PATCH 21/63] Reorder result (first all states, afterwards all state derivatives) --- src/CodeGeneration.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 4e2dad1..812dbf6 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -456,10 +456,12 @@ mutable struct SimulationModel{FloatType,TimeType} # Define result # Store x and der_x for (xe_index, xe_info) in enumerate(equationInfo.x_info) - result_info[xe_info.x_name] = ResultInfo(RESULT_X , xe_index) + result_info[xe_info.x_name] = ResultInfo(RESULT_X, xe_index) + end + for (xe_index, xe_info) in enumerate(equationInfo.x_info) result_info[xe_info.der_x_name] = ResultInfo(RESULT_DER_X, xe_index) end - + # Store variables for (i, name) in enumerate(variableNames) str_name = string(name) From b65270f407834b0f93535409f9ba54d4a2898e90 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Thu, 19 May 2022 09:41:07 +0200 Subject: [PATCH 22/63] New function addHiddenState(instantiatedModel, ...) --- src/CodeGeneration.jl | 26 ++++++++++++++++++++++++++ src/EquationAndStateInfo.jl | 15 --------------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 812dbf6..13e7554 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -564,6 +564,32 @@ function get_xinfo(m::SimulationModel, x_index::Int)::Tuple{Int, Int, String} end +""" + x_hidden_startIndex = addHiddenState!( + m::SimulationModel, + x_name::String, + der_x_name::String, + startOrInit; # Scalar or Vector + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false) + +Add new hidden state to instantiated model and return its index that allows fast copying to x and der(x) vectors. +""" +addHiddenState!(m::SimulationModel, + x_name::String, + der_x_name::String, + startOrInit; + stateCategory::StateCategory = XD, + unit::String = "", + fixed::Bool = true, + nominal::Float64 = NaN, + unbounded::Bool = false)::Int = addHiddenState!(m.equationInfo, x_name, der_x_name, startOrInit; + stateCategory = stateCategory, unit = unit, fixed = fixed, + nominal = nominal, unbounded = unbounded) + + """ copyFromHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{FloatType}) diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 139a98e..98be34f 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -720,21 +720,6 @@ function initEquationInfo!(eqInfo::EquationInfo, nx_infoFixed::Int)::Nothing end -""" - x_hidden_startIndex = addHiddenState!( - eqInfo::EquationInfo, - x_name::String, - der_x_name::String, - startOrInit; # Scalar or Vector - stateCategory::StateCategory = XD, - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false) - -Add new hidden state to model and return its index with respect to x_hidden, der_x_hidden. -The state is stored at place m.x_hidden[x_hidden_startIndex:x_hidden_startIndex+length(startOrInit)-1]. -""" function addHiddenState!( eqInfo::EquationInfo, x_name::String, From b2af87b773ad92e7e0e6c7c834c6ab9196dd0d74 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Thu, 19 May 2022 10:06:36 +0200 Subject: [PATCH 23/63] Bug fix: A hierarchical model name with a derivative operator, say `der(a.b.c)`, has now the correct name `a.b.der(c)` in the result. For example, the plot command needs to be changed to `plot(..., "a.b.der(c)")` instead of the previous command `plot(..., "der(a.b.c)")`. --- docs/src/index.md | 11 ++++++++-- src/Modia.jl | 2 +- src/ModiaLang.jl | 44 ++++++++++++++++++++++++++++++++++++--- test/TestFilterCircuit.jl | 2 +- test/TestHeatTransfer.jl | 2 +- test/TestLinearSystems.jl | 6 +++--- test/runtests_withPlot.jl | 2 +- 7 files changed, 57 insertions(+), 12 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index ae88ca7..0a9b603 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -47,12 +47,19 @@ functionalities of these packages. ** Bug fixes -- The initial state vector was not always correctly filled with start/init values of the model (is now fixed). -- `signalNames(instantiatedModel)` did sometimes not show the correct signal names available in the result (is now fixed). +1. A hierarchical model name with a derivative operator, say `der(a.b.c)`, has now the correct name `a.b.der(c)` + in the result. For example, the plot command needs to be changed to `plot(..., "a.b.der(c)")` instead of the previous + command `plot(..., "der(a.b.c)")`. +2. The initial state vector was not always correctly filled with start/init values of the model (is now fixed). +3. `signalNames(instantiatedModel)` did sometimes not show the correct signal names available in the result (is now fixed). **Non-backwards compatible changes** +- Bug fix 1 can lead for some models to warnings and the selected variable is no longer plotted (-> the model needs to be changed). + +- Bug fix 2 can lead for some models to a different result (without notice). + - Parameters are no longer seen as part of the result (since parameters can be complex internal datastructures, e.g. for Modia3D). Therefore, they are no longer available in result access functions (`printResultInfo, signalNames, rawSignal, getPlotSignal, plot, ...`). Instead, they can be accessed via new functions `hasParameter, parameter, evaluatedParameter, showParameter, showEvaluatedParameter`. diff --git a/src/Modia.jl b/src/Modia.jl index a795bfa..ce63e98 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-05-17" +const Date = "2022-05-19" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index c7c1c5b..e95f19e 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -30,6 +30,44 @@ function printArray(array, heading; order=1:length(array), log=false, number=tru end end + +""" + newName = moveDerToLeaf(name::String)::String + +Move `der(..)` to leaf name part. + +# Examples +``` +moveDerToLeaf("a.b.c") # = "a.b.c" +moveDerToLeaf("der(x)") # = "der(x)" +moveDerToLeaf("der(der(x)") # = "der(der(x))" +moveDerToLeaf("der(a.x)") # = "a.der(x)" +moveDerToLeaf("der(a.b.x)") # = "a.b.der(x)" +moveDerToLeaf("der(der(der(a.b.c.x)))") # = "a.b.c.der(der(der(x)))" +``` +""" +function moveDerToLeaf(name::String)::String + if length(name) >= 4 && name[1:4] == "der(" && !isnothing(findfirst(".", name)) + # name starts with der(..) and name has a dot (".") + i = 5 + indexRange_old = 1:4 + while true + indexRange = findnext("der(", name, i) + if isnothing(indexRange) + j1 = indexRange_old.stop + j2 = findlast(".", name).stop + newName = name[j1+1:j2] * name[1:j1] * name[j2+1:end] + return newName + end + i = indexRange[2]+1 + indexRange_old = indexRange + end + @error("moveDerToLeaf($name): Error should not occur") + end + return name +end + + function performConsistencyCheck(G, Avar, vActive, parameters, unknowns, states, equations, log=false) nUnknowns = length(unknowns) - length(states) nEquations = length(equations) @@ -582,7 +620,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod stateSelectionFunctions = StateSelectionFunctions( - var_name = v -> stringVariables[v], + var_name = v -> moveDerToLeaf(stringVariables[v]), var_julia_name = v -> juliaVariables[v], var_unit = var_unit, var_startInitFixed = var_startInitFixed, @@ -723,7 +761,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # convertedStartValues = convert(Vector{FloatType}, [ustrip(v) for v in startValues]) # ustrip.(value) does not work for MonteCarloMeasurements # @show mappedParameters - + # println("Build SimulationModel") model = @timeit to "build SimulationModel" SimulationModel{FloatType,TimeType}(modelModule, name, buildDict, getDerivatives, equationInfo, previousVars, preVars, holdVars, @@ -890,7 +928,7 @@ function instantiateModel(model; modelName="", modelModule=nothing, source=nothi unitless=true printstyled(" @instantiateModel(...,unitless=true, ..) set automatically, because\n FloatType=MonteCarloMeasurements often fails if units are involved.\n", color=:red) end - + #try # model = JSONModel.cloneModel(model, expressionsAsStrings=false) println("\nInstantiating model $modelName\n in module: $modelModule\n in file: $source") diff --git a/test/TestFilterCircuit.jl b/test/TestFilterCircuit.jl index d95912f..95929cc 100644 --- a/test/TestFilterCircuit.jl +++ b/test/TestFilterCircuit.jl @@ -28,7 +28,7 @@ Modia.printResultInfo(filterCircuit) # Test access functions @testset "Test variable access functions (TestFilterCircuit.jl)" begin currentNames = signalNames(filterCircuit) - requiredNames = String["C.i", "C.n.i", "C.n.v", "C.p.i", "C.p.v", "C.v", "R.i", "R.n.i", "R.n.v", "R.p.i", "R.p.v", "R.v", "V.i", "V.n.i", "V.n.v", "V.p.i", "V.p.v", "V.v", "der(C.v)", "ground.p.i", "ground.p.v", "time"] + requiredNames = String["C.i", "C.n.i", "C.n.v", "C.p.i", "C.p.v", "C.v", "R.i", "R.n.i", "R.n.v", "R.p.i", "R.p.v", "R.v", "V.i", "V.n.i", "V.n.v", "V.p.i", "V.p.v", "V.v", "C.der(v)", "ground.p.i", "ground.p.v", "time"] @test sort!(currentNames) == sort!(requiredNames) @test hasSignal(filterCircuit, "R.v") diff --git a/test/TestHeatTransfer.jl b/test/TestHeatTransfer.jl index e903da9..1e481f6 100644 --- a/test/TestHeatTransfer.jl +++ b/test/TestHeatTransfer.jl @@ -36,6 +36,6 @@ HeatedRod = Model( heatedRod = @instantiateModel(HeatedRod) simulate!(heatedRod, stopTime = 1e5, log=true, requiredFinalStates = [492.9629728925529, 492.607421697723, 492.30480548105595, 492.0850627579106, 491.9694736486912]) -plot(heatedRod, [("fixedT.port.T", "rod.T"), "der(rod.T)"], figure=2) +plot(heatedRod, [("fixedT.port.T", "rod.T"), "rod.der(T)"], figure=2) end diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 14399f8..418cb4a 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -151,7 +151,7 @@ function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationMode @assert(size(ls.A,2) == size(ls.A,1)) @assert(size(ls.B,2) == lsBuild.nu) @assert(size(ls.C,1) == lsBuild.ny) - ls.x_hidden_startIndex = Modia.addHiddenState!(partiallyInstantiatedModel.equationInfo, path*".x", "der("*path*".x)", ls.x_init) + ls.x_hidden_startIndex = Modia.addHiddenState!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) lsBuild.ls = ls return nothing end @@ -229,7 +229,7 @@ printResultInfo(ssTest2) plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), ("submodel.ss.u", "ss.u", "y1", "y2"), - ("der(submodel.ss.x)", "der(submodel.x1)", "der(submodel.x2)", "der(submodel.x3)", "der(submodel.x4)", "der(ss.x)")], figure=3) + ("submodel.ss.der(x)", "submodel.der(x1)", "submodel.der(x2)", "submodel.der(x3)", "submodel.der(x4)", "ss.der(x)")], figure=3) simulate!(ssTest2, stopTime=1.0, log=false, logStates=true, merge = Map(submodel = Map(x4 = [0.85]), @@ -254,6 +254,6 @@ showEvaluatedParameters(ssTest2) plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), ("submodel.ss.u", "ss.u", "y1", "y2"), - ("der(submodel.ss.x)", "der(submodel.x1)", "der(submodel.x2)", "der(submodel.x3)", "der(submodel.x4)", "der(ss.x)")], figure=4, maxLegend=12) + ("submodel.ss.der(x)", "submodel.der(x1)", "submodel.der(x2)", "submodel.der(x3)", "submodel.der(x4)", "ss.der(x)")], maxLegend=12, figure=4) end \ No newline at end of file diff --git a/test/runtests_withPlot.jl b/test/runtests_withPlot.jl index ecf0d5c..c09a2b5 100644 --- a/test/runtests_withPlot.jl +++ b/test/runtests_withPlot.jl @@ -7,7 +7,7 @@ const test_title = "Test Modia (version=$(Modia.Version) with " * currentPlotPa println("\n... $test_title") -@testset "$test_title" begin +@time @testset verbose=true "$test_title" begin include("include_all.jl") end From ec919846675df4a2a11d35c6ee608dab5cec427f Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 20 May 2022 20:50:43 +0200 Subject: [PATCH 24/63] New functions to add extra results from within functions that are not visible in the generated code. --- docs/src/index.md | 3 + src/CodeGeneration.jl | 204 +++++++++++++++++++++++++++--------- src/EquationAndStateInfo.jl | 6 +- src/Modia.jl | 12 +-- src/ModiaLang.jl | 18 ++-- src/SimulateAndPlot.jl | 27 +++-- test/TestLinearSystems.jl | 80 ++++++++------ 7 files changed, 244 insertions(+), 106 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 0a9b603..56179a1 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -42,6 +42,9 @@ functionalities of these packages. get parameter/init/start values by name (e.g. `getEvaluatedParameter(instantiatedModel, "a.b.c")`) or show all parameters. For details see the [function docu](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html). +- New functions to add hidden states and extra results from within functions that are not visible in the generated code: + `Modia.newHiddenState!, Modia.newExtraResult!, Modia.addHiddenState!, Modia.addExtraResult!, Modia.storeResults`. + - Docu improved (e.g. links to utility functions documentation added) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 13e7554..6e143b8 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -235,22 +235,24 @@ end """ - @enum ResultStore RESULT_VARS RESULT_X RESULT_DER_X RESULT_ZERO + @enum ResultStore RESULT_CODE RESULT_EXTRA RESULT_X RESULT_DER_X RESULT_ZERO SimulationModel field name where result is stored: -- RESULT_VARS : stored in `result_vars` +- RESULT_CODE : stored in `result_code` (variables known before code is compiled) +- RESULT_EXTRA: stored in `result_extra` (variables known after code is compiled) - RESULT_X : stored in `result_x` (return argument of DifferentialEquations.solve(...)) - RESULT_DER_X: stored in `result_der_x` - RESULT_ZERO : value is zero """ -@enum ResultStore RESULT_VARS RESULT_X RESULT_DER_X RESULT_ZERO +@enum ResultStore RESULT_CODE RESULT_EXTRA RESULT_X RESULT_DER_X RESULT_ZERO struct ResultInfo store::ResultStore # Location where variable is stored index::Int # Index, depending on store-type - # store = RESULT_VARS : result_vars[ti][index] + # store = RESULT_CODE : result_code[ti][index] + # = RESULT_EXTRA: result_extra[ti][index] # = RESULT_X : result_x[ti][ibeg:iend] # ibeg = equationInfo.x_info[index].startIndex # iend = ibeg + equationInfo.x_info[index].length-1 @@ -344,15 +346,19 @@ mutable struct SimulationModel{FloatType,TimeType} result_info::OrderedDict{String,ResultInfo} # key : Full path name of result variables # value: Storage location and index into the storage. - result_vars::AbstractVector # result_vars[ti][j] is result of variable with index j at time instant ti + result_code::Vector{Tuple} # result_code[ti][j] is result of variable with index j at time instant ti + n_result_code::Int # Number of result_code variables + result_extra::Vector{Vector{Any}} # result_extra[ti][j] is extra result of variable with index j at time instant ti + result_extra_info::OrderedDict{String,ResultInfo} # Extra result variables info (needed to remove extra results before a simulate!(..., merge=...)) + result_extra_temp::Vector{Any} # Memory to store temporarily references to extra results; length(result_extra_temp) = length(result_extra_info) result_x::Union{Any,Missing} # Return value of DifferentialEquations.solve(..) (is a struct) result_der_x::Vector{Vector{FloatType}} # result_der_x[ti][j] is der_x[j] at time instant ti - parameters::OrderedDict{Symbol,Any} + parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor # Available after propagateEvaluateAndInstantiate!(..) called - evaluatedParameters::OrderedDict{Symbol,Any} - nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) + evaluatedParameters::OrderedDict{Symbol,Any} # Evaluated parameters + nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) nextPre::AbstractVector nextHold::AbstractVector @@ -416,10 +422,14 @@ mutable struct SimulationModel{FloatType,TimeType} success = false # Result data structure - result_info = OrderedDict{String, ResultInfo}() - result_vars = Tuple[] - result_x = missing - result_der_x = Vector{FloatType}[] + result_info = OrderedDict{String, ResultInfo}() + result_code = Tuple[] + n_result_code = length(variableNames) + result_extra = Vector{Any}[] + result_extra_info = OrderedDict{String, ResultInfo}() + result_extra_temp = Any[] + result_x = missing + result_der_x = Vector{FloatType}[] parameters = deepcopy(parameterDefinition) obj = new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!, @@ -430,7 +440,7 @@ mutable struct SimulationModel{FloatType,TimeType} hold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, odeIntegrator, daeCopyInfo, algorithmName, addEventPointsDueToDEBug, success, unitless, - result_info, result_vars, result_x, result_der_x, parameters) + result_info, result_code, n_result_code, result_extra, result_extra_info, result_extra_temp, result_x, result_der_x, parameters) evaluatedParameters = propagateEvaluateAndInstantiate!(obj, log=false) if isnothing(evaluatedParameters) @@ -454,19 +464,21 @@ mutable struct SimulationModel{FloatType,TimeType} obj.der_x_full = zeros(FloatType,nx) # Define result - # Store x and der_x - for (xe_index, xe_info) in enumerate(equationInfo.x_info) + # Store visible x and der_x + for xe_index = 1:equationInfo.nx_infoVisible + xe_info = equationInfo.x_info[xe_index] result_info[xe_info.x_name] = ResultInfo(RESULT_X, xe_index) end - for (xe_index, xe_info) in enumerate(equationInfo.x_info) + for xe_index = 1:equationInfo.nx_infoVisible + xe_info = equationInfo.x_info[xe_index] result_info[xe_info.der_x_name] = ResultInfo(RESULT_DER_X, xe_index) end - - # Store variables + + # Store result_code variables for (i, name) in enumerate(variableNames) str_name = string(name) if !haskey(result_info, str_name) - result_info[str_name] = ResultInfo(RESULT_VARS, i) + result_info[str_name] = ResultInfo(RESULT_CODE, i) end end @@ -485,6 +497,9 @@ mutable struct SimulationModel{FloatType,TimeType} end end + # Add hidden states/state derivatives and extra results + addHiddenStatesAndExtraResultsTo_result_info!(obj) + return obj end @@ -521,7 +536,8 @@ mutable struct SimulationModel{FloatType,TimeType} isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, true, LinearEquationsCopyInfoForDAEMode[], odeIntegrator, daeCopyInfo, addEventPointsDueToDEBug, success, m.unitless, - m.result_info, Tuple[], missing, Vector{FloatType}[], + m.result_info, Tuple[], m.n_result_code, Vector{Any}[], deepcopy(m.result_extra_info), + Vector{Any}(nothing,length(m.result_extra_info)), missing, Vector{FloatType}[], deepcopy(m.parameters), deepcopy(m.evaluatedParameters), deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), zeros(FloatType,0), deepcopy(m.x_vec), @@ -550,7 +566,8 @@ pre( m::SimulationModel, i) = m.pre[i] function emptyResult!(m::SimulationModel)::Nothing - empty!(m.result_vars) + empty!(m.result_code) + empty!(m.result_extra) empty!(m.result_der_x) m.result_x = missing return nothing @@ -565,7 +582,7 @@ end """ - x_hidden_startIndex = addHiddenState!( + x_hidden_startIndex = newHiddenState!( m::SimulationModel, x_name::String, der_x_name::String, @@ -577,7 +594,7 @@ end Add new hidden state to instantiated model and return its index that allows fast copying to x and der(x) vectors. """ -addHiddenState!(m::SimulationModel, +newHiddenState!(m::SimulationModel, x_name::String, der_x_name::String, startOrInit; @@ -585,17 +602,17 @@ addHiddenState!(m::SimulationModel, unit::String = "", fixed::Bool = true, nominal::Float64 = NaN, - unbounded::Bool = false)::Int = addHiddenState!(m.equationInfo, x_name, der_x_name, startOrInit; - stateCategory = stateCategory, unit = unit, fixed = fixed, + unbounded::Bool = false)::Int = newHiddenState!(m.equationInfo, x_name, der_x_name, startOrInit; + stateCategory = stateCategory, unit = unit, fixed = fixed, nominal = nominal, unbounded = unbounded) - - + + """ - copyFromHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{FloatType}) + addHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{FloatType}) Copy state from `m` at index `x_hidden_startIndex` into pre-allocated vector `xi`. """ -@inline function copyFromHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} +@inline function addHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} copyto!(xi, 1, m.x_hidden, x_hidden_startIndex, length(xi)) return nothing end @@ -792,8 +809,14 @@ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit return nothing end - if resInfo.store == RESULT_VARS - value = m.result_vars[end][resInfo.index] + if resInfo.store == RESULT_CODE + value = m.result_code[end][resInfo.index] + if !unit + value = stripUnit(value) + end + + elseif resInfo.store == RESULT_EXTRA + value = m.result_extra[end][resInfo.index] if !unit value = stripUnit(value) end @@ -1157,7 +1180,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters if length(m.options.merge) > 0 - removeHiddenStates!(m.equationInfo) + removeHiddenStatesAndExtraResults!(m) removeHiddenCrossingFunctions!(m.eventHandler) m.parameters = mergeModels(m.parameters, m.options.merge) evaluatedParameters = propagateEvaluateAndInstantiate!(m) @@ -1175,22 +1198,15 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti resize!(m.der_x_full , nx) eqInfo = m.equationInfo m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible] + addHiddenStatesAndExtraResultsTo_result_info!(m) end # Initialize auxiliary arrays for event iteration - m.x_init .= 0 - m.der_x_visible .= 0 - m.der_x_hidden .= 0 - m.der_x_full .= 0 - #= - @show m.equationInfo.nx - @show m.x_vec - @show m.x_start - @show m.x_init - @show m.der_x_visible - @show m.der_x_hidden - @show m.equationInfo - =# + m.x_init .= FloatType(0) + m.der_x_visible .= FloatType(0) + m.x_hidden .= FloatType(0) + m.der_x_hidden .= FloatType(0) + m.der_x_full .= FloatType(0) # Log parameters if m.options.logParameters @@ -1462,14 +1478,14 @@ function affectEvent!(integrator, stateEvent::Bool, eventIndex::Int)::Nothing sol_t = integrator.sol.t sol_x = integrator.sol.u ilast = length(sol_t) - for i = length(m.result_vars)+1:ilast # -1 + for i = length(m.result_code)+1:ilast # -1 outputs!(sol_x[i], sol_t[i], integrator) end # A better solution is needed. #if sol_t[ilast] == sol_t[ilast-1] # # Continuous time instant is present twice because "saveat" and "DiscreteCallback" occur at the same time instant # # Do not compute the model again - # push!(m.result_vars , m.result_vars[end]) + # push!(m.result_code , m.result_code[end]) # push!(m.result_der_x, m.result_der_x[end]) #else # outputs!(sol_x[ilast], sol_t[ilast], integrator) @@ -1655,11 +1671,101 @@ Add `variableValues...` to `simulationModel::SimulationModel`. It is assumed that the first variable in `variableValues` is `time`. """ @inline function addToResult!(m::SimulationModel, variableValues...)::Nothing - push!(m.result_vars , deepcopy(variableValues)) + @assert(length(variableValues) == m.n_result_code) + push!(m.result_code , deepcopy(variableValues)) + push!(m.result_extra, deepcopy(m.result_extra_temp)) + return nothing +end + + +""" + addHiddenStatesAndExtraResultsTo_result_info!(simulationModel) + +Add hidden states and its derivatives, as well as extra results to result_info. +""" +function addHiddenStatesAndExtraResultsTo_result_info!(m::SimulationModel)::Nothing + result_info = m.result_info + + # Add hidden x and der_x to result_info + eqInfo = m.equationInfo + for xe_index = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) + xe_info = eqInfo.x_info[xe_index] + result_info[xe_info.x_name] = ResultInfo(RESULT_X, xe_index) + end + for xe_index = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) + xe_info = eqInfo.x_info[xe_index] + result_info[xe_info.der_x_name] = ResultInfo(RESULT_DER_X, xe_index) + end + + # Add extra results to result_info + merge!(result_info, m.result_extra_info) + resize!(m.result_extra_temp, length(m.result_extra_info)) + m.result_extra_temp .= nothing + + return nothing +end + + +""" + removeHiddenStatesAndExtraResults!(simulationModel) + +Remove hidden states, their derivatives, as well as extra result from result_info, +and remove hidden states from equationInfo. +""" +function removeHiddenStatesAndExtraResults!(m::SimulationModel)::Nothing + # Remove hiddens states and their derivatives from result_info + x_info = m.equationInfo.x_info + for xe_index = m.equationInfo.nx_infoVisible+1:length(x_info) + delete!(m.result_info, x_info[xe_index].x_name) + delete!(m.result_info, x_info[xe_index].der_x_name) + end + + # Remove hidden states from equationInfo + removeHiddenStates!(m.equationInfo) + + # Remove extra results from result_info + for (name,index) in m.result_extra_info + delete!(m.result_info, name) + end + empty!(m.result_extra_info) + m.result_extra_temp .= nothing + resize!(m.result_extra_temp , 0) return nothing end + +""" + extraResult_index = newExtraResult!(partiallyInstantiatedModel::SimulationModel, name::String)::Int + +Reserve storage location for one extra result variable. The returned extraResult_index is +used to store extra results at communication points in the result data structure. +""" +function newExtraResult!(m::SimulationModel, name::String)::Int + if haskey(m.result_info, name) || haskey(m.result_extra_info, name) + error("Trying to add extra result variable $name but this name is already in use!") + end + extraResult_index = length(m.result_extra_info)+1 + m.result_extra_info[name] = ResultInfo(RESULT_EXTRA, extraResult_index) + return extraResult_index +end + + +""" + addExtraResult!(instantiatedModel::SimulationModel, extraResult_index::Int, extraResult)::Nothing + +Store deepcopy(extraResult) at extraResult_index in instantiatedModel. +""" +@inline function addExtraResult!(m::SimulationModel, extraResult_index::Int, extraResult)::Nothing + m.result_extra_temp[extraResult_index] = extraResult + return nothing +end + + + + + + """ code = generate_getDerivatives!(AST, equationInfo, parameters, variables, functionName; hasUnits=false) @@ -1823,7 +1929,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati $(code_previous...) $(code_pre...) - if _m.storeResult + if Modia.storeResults(_m) Modia.TimerOutputs.@timeit _m.timer "Modia addToResult!" Modia.addToResult!(_m, $(variables...)) end return nothing diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 98be34f..03593ef 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -647,7 +647,7 @@ mutable struct EquationInfo nxVisible::Int # = number of visible x-elements (so x[1:nxVisible] are visible states) or -1 if not yet known # This variable is updated once all states are known. nxHidden::Int # = number of hidden x-elements (x[nxVisible+1:nxVisible+nxHidden]. - # This variable is always updated consistently via function addHiddenState!(..) + # This variable is always updated consistently via function newHiddenState!(..) # (nxHidden=0, if there are no hidden states yet). nx_infoFixed::Int # x_info[1:nx_infoFixed] are states with fixed length (does not change after compilation) or -1 if not yet known nx_infoVisible::Int # x_info[1:nx_infoVisible] are states that are visible in getDerivatives!(..) or -1 if not yet known @@ -720,7 +720,7 @@ function initEquationInfo!(eqInfo::EquationInfo, nx_infoFixed::Int)::Nothing end -function addHiddenState!( +function newHiddenState!( eqInfo::EquationInfo, x_name::String, der_x_name::String, @@ -786,7 +786,7 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa if length(x_info) == 0 # Handle systems with only algebraic variables, by introducing a dummy # differential equation der_x[1] = -x[1], with state name _dummy_x - addHiddenState!(eqInfo, "_dummy_x", "der(_dummy_x)", FloatType(0.0)) + newHiddenState!(eqInfo, "_dummy_x", "der(_dummy_x)", FloatType(0.0)) startIndex = 1 elseif nx_infoFixed == 0 startIndex = 1 diff --git a/src/Modia.jl b/src/Modia.jl index ce63e98..5844c0b 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-05-19" +const Date = "2022-05-20" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -132,7 +132,7 @@ v2 = eval(code) ``` # Notes -Transforms unit to string representation that is parseable again +Transforms unit to string representation that is parseable again (see also Unitful [issue 412](https://github.com/PainterQubits/Unitful.jl/issues/412)). This implementation is a hack and only works in common cases. Implementation is performed in the following way: @@ -144,7 +144,7 @@ unitAsString(unitOfQuantity::Unitful.FreeUnits) = replace(repr(unitOfQuantity,co """ quantityType = quantity(numberType, numberUnit::Unitful.FreeUnits) - + Return the quantity type given the numberType and the numberUnit. # Example @@ -154,17 +154,17 @@ mutable struct Data{FloatType <: AbstractFloat} end v = Data{Float64}(2.0u"mm/s") -@show v # v = +@show v # v = ``` """ -quantity(numberType, numberUnit::Unitful.FreeUnits) = Quantity{numberType, dimension(numberUnit), typeof(numberUnit)} +quantity(numberType, numberUnit::Unitful.FreeUnits) = Quantity{numberType, dimension(numberUnit), typeof(numberUnit)} quantityTypes(::Type{Unitful.Quantity{T,D,U}}) where {T,D,U} = (T,D,U) """ str = modelPathAsString(modelPath::Union{Expr,Symbol,Nothing}) - + Return modelPath of submodel as string. """ modelPathAsString(modelPath::Union{Expr,Symbol,Nothing}) = isnothing(modelPath) ? "" : string(modelPath) diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index e95f19e..f569a1a 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -715,21 +715,21 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod holdVars = Symbol.(holdVars) # Variables added to result - extraResults = vcat(:time, setdiff([Symbol(u) for u in unknowns], - [Symbol(h) for h in hideResults], - Symbol[Symbol(xi_info.x_name_julia) for xi_info in equationInfo.x_info], - Symbol[Symbol(xi_info.der_x_name_julia) for xi_info in equationInfo.x_info])) + result_code_names = vcat(:time, setdiff([Symbol(u) for u in unknowns], + [Symbol(h) for h in hideResults], + Symbol[Symbol(xi_info.x_name_julia) for xi_info in equationInfo.x_info], + Symbol[Symbol(xi_info.der_x_name_julia) for xi_info in equationInfo.x_info])) if true # logTiming # println("Generate code") if useNewCodeGeneration - @timeit to "generate_getDerivativesNew!" code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], vcat(:time, [Symbol(u) for u in unknowns]), previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) + @timeit to "generate_getDerivativesNew!" code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], result_code_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) else - @timeit to "generate_getDerivatives!" code = generate_getDerivatives!(FloatType, TimeType, AST, equationInfo, [:(_p)], extraResults, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) + @timeit to "generate_getDerivatives!" code = generate_getDerivatives!(FloatType, TimeType, AST, equationInfo, [:(_p)], result_code_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) end else -# code = generate_getDerivatives!(AST, equationInfo, Symbol.(keys(parameters)), extraResults, :getDerivatives, hasUnits = !unitless) - code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], extraResults, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) +# code = generate_getDerivatives!(AST, equationInfo, Symbol.(keys(parameters)), result_code_names, :getDerivatives, hasUnits = !unitless) + code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], result_code_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) end if logCode #@show mappedParameters @@ -765,7 +765,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # println("Build SimulationModel") model = @timeit to "build SimulationModel" SimulationModel{FloatType,TimeType}(modelModule, name, buildDict, getDerivatives, equationInfo, previousVars, preVars, holdVars, - mappedParameters, extraResults; + mappedParameters, result_code_names; vSolvedWithInitValuesAndUnit, vEliminated, vProperty, var_name = (v)->string(unknownsWithEliminated[v]), nz=nCrossingFunctions, nAfter=nAfter, unitless=unitless) diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 1031f07..a0f60e4 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -228,7 +228,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me # Initialize/re-initialize SimulationModel if m.options.log || m.options.logEvaluatedParameters || m.options.logStates - println("... Simulate model ", m.modelName) + println("\n... Simulate model ", m.modelName) end useRecursiveFactorizationUptoSize = m.options.useRecursiveFactorizationUptoSize @@ -305,7 +305,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end else # ODE integrator - m.odeIntegrator = true + m.odeIntegrator = true TimerOutputs.@timeit m.timer "DifferentialEquations.ODEProblem" problem = DifferentialEquations.ODEProblem{true}(derivatives!, m.x_init, tspan, m) end @@ -360,7 +360,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me sol_t = solution.t sol_x = solution.u m.storeResult = true - for i = length(m.result_vars)+1:length(sol_t) + for i = length(m.result_code)+1:length(sol_t) invokelatest_getDerivatives_without_der_x!(sol_x[i], m, sol_t[i]) end m.storeResult = false @@ -594,7 +594,7 @@ is defined in the instantiateModel that can be accessed and can be used for plot """ ModiaResult.hasSignal(m::SimulationModel, name::AbstractString) = begin # m.save_x_in_solution ? name == "time" || haskey(m.equationInfo.x_dict, name) : - if isnothing(m) || ismissing(m) || ismissing(m.result_x) || ismissing(m.result_vars) || ismissing(m.result_der_x) + if isnothing(m) || ismissing(m) || ismissing(m.result_x) || ismissing(m.result_code) || ismissing(m.result_extra) || ismissing(m.result_der_x) return false end haskey(m.result_info, name) || !ismissing(get_value(m.evaluatedParameters, name)) @@ -608,7 +608,7 @@ Return true if parameter `name` (for example `name = "a.b.c"`) is defined in the instantiateModel. """ hasParameter(m::SimulationModel, name::AbstractString) = begin - if isnothing(m) || ismissing(m) || ismissing(m.result_x) || ismissing(m.result_vars) || ismissing(m.result_der_x) + if isnothing(m) || ismissing(m) || ismissing(m.result_x) || ismissing(m.result_code) || ismissing(m.result_extra) || ismissing(m.result_der_x) return false end !ismissing(get_value(m.evaluatedParameters, name)) @@ -655,7 +655,7 @@ function showEvaluatedParameters(m::SimulationModel)::Nothing @showModel evaluatedParameters return nothing end - + """ names = signalNames(instantiatedModel::Modia.SimulationModel) @@ -683,7 +683,7 @@ end """ (timeSignal, signal, signalType) = ModiaResult.rawSignal(instantiatedModel, name) (timeSignal, signal, signalType) = Modia.rawSignal( instantiatedModel, name) - + Get raw signal of result from an instantiated model of Modia. """ function ModiaResult.rawSignal(m::SimulationModel, name::AbstractString) @@ -739,8 +739,17 @@ function ModiaResult.rawSignal(m::SimulationModel, name::AbstractString) end return ([tsig], [derxSig], ModiaResult.Continuous) - elseif resInfo.store == RESULT_VARS - signal = ModiaResult.SignalView(m.result_vars, resInfo.index, resInfo.negate) + elseif resInfo.store == RESULT_CODE + signal = ModiaResult.SignalView(m.result_code, resInfo.index, resInfo.negate) + if length(signal) != length(tsig) + lens = length(signal) + lent = length(tsig) + error("Bug in SimulateAndPlot.jl (rawSignal(..)): name=\"$name\",\nlength(signal) = $lens, length(tsig) = $lent") + end + return ([tsig], [signal], ModiaResult.Continuous) + + elseif resInfo.store == RESULT_EXTRA + signal = ModiaResult.SignalView(m.result_extra, resInfo.index, resInfo.negate) if length(signal) != length(tsig) lens = length(signal) lent = length(tsig) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 418cb4a..1045899 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -8,14 +8,15 @@ using Modia.Test @usingModiaPlot """ - ls = LinearStateSpace(; A, B, C, x_init=nothing) + ls = LinearStateSpace(; A, B, C, W=fill(0.0,0,0), x_init=nothing) Define a linear state space system Model: ```math \begin{aligned} \frac{dx}{dt} &= A*x + B*u \\ - y &= C*x + y &= C*x \\ + w &= W*x \end{aligned} ``` @@ -23,8 +24,8 @@ where - `x_init` is the optional vector of init-values. If not provided, zeros will be used. - The number of **inputs** (= `size(B,2)`) and **outputs** (= `size(C,1)`) is **fixed**, after @instantiateModel(..) was called. -- The number of **states** (= `size(A,1)`) can be **changed** before simulation starts, - by providing appropriate ``A,B,C`` matrices and `x_init` vector as `merge` values in `simulate!(..., merge = ...)`. +- The number of **states** (= `size(A,1)`) and the number of **extra outputs** (= `size(W,1)` can be **changed** before simulation starts, + by providing appropriate ``A,B,C,W`` matrices and `x_init` vector as `merge` values in `simulate!(..., merge = ...)`. # Example ``` @@ -34,14 +35,14 @@ using Modia # T*der(x) + x = u T = 0.2; SSTest = Model( - ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), # one state + ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], W=[1.1;;], x_init=[0.2]), # one state equations = :[ss.u = 2.0, y = ss.y[1]] ) ssTest = @instantiateModel(SSTest, logCode=false) simulate!(ssTest, stopTime=1.0, log=true, logStates=true) -plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) +plot(ssTest, ("ss.x", "ss.u", "y", "ss.w"), figure=1) simulate!(ssTest, stopTime=1.0, log=true, logStates=true, merge=Map(ss = Map(A=[-1/T 0.0; @@ -49,8 +50,9 @@ simulate!(ssTest, stopTime=1.0, log=true, logStates=true, B=[1.0/T; 1.0/T;;], C=[0.4 0.4;], + W=[1.1 1.2;], x_init=[0.2,0.4]))) # two states -plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) +plot(ssTest, ("ss.x", "ss.u", "y", "ss.w"), figure=2) ``` """ LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace!), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated @@ -60,15 +62,18 @@ LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace mutable struct LinearStateSpaceStruct{FloatType} path::String # Path name of instance x_hidden_startIndex::Int + w_extraResult_index::Int A::Matrix{FloatType} B::Matrix{FloatType} C::Matrix{FloatType} + W::Matrix{FloatType} x_init::Vector{FloatType} # Initial values of states y::Vector{FloatType} # Internal memory for y + w::Vector{FloatType} # Internal memory for w x::Vector{FloatType} # Internal memory for x der_x::Vector{FloatType} # Internal memory for der(x) - function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, + function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, W::AbstractMatrix = fill(FloatType(0),0,0), x_init::Union{AbstractVector,Nothing}=nothing, u::AbstractVector, y::AbstractVector, # Code generated with buildLinearStateSpace! provides start values of u and y. path::String, kwargs...) where {FloatType} @@ -83,11 +88,18 @@ mutable struct LinearStateSpaceStruct{FloatType} @assert(size(y,1) == size(C,1)) @assert(size(u,1) == size(B,2)) @assert(size(y,1) == size(C,1)) + if length(W) > 0 + @assert(size(W,2) == size(A,1)) + end + if !isnothing(x_init) + @assert(length(x_init) == size(A,1)) + end copyA = Matrix{FloatType}(deepcopy(A)) copyB = Matrix{FloatType}(deepcopy(B)) copyC = Matrix{FloatType}(deepcopy(C)) + copyW = length(W) > 0 ? Matrix{FloatType}(deepcopy(W)) : zeros(FloatType, 0, size(A,1)) copy_x_init = if isnothing(x_init); zeros(FloatType, size(A,1)) else Vector{FloatType}(deepcopy(x_init)) end - new(path, 0, copyA, copyB, copyC, copy_x_init, zeros(FloatType,size(C,1)), zeros(FloatType, size(A,1)), zeros(FloatType,size(A,1))) + new(path, 0, 0, copyA, copyB, copyC, copyW, copy_x_init, zeros(FloatType,size(C,1)), zeros(FloatType,size(W,1)), zeros(FloatType, size(A,1)), zeros(FloatType,size(A,1))) end end @@ -148,10 +160,10 @@ function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationMode end lsBuild::LinearStateSpaceBuild{FloatType} = partiallyInstantiatedModel.buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) - @assert(size(ls.A,2) == size(ls.A,1)) - @assert(size(ls.B,2) == lsBuild.nu) - @assert(size(ls.C,1) == lsBuild.ny) - ls.x_hidden_startIndex = Modia.addHiddenState!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) + ls.x_hidden_startIndex = Modia.newHiddenState!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) + if length(ls.W) > 0 + ls.w_extraResult_index = Modia.newExtraResult!(partiallyInstantiatedModel, path*".w") + end lsBuild.ls = ls return nothing end @@ -159,7 +171,12 @@ end function openLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls - Modia.copyFromHiddenState!(instantiatedModel, ls.x_hidden_startIndex, ls.x) + Modia.addHiddenState!(instantiatedModel, ls.x_hidden_startIndex, ls.x) + if Modia.storeResults(instantiatedModel) && length(ls.W) > 0 + # w = W*x + mul!(ls.w, ls.W, ls.x) + Modia.addExtraResult!(instantiatedModel, ls.w_extraResult_index, ls.w) + end return ls end @@ -169,7 +186,7 @@ function computeOutputs!(instantiatedModel, ls) end function computeStateDerivatives!(instantiatedModel, ls, u)::Bool - # ls.der_x .= ls.A*ls.x + ls.B*u + # der_x = A*x + B*u mul!(ls.der_x, ls.A, ls.x) mul!(ls.der_x, ls.B, u, 1.0, 1.0) Modia.copyToHiddenStateDerivative!(instantiatedModel, ls.x_hidden_startIndex, ls.der_x) @@ -179,7 +196,7 @@ end # T*der(x) + x = u T = 0.2; SSTest = Model( - ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), # one state + ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], W=[1.1;;], x_init=[0.2]), # one state equations = :[ss.u = [2.0], y = ss.y[1]] ) @@ -187,27 +204,30 @@ SSTest = Model( ssTest = @instantiateModel(SSTest, logCode=true) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, requiredFinalStates = [1.987867388853733]) Modia.printResultInfo(ssTest) -plot(ssTest, ("ss.x", "ss.u", "y"), figure=1) +plot(ssTest, ("ss.x", "ss.u","ss.w", "y"), figure=1) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, merge=Map(ss = Map(A=[-1/T 0.0; 0.0 -1/T], B=[1.0/T; 1.0/T;;], - C=[0.4 0.4;], - x_init=[0.2,0.4])), # two states + C=[0.5 0.5;], + W=[0.5 0.6; + 0.7 0.8; + 0.9 1.0], + x_init=[0.3,0.4])), # two states requiredFinalStates = [1.98786636233743, 1.9892145443000466]) Modia.printResultInfo(ssTest) -plot(ssTest, ("ss.x", "ss.u", "y"), figure=2) +plot(ssTest, ("ss.x", "ss.u", "y", "ss.w"), figure=2) -println("\n... Test init vectors of scalars, fixed-size, variable-size, hidden-size vectors") +println("\n\n... Test init vectors of scalars, fixed-size, variable-size, hidden-size vectors") T = 0.2 - + SSTest2 = Model( - submodel = Model( ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], x_init=[0.2]), - x1 = Var(init = 1.1), + submodel = Model( ss = LinearStateSpace(A=[-1.0/T;;], B=[1.0/T;;], C=[0.9;;], W=[1.1;;], x_init=[0.2]), + x1 = Var(init = 1.1), x3 = Var(init = SVector{3}(0.5, 0.6, 0.7)), x4 = Var(init = [0.8, 0.9]), equations = :[ der(x1) = -x1 @@ -221,18 +241,18 @@ SSTest2 = Model( C=[0.4 0.4;], x_init=[0.3,0.4]), equations = :[ss.u = [2.0], submodel.ss.u = [2.1], - y1 = ss.y[1], y2 = submodel.ss.y[1]] + y1 = ss.y[1], y2 = submodel.ss.y[1]] ) -ssTest2 = @instantiateModel(SSTest2, logCode=false) +ssTest2 = @instantiateModel(SSTest2, logCode=false) simulate!(ssTest2, stopTime=1.0, log=true, logStates=true) printResultInfo(ssTest2) plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), - ("submodel.ss.u", "ss.u", "y1", "y2"), + ("submodel.ss.u", "ss.u", "y1", "y2", "submodel.ss.w"), ("submodel.ss.der(x)", "submodel.der(x1)", "submodel.der(x2)", "submodel.der(x3)", "submodel.der(x4)", "ss.der(x)")], figure=3) simulate!(ssTest2, stopTime=1.0, log=false, logStates=true, - merge = Map(submodel = Map(x4 = [0.85]), + merge = Map(submodel = Map(x4 = [0.85]), ss = LinearStateSpace(A=[-1/T 0.0 0.0; 0.0 -1/T 0.0; 0.0 0.0 -1/T], @@ -241,7 +261,7 @@ simulate!(ssTest2, stopTime=1.0, log=false, logStates=true, 1.0/T;;], C=[0.5 0.5 0.5;], x_init=[0.35,0.45,0.55])) - ) + ) printResultInfo(ssTest2) println("\n... Check functions for parameters and signals") @@ -253,7 +273,7 @@ showEvaluatedParameters(ssTest2) @test getLastValue( ssTest2, "ss.x_init") == [0.35,0.45,0.55] plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), - ("submodel.ss.u", "ss.u", "y1", "y2"), + ("submodel.ss.u", "ss.u", "y1", "y2", "submodel.ss.w"), ("submodel.ss.der(x)", "submodel.der(x1)", "submodel.der(x2)", "submodel.der(x3)", "submodel.der(x4)", "ss.der(x)")], maxLegend=12, figure=4) end \ No newline at end of file From 003f3fa8e48551eca80e8e3da07dc2c35cbbbca5 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Mon, 23 May 2022 08:45:38 +0200 Subject: [PATCH 25/63] Internal changes (not relevant for user): - newExtraResult!(..., defaultExtraResult): Add argument defaultExtraResult and push! it on result_extra_temp - Rename addZeroCrossings to newZeroCrossing (for consistent naming convention) - New function getStateStartIndexFromHiddenStateStartIndex(..) --- src/CodeGeneration.jl | 22 +++++++++++++++------- src/Modia.jl | 2 +- test/TestLinearSystems.jl | 4 +++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 6e143b8..f49ea36 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -606,6 +606,13 @@ newHiddenState!(m::SimulationModel, stateCategory = stateCategory, unit = unit, fixed = fixed, nominal = nominal, unbounded = unbounded) +""" + x_startIndex = getStateStartIndexFromHiddenStateStartIndex(instantiatedModel::SimulationModel, x_hidden_startIndex) + +Return the startindex of hidden staten with respect to x-vector, given the startIndex with respect to the x_hidden vector. +""" +getStateStartIndexFromHiddenStateStartIndex(m::SimulationModel, x_hidden_startIndex::Int) = m.equationInfo.nxVisible + x_hidden_startIndex + """ addHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{FloatType}) @@ -1089,12 +1096,12 @@ getTime(m::SimulationModel) = m.time """ - zStartIndex = addZeroCrossings(instantiatedModel, nz) + zStartIndex = newZeroCrossings(instantiatedModel, nz) Add nz new zero crossing functions and return the start index with respect to instantiatedModel.eventHandler.z. """ -function addZeroCrossings(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} +function newZeroCrossings(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} eh = m.eventHandler zStartIndex = eh.nz + 1 eh.nz += nz @@ -1699,9 +1706,7 @@ function addHiddenStatesAndExtraResultsTo_result_info!(m::SimulationModel)::Noth # Add extra results to result_info merge!(result_info, m.result_extra_info) - resize!(m.result_extra_temp, length(m.result_extra_info)) - m.result_extra_temp .= nothing - + @assert(length(m.result_extra_info) == length(m.result_extra_temp)) return nothing end @@ -1736,17 +1741,20 @@ end """ - extraResult_index = newExtraResult!(partiallyInstantiatedModel::SimulationModel, name::String)::Int + extraResult_index = newExtraResult!(partiallyInstantiatedModel::SimulationModel, name::String, defaultExtraResult)::Int Reserve storage location for one extra result variable. The returned extraResult_index is used to store extra results at communication points in the result data structure. +Value defaultExtraResult is stored as default value for the extra result +(`addExtraResult!(.., extraResult)`: `defaultExtraResult` and `extraResult` must have the same type and size) """ -function newExtraResult!(m::SimulationModel, name::String)::Int +function newExtraResult!(m::SimulationModel, name::String, defaultExtraResult)::Int if haskey(m.result_info, name) || haskey(m.result_extra_info, name) error("Trying to add extra result variable $name but this name is already in use!") end extraResult_index = length(m.result_extra_info)+1 m.result_extra_info[name] = ResultInfo(RESULT_EXTRA, extraResult_index) + push!(m.result_extra_temp, defaultExtraResult) return extraResult_index end diff --git a/src/Modia.jl b/src/Modia.jl index 5844c0b..a74da20 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-05-20" +const Date = "2022-05-23" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 1045899..77ba824 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -162,7 +162,9 @@ function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationMode ls = LinearStateSpaceStruct{FloatType}(; path, model...) ls.x_hidden_startIndex = Modia.newHiddenState!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) if length(ls.W) > 0 - ls.w_extraResult_index = Modia.newExtraResult!(partiallyInstantiatedModel, path*".w") + # w = W*x_init + ls.w = ls.W*ls.x_init + ls.w_extraResult_index = Modia.newExtraResult!(partiallyInstantiatedModel, path*".w", ls.w) end lsBuild.ls = ls return nothing From 5c3d5cbd96e6c54037c6dfb88e41e362b498a089 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 24 May 2022 11:11:14 +0200 Subject: [PATCH 26/63] propagateEvaluateAndInstantiate!: Strip units in the problematic statement that is printed in case of an error, since printing with units is nearly unreadable. --- src/EvaluateParameters.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index c45d5b4..cb0757c 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -21,6 +21,7 @@ function getConstructorAsString(path, constructor, parameters):String elseif typeof(value) <: AbstractDict svalue = "..." # Do not show dictionaries, since too much output, especially due to pointers to Object3Ds else + value = ustrip.(value) svalue = string(value) if length(svalue) > 20 svalue = svalue[1:20] * "..." # Restrict the length of the output From 0cb498e08a4a68fa1a58d0a8797feb3d477e3d6a Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Thu, 26 May 2022 14:03:04 +0200 Subject: [PATCH 27/63] Tiny docu issue corrected --- src/EquationAndStateInfo.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 03593ef..68643d5 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -552,7 +552,7 @@ mutable struct StateElementInfo startIndex::Int # start index of state with respect to x-vector or -1 if not yet known x_hidden_startIndex::Int # start index of hidden state with respect to x_hidden vector # or -1, if it is no hidden state (for a hidden state, x_hidden_startIndex - # is consistently set when it is added via addHiddenState(..)). + # is consistently set when it is added via newHiddenState(..)). end From 3e244b8cf087131fd5d0402ec756a0310f86a95c Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 27 May 2022 08:51:58 +0200 Subject: [PATCH 28/63] simulate!: If requiredFinalStates is not correct, print also the maximum absolute value of the difference --- src/SimulateAndPlot.jl | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index a0f60e4..b6c7053 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -142,8 +142,10 @@ not called before (the signals in Python module matplotlib.pyplot intervene with are used for initialization and during simulation. - `requiredFinalStates`: is not `missing`: Test with `@test` whether the ODE state vector at the final time instant is in agreement to vector `requiredFinalStates` with respect - to some relative tolerance `requiredFinalStates_rtol`. If this is not the case, print the + to tolerances `requiredFinalStates_rtol, requiredFinalStates_atol`. If this is not the case, print the final state vector (so that it can be included with copy-and-paste in the simulate!(..) call). + If you checked that the result of the simulation is correct, use `requiredFinalStates = []` to get + a printout of the required final states and then copy it in your test. - `requiredFinalStates_rtol`: Relative tolerance used for `requiredFinalStates`. - `requiredFinalStates_atol`: Absolute tolerance used for `requiredFinalStates` (see atol in `?isapprox`) - `useRecursiveFactorizationUptoSize`: = 0: Linear equation systems A*v=b are solved with @@ -441,15 +443,17 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me else println("\nrequiredFinalStates_rtol = $rtol") println("requiredFinalStates_atol = $atol") + diff = requiredFinalStates-finalStates if length(requiredFinalStates) > 0 && typeof(requiredFinalStates[1]) <: Measurements.Measurement - println( "\nrequiredFinalStates = ", measurementToString(requiredFinalStates)) - printstyled("finalStates = ", measurementToString(finalStates), "\n\n", bold=true, color=:red) - printstyled("difference = ", measurementToString(requiredFinalStates-finalStates), "\n\n", bold=true, color=:red) + println( "\nrequiredFinalStates = ", measurementToString(requiredFinalStates)) + printstyled("finalStates = ", measurementToString(finalStates), "\n\n", bold=true, color=:red) + printstyled("difference = ", measurementToString(diff), "\n\n", bold=true, color=:red) else - println( "\nrequiredFinalStates = ", requiredFinalStates) - printstyled("finalStates = ", finalStates, "\n\n", bold=true, color=:red) - printstyled("difference = ", requiredFinalStates-finalStates, "\n\n", bold=true, color=:red) + println( "\nrequiredFinalStates = ", requiredFinalStates) + printstyled("finalStates = ", finalStates, "\n\n", bold=true, color=:red) + printstyled("difference = ", diff, "\n\n", bold=true, color=:red) end + printstyled("maximum(|difference|) = ", maximum(abs.(diff)), "\n\n", bold=true, color=:red) @test isapprox(finalStates, requiredFinalStates, rtol=rtol, atol=atol) end end From be443e4bbfef0e1cb9b20de5916f79b96398a5a1 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 29 May 2022 11:56:04 +0200 Subject: [PATCH 29/63] Fix a few tiny issues --- src/CodeGeneration.jl | 6 +++++- src/SimulateAndPlot.jl | 13 +++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index f49ea36..eb50c43 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -182,7 +182,11 @@ struct SimulationOptions{FloatType,TimeType} rawStopTime = get(kwargs, :stopTime, startTime) stopTime = convertTimeVariable(TimeType, rawStopTime) interval = convertTimeVariable(TimeType, get(kwargs, :interval , (stopTime - startTime)/500.0) ) - dtmax = convert(Float64, get(kwargs, :dtmax, 100*getValue(interval))) + dtmax = get(kwargs, :dtmax, 100*getValue(interval)) + if ismissing(dtmax) || isnothing(dtmax) + dtmax = 100*getValue(interval) + end + dtmax = convert(Float64, dtmax) desiredResultTimeUnit = unit(rawStopTime) interp_points = get(kwargs, :interp_points, 0) if interp_points < 0 diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index b6c7053..4238441 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -443,17 +443,22 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me else println("\nrequiredFinalStates_rtol = $rtol") println("requiredFinalStates_atol = $atol") - diff = requiredFinalStates-finalStates if length(requiredFinalStates) > 0 && typeof(requiredFinalStates[1]) <: Measurements.Measurement println( "\nrequiredFinalStates = ", measurementToString(requiredFinalStates)) printstyled("finalStates = ", measurementToString(finalStates), "\n\n", bold=true, color=:red) - printstyled("difference = ", measurementToString(diff), "\n\n", bold=true, color=:red) + if length(finalStates) == length(requiredFinalStates) + printstyled("difference = ", measurementToString(requiredFinalStates-finalStates), "\n\n", bold=true, color=:red) + end else println( "\nrequiredFinalStates = ", requiredFinalStates) printstyled("finalStates = ", finalStates, "\n\n", bold=true, color=:red) - printstyled("difference = ", diff, "\n\n", bold=true, color=:red) + if length(finalStates) == length(requiredFinalStates) + printstyled("difference = ", requiredFinalStates-finalStates, "\n\n", bold=true, color=:red) + end + end + if length(finalStates) == length(requiredFinalStates) + printstyled("maximum(|difference|) = ", maximum(abs.(requiredFinalStates-finalStates)), "\n\n", bold=true, color=:red) end - printstyled("maximum(|difference|) = ", maximum(abs.(diff)), "\n\n", bold=true, color=:red) @test isapprox(finalStates, requiredFinalStates, rtol=rtol, atol=atol) end end From 2f53a8e7d40cfbd294ad9016f01aebefec1cd0f0 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Mon, 30 May 2022 12:48:58 +0200 Subject: [PATCH 30/63] =?UTF-8?q?-=20simulate!(..):=20restructured=20-=20s?= =?UTF-8?q?imulate!(..):=20maximum=20number=20of=20iterations=20is=20switc?= =?UTF-8?q?hed=20off=20(DifferentialEquations.jl=20option=20set=20to:=20ma?= =?UTF-8?q?xiters=20=3D=20Int(typemax(Int32))=20=E2=89=88=202e9;=20typemax?= =?UTF-8?q?(Int)=20would=20give=20an=20inexact=20error=20in=20Sundials).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/index.md | 4 +- src/CodeGeneration.jl | 21 +- src/Modia.jl | 2 +- src/SimulateAndPlot.jl | 460 +++++++++++++++++++++-------------------- 4 files changed, 252 insertions(+), 235 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 56179a1..d0034e0 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -44,7 +44,9 @@ functionalities of these packages. - New functions to add hidden states and extra results from within functions that are not visible in the generated code: `Modia.newHiddenState!, Modia.newExtraResult!, Modia.addHiddenState!, Modia.addExtraResult!, Modia.storeResults`. - + +- simulate!(..): Maximum number of iterations is switched off (DifferentialEquations.jl option set to: maxiters = Int(typemax(Int32)) ≈ 2e9). + - Docu improved (e.g. links to utility functions documentation added) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index eb50c43..c066f91 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -140,12 +140,13 @@ convertTimeVariable(Float32, 2.0u"hr") # = 7200.0f0 convertTimeVariable(TimeType, t) = typeof(t) <: Unitful.AbstractQuantity ? convert(TimeType, stripUnit(t)) : convert(TimeType, t) -struct SimulationOptions{FloatType,TimeType} +mutable struct SimulationOptions{FloatType,TimeType} merge::OrderedDict{Symbol,Any} tolerance::Float64 - startTime::TimeType # u"s" - stopTime::TimeType # u"s" - interval::TimeType # u"s" + startTimeFirstSegment::TimeType # u"s"; startTime of first segment + startTime::TimeType # u"s"; startTime of actual segment + stopTime::TimeType # u"s" + interval::TimeType # u"s" desiredResultTimeUnit interp_points::Int dtmax::Float64 @@ -178,7 +179,8 @@ struct SimulationOptions{FloatType,TimeType} "tolerance changed to $newTolerance.\n\n", bold=true, color=:red) tolerance = newTolerance end - startTime = convertTimeVariable(TimeType, get(kwargs, :startTime, 0.0) ) + startTimeFirstSegment = convertTimeVariable(TimeType, get(kwargs, :startTime, 0.0) ) + startTime = startTimeFirstSegment rawStopTime = get(kwargs, :stopTime, startTime) stopTime = convertTimeVariable(TimeType, rawStopTime) interval = convertTimeVariable(TimeType, get(kwargs, :interval , (stopTime - startTime)/500.0) ) @@ -226,7 +228,7 @@ struct SimulationOptions{FloatType,TimeType} end # obj = new(isnothing(merge) ? NamedTuple() : merge, tolerance, startTime, stopTime, interval, desiredResultTimeUnit, interp_points, - obj = new(ismissing(merge) || isnothing(merge) ? OrderedDict{Symbol,Any}() : merge, tolerance, startTime, stopTime, interval, desiredResultTimeUnit, interp_points, + obj = new(ismissing(merge) || isnothing(merge) ? OrderedDict{Symbol,Any}() : merge, tolerance, startTimeFirstSegment, startTime, stopTime, interval, desiredResultTimeUnit, interp_points, dtmax, adaptive, nlinearMinForDAE, log, logStates, logEvents, logProgress, logTiming, logParameters, logEvaluatedParameters, requiredFinalStates, requiredFinalStates_rtol, requiredFinalStates_atol, useRecursiveFactorizationUptoSize, extra_kwargs) return success ? obj : nothing @@ -341,6 +343,7 @@ mutable struct SimulationModel{FloatType,TimeType} daeCopyInfo::Vector{LinearEquationsCopyInfoForDAEMode} # Info to efficiently copy between DAE and linear equation systems algorithmName::Union{String,Missing} # Name of integration algorithm as string (used in default-heading of plot) + sundials::Bool # = true, if algorithm is a Sundials integrator addEventPointsDueToDEBug::Bool # = true, if event points are explicitly stored for Sundials integrators, due to bug in DifferentialEquations # (https://github.com/SciML/Sundials.jl/issues/309) success::Bool # = true, if after first outputs!(..) call and no error was triggered @@ -422,6 +425,7 @@ mutable struct SimulationModel{FloatType,TimeType} odeIntegrator = true daeCopyInfo = LinearEquationsCopyInfoForDAEMode[] algorithmName = missing + sundials = false addEventPointsDueToDEBug = false success = false @@ -443,7 +447,7 @@ mutable struct SimulationModel{FloatType,TimeType} pre, pre_names, pre_dict, hold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, - odeIntegrator, daeCopyInfo, algorithmName, addEventPointsDueToDEBug, success, unitless, + odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, result_info, result_code, n_result_code, result_extra, result_extra_info, result_extra_temp, result_x, result_der_x, parameters) evaluatedParameters = propagateEvaluateAndInstantiate!(obj, log=false) @@ -526,7 +530,6 @@ mutable struct SimulationModel{FloatType,TimeType} odeIntegrator = true daeCopyInfo = LinearEquationsCopyInfoForDAEMode[] algorithmName = missing - addEventPointsDueToDEBug = false success = false nx = m.equationInfo.nx @@ -539,7 +542,7 @@ mutable struct SimulationModel{FloatType,TimeType} deepcopy(m.hold), m.hold_names, m.hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, true, LinearEquationsCopyInfoForDAEMode[], - odeIntegrator, daeCopyInfo, addEventPointsDueToDEBug, success, m.unitless, + odeIntegrator, daeCopyInfo, m.sundials, m.addEventPointsDueToDEBug, success, m.unitless, m.result_info, Tuple[], m.n_result_code, Vector{Any}[], deepcopy(m.result_extra_info), Vector{Any}(nothing,length(m.result_extra_info)), missing, Vector{FloatType}[], deepcopy(m.parameters), deepcopy(m.evaluatedParameters), diff --git a/src/Modia.jl b/src/Modia.jl index a74da20..02aed9a 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-05-23" +const Date = "2022-05-30" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 4238441..d80a977 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -220,248 +220,131 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me return nothing end m.options = options - solution = nothing - - #try - if ismissing(algorithm) && FloatType == Float64 - algorithm = Sundials.CVODE_BDF() - end - m.algorithmName = getAlgorithmName(algorithm) - - # Initialize/re-initialize SimulationModel - if m.options.log || m.options.logEvaluatedParameters || m.options.logStates - println("\n... Simulate model ", m.modelName) - end - - useRecursiveFactorizationUptoSize = m.options.useRecursiveFactorizationUptoSize - for leq in m.linearEquations - leq.useRecursiveFactorization = length(leq.x) <= useRecursiveFactorizationUptoSize && length(leq.x) > 1 - end - - #TimerOutputs.@timeit m.timer "Modia.init!" success = init!(m) - if m.options.log || m.options.logTiming - @time (success = init!(m); if m.options.log || m.options.logTiming; print(" Initialization finished within") end) - else - success = init!(m) - end - if !success - @test false - return nothing - end - - enable_timer!(m.timer) - reset_timer!(m.timer) - TimerOutputs.@timeit m.timer "Modia.simulate!" begin - sizesOfLinearEquationSystems = Int[length(leq.b) for leq in m.linearEquations] + if ismissing(algorithm) && FloatType == Float64 + algorithm = Sundials.CVODE_BDF() + end + m.algorithmName = getAlgorithmName(algorithm) + m.sundials = !ismissing(algorithm) && (typeof(algorithm) <: Sundials.SundialsODEAlgorithm || typeof(algorithm) <: Sundials.SundialsDAEAlgorithm) + m.addEventPointsDueToDEBug = m.sundials - # Define problem and callbacks based on algorithm and model type - interval = m.options.interval - if abs(m.options.stopTime - m.options.startTime) <= 0 - interval = 1.0 - tspan2 = [m.options.startTime] - elseif abs(m.options.interval) < abs(m.options.stopTime-m.options.startTime) - tspan2 = m.options.startTime:m.options.interval:m.options.stopTime - else - tspan2 = [m.options.startTime, m.options.stopTime] - end - tspan = (m.options.startTime, m.options.stopTime) - - eh = m.eventHandler - m.odeMode = true - m.solve_leq = true - if typeof(algorithm) <: DifferentialEquations.DiffEqBase.AbstractDAEAlgorithm - # DAE integrator - m.odeIntegrator = false - nx = length(m.x_init) - differential_vars = eh.nz > 0 ? fill(true, nx) : nothing # due to DifferentialEquations issue #549 - copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) - TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x_full, m.x_init, tspan, m, differential_vars = differential_vars) - empty!(m.daeCopyInfo) - if length(sizesOfLinearEquationSystems) > 0 && maximum(sizesOfLinearEquationSystems) >= options.nlinearMinForDAE - # Prepare data structure to efficiently perform copy operations for DAE integrator - x_info = m.equationInfo.x_info - der_x_dict = m.equationInfo.der_x_dict - der_x_names = keys(der_x_dict) - for (ileq,leq) in enumerate(m.linearEquations) - if sizesOfLinearEquationSystems[ileq] >= options.nlinearMinForDAE && - length(intersect(leq.x_names,der_x_names)) == length(leq.x_names) - # Linear equation shall be solved by DAE and all unknowns of the linear equation system are DAE derivatives - leq.odeMode = false - m.odeMode = false - leq_copy = LinearEquationsCopyInfoForDAEMode(ileq) - for ix in 1:length(leq.x_names) - x_name = leq.x_names[ix] - x_length = leq.x_lengths[ix] - x_info_i = x_info[ der_x_dict[x_name] ] - @assert(x_length == x_info_i.length) - startIndex = x_info_i.startIndex - endIndex = startIndex + x_length - 1 - append!(leq_copy.index, startIndex:endIndex) - end - push!(m.daeCopyInfo, leq_copy) - else - leq.odeMode = true - end - end - end - else - # ODE integrator - m.odeIntegrator = true - TimerOutputs.@timeit m.timer "DifferentialEquations.ODEProblem" problem = DifferentialEquations.ODEProblem{true}(derivatives!, m.x_init, tspan, m) - end + # Initialize/re-initialize SimulationModel + if m.options.log || m.options.logEvaluatedParameters || m.options.logStates + println("\n... Simulate model ", m.modelName) + end - callback2 = DifferentialEquations.DiscreteCallback(timeEventCondition!, affectTimeEvent!) - if eh.nz > 0 - #println("\n!!! Callback set with crossing functions") - # Due to DifferentialEquations bug https://github.com/SciML/DifferentialEquations.jl/issues/686 - # FunctionalCallingCallback(outputs!, ...) is not correctly called when zero crossings are present. - # The fix is to call outputs!(..) from the previous to the current event, when an event occurs. - # (alternativey: callback4 = DifferentialEquations.PresetTimeCallback(tspan2, affect_outputs!) ) - callback1 = DifferentialEquations.FunctionCallingCallback(outputs!, funcat=[m.options.startTime]) # call outputs!(..) at startTime - callback3 = DifferentialEquations.VectorContinuousCallback(zeroCrossings!, - affectStateEvent!, eh.nz, interp_points=m.options.interp_points, rootfind=DifferentialEquations.SciMLBase.RightRootFind) - #callback4 = DifferentialEquations.PresetTimeCallback(tspan2, affect_outputs!) - callbacks = DifferentialEquations.CallbackSet(callback1, callback2, callback3) #, callback4) - else - #println("\n!!! Callback set without crossing functions") - callback1 = DifferentialEquations.FunctionCallingCallback(outputs!, funcat=tspan2) - callbacks = DifferentialEquations.CallbackSet(callback1, callback2) - end + useRecursiveFactorizationUptoSize = m.options.useRecursiveFactorizationUptoSize + for leq in m.linearEquations + leq.useRecursiveFactorization = length(leq.x) <= useRecursiveFactorizationUptoSize && length(leq.x) > 1 + end - # Initial step size (the default of DifferentialEquations is too large) + step-size of fixed-step algorithm - if !ismissing(algorithm) && (typeof(algorithm) <: Sundials.SundialsODEAlgorithm || - typeof(algorithm) <: Sundials.SundialsDAEAlgorithm) - sundials = true - else - sundials = false - dt = m.options.adaptive ? m.options.interval/10 : m.options.interval # initial step-size - end - m.addEventPointsDueToDEBug = sundials - - # Compute solution - abstol = 0.1*m.options.tolerance - tstops = (m.eventHandler.nextEventTime,) - m.cpuLast = time_ns() - m.cpuFirst = m.cpuLast - if ismissing(algorithm) - TimerOutputs.@timeit m.timer "DifferentialEquations.solve" solution = DifferentialEquations.solve(problem, reltol=m.options.tolerance, abstol=abstol, save_everystep=false, - callback=callbacks, adaptive=m.options.adaptive, saveat=tspan2, dt=dt, dtmax=m.options.dtmax, tstops = tstops, - initializealg = DifferentialEquations.NoInit()) - elseif sundials - TimerOutputs.@timeit m.timer "DifferentialEquations.solve" solution = DifferentialEquations.solve(problem, algorithm, reltol=m.options.tolerance, abstol=abstol, save_everystep=false, - callback=callbacks, adaptive=m.options.adaptive, saveat=tspan2, dtmax=m.options.dtmax, tstops = tstops, - initializealg = DifferentialEquations.NoInit()) - else - TimerOutputs.@timeit m.timer "DifferentialEquations.solve" solution = DifferentialEquations.solve(problem, algorithm, reltol=m.options.tolerance, abstol=abstol, save_everystep=false, - callback=callbacks, adaptive=m.options.adaptive, saveat=tspan2, dt=dt, dtmax=m.options.dtmax, tstops = tstops, - initializealg = DifferentialEquations.NoInit()) - end + if m.options.log || m.options.logTiming + @time (success = init!(m); if m.options.log || m.options.logTiming; print(" Initialization finished within") end) + else + success = init!(m) + end + if !success + @test false + return nothing + end - # Compute and store outputs from last event until final time - sol_t = solution.t - sol_x = solution.u - m.storeResult = true - for i = length(m.result_code)+1:length(sol_t) - invokelatest_getDerivatives_without_der_x!(sol_x[i], m, sol_t[i]) - end - m.storeResult = false + enable_timer!(m.timer) + reset_timer!(m.timer) + m.cpuLast = time_ns() + m.cpuFirst = m.cpuLast - # Final update of instantiatedModel - m.result_x = solution - if ismissing(algorithm) - m.algorithmName = getAlgorithmName(solution.alg) - end + solution = nothing + TimerOutputs.@timeit m.timer "Modia.simulate!" while true + solution = simulateSegment!(m, algorithm; merge=merge, kwargs...) + if m.eventHandler.restart != Modia.FullRestart + break + end + m.options.startTime = m.time + end - # Terminate simulation - finalStates = solution.u[end] - finalTime = solution.t[end] - terminate!(m, finalStates, finalTime) + disable_timer!(m.timer) - # Raise an error, if simulation was not successful - if !(solution.retcode == :Default || solution.retcode == :Success || solution.retcode == :Terminated) - error("\nsolution = simulate!(", m.modelName, ", ...) failed with solution.retcode = :$(solution.retcode) at time = $finalTime.\n") - end - end - disable_timer!(m.timer) + if !m.success + return nothing + end - if !m.success - return nothing + if m.options.log + eh = m.eventHandler + useRecursiveFactorization = Bool[leq.useRecursiveFactorization for leq in m.linearEquations] + println(" Termination of ", m.modelName, " at time = ", solution.t[end], " s") + println(" cpuTime (without init.) = ", round(TimerOutputs.time(m.timer["Modia.simulate!"])*1e-9, sigdigits=3), " s") + println(" allocated (without init.) = ", round(TimerOutputs.allocated(m.timer["Modia.simulate!"])/1048576.0, sigdigits=3), " MiB") + println(" algorithm = ", get_algorithmName_for_heading(m)) + println(" FloatType = ", FloatType) + println(" interval = ", m.options.interval, " s") + println(" tolerance = ", m.options.tolerance, " (relative tolerance)") + println(" nStates = ", length(m.x_start)) + println(" linearSystemSizes = ", Int[length(leq.b) for leq in m.linearEquations]) + println(" useRecursiveFactorization = ", useRecursiveFactorization) + println(" odeModeLinearSystems = ", Bool[leq.odeMode for leq in m.linearEquations]) + println(" nResults = ", length(m.result_x.t)) + println(" nGetDerivatives = ", m.nGetDerivatives, " (total number of getDerivatives! calls)") + println(" nf = ", m.nf, " (number of getDerivatives! calls from integrator)") # solution.destats.nf + println(" nZeroCrossings = ", eh.nZeroCrossings, " (number of getDerivatives! calls for zero crossing detection)") + + if m.sundials && (eh.nTimeEvents > 0 || eh.nStateEvents > 0) + # statistics is wrong, due to a bug in the Sundials.jl interface + println(" nJac = ??? (number of Jacobian computations)") + println(" nAcceptedSteps = ???") + println(" nRejectedSteps = ???") + println(" nErrTestFails = ???") + else + println(" nJac = ", solution.destats.njacs, " (number of Jacobian computations)") + println(" nAcceptedSteps = ", solution.destats.naccept) + println(" nRejectedSteps = ", solution.destats.nreject) + println(" nErrTestFails = ", solution.destats.nreject) end + println(" nTimeEvents = ", eh.nTimeEvents) + println(" nStateEvents = ", eh.nStateEvents) + println(" nRestartEvents = ", eh.nRestartEvents) + end + if m.options.logTiming + println("\n... Timings for simulation of ", m.modelName," (without initialization):") + TimerOutputs.print_timer(TimerOutputs.flatten(m.timer), compact=true) + end - if m.options.log - useRecursiveFactorization = Bool[leq.useRecursiveFactorization for leq in m.linearEquations] - println(" Termination of ", m.modelName, " at time = ", finalTime, " s") - println(" cpuTime (without init.) = ", round(TimerOutputs.time(m.timer["Modia.simulate!"])*1e-9, sigdigits=3), " s") - println(" allocated (without init.) = ", round(TimerOutputs.allocated(m.timer["Modia.simulate!"])/1048576.0, sigdigits=3), " MiB") - println(" algorithm = ", get_algorithmName_for_heading(m)) - println(" FloatType = ", FloatType) - println(" interval = ", m.options.interval, " s") - println(" tolerance = ", m.options.tolerance, " (relative tolerance)") - println(" nStates = ", length(m.x_start)) - println(" linearSystemSizes = ", sizesOfLinearEquationSystems) - println(" useRecursiveFactorization = ", useRecursiveFactorization) - println(" odeModeLinearSystems = ", Bool[leq.odeMode for leq in m.linearEquations]) - println(" nResults = ", length(m.result_x.t)) - println(" nGetDerivatives = ", m.nGetDerivatives, " (total number of getDerivatives! calls)") - println(" nf = ", m.nf, " (number of getDerivatives! calls from integrator)") # solution.destats.nf - println(" nZeroCrossings = ", eh.nZeroCrossings, " (number of getDerivatives! calls for zero crossing detection)") - - if sundials && (eh.nTimeEvents > 0 || eh.nStateEvents > 0) - # statistics is wrong, due to a bug in the Sundials.jl interface - println(" nJac = ??? (number of Jacobian computations)") - println(" nAcceptedSteps = ???") - println(" nRejectedSteps = ???") - println(" nErrTestFails = ???") - else - println(" nJac = ", solution.destats.njacs, " (number of Jacobian computations)") - println(" nAcceptedSteps = ", solution.destats.naccept) - println(" nRejectedSteps = ", solution.destats.nreject) - println(" nErrTestFails = ", solution.destats.nreject) - end - println(" nTimeEvents = ", eh.nTimeEvents) - println(" nStateEvents = ", eh.nStateEvents) - println(" nRestartEvents = ", eh.nRestartEvents) - end - if m.options.logTiming - println("\n... Timings for simulation of ", m.modelName," (without initialization):") - TimerOutputs.print_timer(TimerOutputs.flatten(m.timer), compact=true) + requiredFinalStates = m.options.requiredFinalStates + if !ismissing(requiredFinalStates) + finalStates = solution.u[end] + rtol = m.options.requiredFinalStates_rtol + atol = m.options.requiredFinalStates_atol + if length(finalStates) != length(requiredFinalStates) + success = false + else + success = isapprox(finalStates, requiredFinalStates, rtol=rtol, atol=atol) end - requiredFinalStates = m.options.requiredFinalStates - if !ismissing(requiredFinalStates) - rtol = m.options.requiredFinalStates_rtol - atol = m.options.requiredFinalStates_atol - if length(finalStates) != length(requiredFinalStates) - success = false - else - success = isapprox(finalStates, requiredFinalStates, rtol=rtol, atol=atol) - end - - if success - @test success - else - println("\nrequiredFinalStates_rtol = $rtol") - println("requiredFinalStates_atol = $atol") - if length(requiredFinalStates) > 0 && typeof(requiredFinalStates[1]) <: Measurements.Measurement - println( "\nrequiredFinalStates = ", measurementToString(requiredFinalStates)) - printstyled("finalStates = ", measurementToString(finalStates), "\n\n", bold=true, color=:red) - if length(finalStates) == length(requiredFinalStates) - printstyled("difference = ", measurementToString(requiredFinalStates-finalStates), "\n\n", bold=true, color=:red) - end - else - println( "\nrequiredFinalStates = ", requiredFinalStates) - printstyled("finalStates = ", finalStates, "\n\n", bold=true, color=:red) - if length(finalStates) == length(requiredFinalStates) - printstyled("difference = ", requiredFinalStates-finalStates, "\n\n", bold=true, color=:red) - end + if success + @test success + else + println("\nrequiredFinalStates_rtol = $rtol") + println("requiredFinalStates_atol = $atol") + if length(requiredFinalStates) > 0 && typeof(requiredFinalStates[1]) <: Measurements.Measurement + println( "\nrequiredFinalStates = ", measurementToString(requiredFinalStates)) + printstyled("finalStates = ", measurementToString(finalStates), "\n\n", bold=true, color=:red) + if length(finalStates) == length(requiredFinalStates) + printstyled("difference = ", measurementToString(requiredFinalStates-finalStates), "\n\n", bold=true, color=:red) end + else + println( "\nrequiredFinalStates = ", requiredFinalStates) + printstyled("finalStates = ", finalStates, "\n\n", bold=true, color=:red) if length(finalStates) == length(requiredFinalStates) - printstyled("maximum(|difference|) = ", maximum(abs.(requiredFinalStates-finalStates)), "\n\n", bold=true, color=:red) + printstyled("difference = ", requiredFinalStates-finalStates, "\n\n", bold=true, color=:red) end - @test isapprox(finalStates, requiredFinalStates, rtol=rtol, atol=atol) end + if length(finalStates) == length(requiredFinalStates) + printstyled("maximum(|difference|) = ", maximum(abs.(requiredFinalStates-finalStates)), "\n\n", bold=true, color=:red) + end + @test isapprox(finalStates, requiredFinalStates, rtol=rtol, atol=atol) end + end + + return solution #= catch e @@ -485,6 +368,135 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end end =# +end + + +function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; merge=nothing, kwargs...) where {FloatType,TimeType} + solution = nothing + + sizesOfLinearEquationSystems = Int[length(leq.b) for leq in m.linearEquations] + + # Define problem and callbacks based on algorithm and model type + interval = m.options.interval + if abs(m.options.stopTime - m.options.startTime) <= 0 + interval = 1.0 + tspan2 = [m.options.startTime] + elseif abs(m.options.interval) < abs(m.options.stopTime-m.options.startTime) + tspan2 = m.options.startTime:m.options.interval:m.options.stopTime + else + tspan2 = [m.options.startTime, m.options.stopTime] + end + tspan = (m.options.startTime, m.options.stopTime) + + eh = m.eventHandler + m.odeMode = true + m.solve_leq = true + if typeof(algorithm) <: DifferentialEquations.DiffEqBase.AbstractDAEAlgorithm + # DAE integrator + m.odeIntegrator = false + nx = length(m.x_init) + differential_vars = eh.nz > 0 ? fill(true, nx) : nothing # due to DifferentialEquations issue #549 + copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) + TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x_full, m.x_init, tspan, m, differential_vars = differential_vars) + empty!(m.daeCopyInfo) + if length(sizesOfLinearEquationSystems) > 0 && maximum(sizesOfLinearEquationSystems) >= options.nlinearMinForDAE + # Prepare data structure to efficiently perform copy operations for DAE integrator + x_info = m.equationInfo.x_info + der_x_dict = m.equationInfo.der_x_dict + der_x_names = keys(der_x_dict) + for (ileq,leq) in enumerate(m.linearEquations) + if sizesOfLinearEquationSystems[ileq] >= options.nlinearMinForDAE && + length(intersect(leq.x_names,der_x_names)) == length(leq.x_names) + # Linear equation shall be solved by DAE and all unknowns of the linear equation system are DAE derivatives + leq.odeMode = false + m.odeMode = false + leq_copy = LinearEquationsCopyInfoForDAEMode(ileq) + for ix in 1:length(leq.x_names) + x_name = leq.x_names[ix] + x_length = leq.x_lengths[ix] + x_info_i = x_info[ der_x_dict[x_name] ] + @assert(x_length == x_info_i.length) + startIndex = x_info_i.startIndex + endIndex = startIndex + x_length - 1 + append!(leq_copy.index, startIndex:endIndex) + end + push!(m.daeCopyInfo, leq_copy) + else + leq.odeMode = true + end + end + end + else + # ODE integrator + m.odeIntegrator = true + TimerOutputs.@timeit m.timer "DifferentialEquations.ODEProblem" problem = DifferentialEquations.ODEProblem{true}(derivatives!, m.x_init, tspan, m) + end + + callback2 = DifferentialEquations.DiscreteCallback(timeEventCondition!, affectTimeEvent!) + if eh.nz > 0 + #println("\n!!! Callback set with crossing functions") + # Due to DifferentialEquations bug https://github.com/SciML/DifferentialEquations.jl/issues/686 + # FunctionalCallingCallback(outputs!, ...) is not correctly called when zero crossings are present. + # The fix is to call outputs!(..) from the previous to the current event, when an event occurs. + # (alternativey: callback4 = DifferentialEquations.PresetTimeCallback(tspan2, affect_outputs!) ) + callback1 = DifferentialEquations.FunctionCallingCallback(outputs!, funcat=[m.options.startTime]) # call outputs!(..) at startTime + callback3 = DifferentialEquations.VectorContinuousCallback(zeroCrossings!, + affectStateEvent!, eh.nz, interp_points=m.options.interp_points, rootfind=DifferentialEquations.SciMLBase.RightRootFind) + #callback4 = DifferentialEquations.PresetTimeCallback(tspan2, affect_outputs!) + callbacks = DifferentialEquations.CallbackSet(callback1, callback2, callback3) #, callback4) + else + #println("\n!!! Callback set without crossing functions") + callback1 = DifferentialEquations.FunctionCallingCallback(outputs!, funcat=tspan2) + callbacks = DifferentialEquations.CallbackSet(callback1, callback2) + end + + # Initial step size (the default of DifferentialEquations integrators is too large) + step-size of fixed-step algorithm + if !m.sundials + dt = m.options.adaptive ? m.options.interval/10 : m.options.interval # initial step-size + end + + # Compute solution + abstol = 0.1*m.options.tolerance + tstops = (m.eventHandler.nextEventTime,) + maxiters = Int(typemax(Int32)) # switch off maximum number of iterations (typemax(Int) gives an inexact error for Sundials) + if ismissing(algorithm) + TimerOutputs.@timeit m.timer "DifferentialEquations.solve" solution = DifferentialEquations.solve(problem, reltol=m.options.tolerance, abstol=abstol, save_everystep=false, + callback=callbacks, adaptive=m.options.adaptive, saveat=tspan2, dt=dt, dtmax=m.options.dtmax, maxiters=maxiters, tstops = tstops, + initializealg = DifferentialEquations.NoInit()) + elseif m.sundials + TimerOutputs.@timeit m.timer "DifferentialEquations.solve" solution = DifferentialEquations.solve(problem, algorithm, reltol=m.options.tolerance, abstol=abstol, save_everystep=false, + callback=callbacks, adaptive=m.options.adaptive, saveat=tspan2, dtmax=m.options.dtmax, maxiters=maxiters, tstops = tstops, + initializealg = DifferentialEquations.NoInit()) + else + TimerOutputs.@timeit m.timer "DifferentialEquations.solve" solution = DifferentialEquations.solve(problem, algorithm, reltol=m.options.tolerance, abstol=abstol, save_everystep=false, + callback=callbacks, adaptive=m.options.adaptive, saveat=tspan2, dt=dt, dtmax=m.options.dtmax, maxiters=maxiters, tstops = tstops, + initializealg = DifferentialEquations.NoInit()) + end + + # Compute and store outputs from last event until final time + sol_t = solution.t + sol_x = solution.u + m.storeResult = true + for i = length(m.result_code)+1:length(sol_t) + invokelatest_getDerivatives_without_der_x!(sol_x[i], m, sol_t[i]) + end + m.storeResult = false + + # Final update of instantiatedModel + m.result_x = solution + if ismissing(algorithm) + m.algorithmName = getAlgorithmName(solution.alg) + end + + # Terminate simulation + finalStates = solution.u[end] + finalTime = solution.t[end] + terminate!(m, finalStates, finalTime) + + # Raise an error, if simulation was not successful + if !(solution.retcode == :Default || solution.retcode == :Success || solution.retcode == :Terminated) + error("\nsolution = simulate!(", m.modelName, ", ...) failed with solution.retcode = :$(solution.retcode) at time = $finalTime.\n") + end return solution end From 9522dbc83c5f12bdaf5a616cd97bc0ad1e73c7db Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 31 May 2022 14:30:16 +0200 Subject: [PATCH 31/63] simulate!(..) further restructured --- src/CodeGeneration.jl | 43 +++++++++------- src/EvaluateParameters.jl | 1 + src/EventHandler.jl | 66 +++++++++++++++++++++---- src/Modia.jl | 2 +- src/SimulateAndPlot.jl | 100 +++++++++++++++++++++++++++++++------- 5 files changed, 168 insertions(+), 44 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index c066f91..bb3155e 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -362,10 +362,14 @@ mutable struct SimulationModel{FloatType,TimeType} result_der_x::Vector{Vector{FloatType}} # result_der_x[ti][j] is der_x[j] at time instant ti parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor + instantiateFunctions::Vector{Tuple{Union{Expr,Symbol},OrderedDict{Symbol,Any},String}} + # All definitions `_instantiateFunction = Par(functionName = XXX)` in the model to call + # `XXX(instantiatedModel, submodel, submodelPath)` in the order occurring during evaluation + # of the parameters where, instantiatedFunctions[i] = (XXX, submodel, submodelPath) # Available after propagateEvaluateAndInstantiate!(..) called - evaluatedParameters::OrderedDict{Symbol,Any} # Evaluated parameters - nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) + evaluatedParameters::OrderedDict{Symbol,Any} # Evaluated parameters + nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) nextPre::AbstractVector nextHold::AbstractVector @@ -416,7 +420,6 @@ mutable struct SimulationModel{FloatType,TimeType} # Initialize execution flags eventHandler = EventHandler{FloatType,TimeType}(nz=nz, nAfter=nAfter) - eventHandler.initial = true isInitial = true storeResult = false solve_leq = true @@ -440,6 +443,7 @@ mutable struct SimulationModel{FloatType,TimeType} result_der_x = Vector{FloatType}[] parameters = deepcopy(parameterDefinition) + instantiateFunctions = Tuple{Any,String}[] obj = new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!, equationInfo, linearEquations, eventHandler, vSolvedWithInitValuesAndUnit2, @@ -448,7 +452,7 @@ mutable struct SimulationModel{FloatType,TimeType} hold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, - result_info, result_code, n_result_code, result_extra, result_extra_info, result_extra_temp, result_x, result_der_x, parameters) + result_info, result_code, n_result_code, result_extra, result_extra_info, result_extra_temp, result_x, result_der_x, parameters, instantiateFunctions) evaluatedParameters = propagateEvaluateAndInstantiate!(obj, log=false) if isnothing(evaluatedParameters) @@ -545,7 +549,7 @@ mutable struct SimulationModel{FloatType,TimeType} odeIntegrator, daeCopyInfo, m.sundials, m.addEventPointsDueToDEBug, success, m.unitless, m.result_info, Tuple[], m.n_result_code, Vector{Any}[], deepcopy(m.result_extra_info), Vector{Any}(nothing,length(m.result_extra_info)), missing, Vector{FloatType}[], - deepcopy(m.parameters), deepcopy(m.evaluatedParameters), + deepcopy(m.parameters), deepcopy(m.instantiateFunctions), deepcopy(m.evaluatedParameters), deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), zeros(FloatType,0), deepcopy(m.x_vec), convert(Vector{FloatType}, m.x_start), zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), @@ -1165,6 +1169,22 @@ function invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing end +function resizeStatesAndResults!(m::SimulationModel{FloatType,TimeType})::Nothing where {FloatType,TimeType} + nx = length(m.x_start) + nxHidden = nx - m.equationInfo.nxVisible + resize!(m.x_init, nx) + resize!(m.der_x_visible, m.equationInfo.nxVisible) + resize!(m.x_hidden , nxHidden) + resize!(m.der_x_hidden , nxHidden) + resize!(m.der_x_full , nx) + eqInfo = m.equationInfo + m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible] + addHiddenStatesAndExtraResultsTo_result_info!(m) + return nothing +end + + + """ success = init!(simulationModel) @@ -1189,8 +1209,6 @@ If initialization is successful return true, otherwise false. function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,TimeType} emptyResult!(m) eh = m.eventHandler - reinitEventHandler!(eh, m.options.stopTime, m.options.logEvents) - eh.firstInitialOfAllSegments = true # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters if length(m.options.merge) > 0 @@ -1203,16 +1221,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti end m.evaluatedParameters = evaluatedParameters m.x_start = initialStateVector!(m.equationInfo, FloatType) - nx = length(m.x_start) - nxHidden = nx - m.equationInfo.nxVisible - resize!(m.x_init, nx) - resize!(m.der_x_visible, m.equationInfo.nxVisible) - resize!(m.x_hidden , nxHidden) - resize!(m.der_x_hidden , nxHidden) - resize!(m.der_x_full , nx) - eqInfo = m.equationInfo - m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible] - addHiddenStatesAndExtraResultsTo_result_info!(m) + resizeStatesAndResults!(m) end # Initialize auxiliary arrays for event iteration diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index cb0757c..1eb5c57 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -378,6 +378,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType println(" 13: +++ Instantiated $path: $instantiateFunction will be called to instantiate sub-model and define hidden states\n\n") end Core.eval(modelModule, :($instantiateFunction($m, $current, $path, log=$log))) + push!(m.instantiateFunctions, (instantiateFunction, current, path)) end return current else diff --git a/src/EventHandler.jl b/src/EventHandler.jl index ce9f231..a01845d 100644 --- a/src/EventHandler.jl +++ b/src/EventHandler.jl @@ -34,15 +34,16 @@ mutable struct EventHandler{FloatType,TimeType} # Logging logEvents::Bool # = true, if events shall be logged nZeroCrossings::Int # Number of zero crossing calls - nRestartEvents::Int # Number of Restart events + nRestartEvents::Int # Number of Restart events (= nStateEvents + nTimeEvents + nFullRestartEvents) nStateEvents::Int # Number of state events nTimeEvents::Int # Number of time events + nFullRestartEvents::Int # Number of full restart events # Input values for the event functions time::TimeType # Current simulation time - initial::Bool # = true, if model is called at initialization + initial::Bool # = true, if model is called at initialization of current simulation segment # (if initial, event=true) - terminal::Bool # = true, if model is called for termination (close files, streams, visualization, ...) + terminal::Bool # = true, if model is called for termination at current simulation segment (close files, streams, visualization, ...) event::Bool # = true, if model is called at an event afterSimulationStart::Bool # = true, if model is called after simulation start crossing::Bool # = true, if model is called to compute crossing function @@ -52,6 +53,8 @@ mutable struct EventHandler{FloatType,TimeType} # Values especially for simulations with several segments firstInitialOfAllSegments::Bool # = true, if model is called at initialization of the first simulation segment. terminalOfAllSegments::Bool # = true, if model is called for termination at the last simulation segment. + fullRestart::Bool # = true, if model is called at initialization of a FullRestart + # (if fullRestart==true -> initial=event=true; if firstInitialOfAllSegments==true -> fullRestart=false) # Computed by the event functions # For time events: @@ -89,13 +92,26 @@ mutable struct EventHandler{FloatType,TimeType} @assert(nAfter >= 0) nAfter = nAfter > 0 ? nAfter : nAfterDefault zEps = FloatType(1e-10) - new(floatmax(TimeType), logEvents, 0, 0, 0, 0, convert(TimeType,0), - false, false, false, false, false, false, false, false, false, floatmax(TimeType), floatmax(TimeType), + + initial = true + terminal = false + event = true + afterSimulationStart = false + crossing = false + firstEventIterationDirectlyAfterInitial = false + triggerEventDirectlyAfterInitial = false + firstInitialOfAllSegments = true + terminalOfAllSegments = false + fullRestart = false + new(floatmax(TimeType), logEvents, 0, 0, 0, 0, 0, convert(TimeType,0), + initial, terminal, event, afterSimulationStart, crossing, firstEventIterationDirectlyAfterInitial, triggerEventDirectlyAfterInitial, + firstInitialOfAllSegments, terminalOfAllSegments, fullRestart, floatmax(TimeType), floatmax(TimeType), true, NoRestart, false, false, zEps, nz, nz, ones(FloatType,nz), fill(false, nz), nAfter, fill(false,nAfter), fill(convert(TimeType,0),nClock), Vector{Any}(undef, nSample)) end end + # Default constructors #EventHandler( ; kwargs...) = EventHandler{Float64 ,Float64}(; kwargs...) #EventHandler{FloatType}(; kwargs...) where {FloatType} = EventHandler{FloatType,Float64}(; kwargs...) @@ -110,16 +126,17 @@ function removeHiddenCrossingFunctions!(eh::EventHandler{FloatType,TimeType})::N return nothing end - + function reinitEventHandler!(eh::EventHandler{FloatType,TimeType}, stopTime::TimeType, logEvents::Bool)::Nothing where {FloatType,TimeType} eh.logEvents = logEvents eh.nZeroCrossings = 0 eh.nRestartEvents = 0 eh.nStateEvents = 0 eh.nTimeEvents = 0 + eh.nFullRestartEvents = 0 eh.time = convert(TimeType, 0) - eh.initial = false + eh.initial = true eh.terminal = false eh.event = false eh.crossing = false @@ -127,8 +144,39 @@ function reinitEventHandler!(eh::EventHandler{FloatType,TimeType}, stopTime::Tim eh.triggerEventDirectlyAfterInitial = false eh.afterSimulationStart = false - eh.firstInitialOfAllSegments = false + eh.firstInitialOfAllSegments = true eh.terminalOfAllSegments = false + eh.fullRestart = false + + eh.stopTime = stopTime + eh.maxTime = floatmax(TimeType) + eh.nextEventTime = floatmax(TimeType) + eh.integrateToEvent = false + eh.restart = Restart + eh.newEventIteration = false + eh.firstEventIteration = true + eh.z .= convert(FloatType, 1.0) + eh.zPositive .= false + eh.after .= false + + return nothing +end + +function reinitEventHandlerForFullRestart!(eh::EventHandler{FloatType,TimeType}, currentTime::TimeType, stopTime::TimeType, logEvents::Bool)::Nothing where {FloatType,TimeType} + eh.nRestartEvents += 1 + eh.nFullRestartEvents += 1 + eh.initial = true + eh.terminal = false + eh.event = false + eh.crossing = false + eh.firstEventIterationDirectlyAfterInitial = false + eh.triggerEventDirectlyAfterInitial = false + + eh.afterSimulationStart = false + eh.terminalOfAllSegments = false + eh.fullRestart = true + + eh.time = currentTime eh.stopTime = stopTime eh.maxTime = floatmax(TimeType) eh.nextEventTime = floatmax(TimeType) @@ -139,7 +187,7 @@ function reinitEventHandler!(eh::EventHandler{FloatType,TimeType}, stopTime::Tim eh.z .= convert(FloatType, 1.0) eh.zPositive .= false eh.after .= false - + return nothing end diff --git a/src/Modia.jl b/src/Modia.jl index 02aed9a..31374c0 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-05-30" +const Date = "2022-05-31" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index d80a977..adf3226 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -219,7 +219,10 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me @test false return nothing end - m.options = options + m.options = options + m.time = options.startTime + m.isInitial = true + reinitEventHandler!(m.eventHandler, m.options.stopTime, m.options.logEvents) if ismissing(algorithm) && FloatType == Float64 algorithm = Sundials.CVODE_BDF() @@ -252,15 +255,87 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me reset_timer!(m.timer) m.cpuLast = time_ns() m.cpuFirst = m.cpuLast - + eh = m.eventHandler solution = nothing + + # --------------------------------------------------------- Core simulation loop --------------------------------- TimerOutputs.@timeit m.timer "Modia.simulate!" while true - solution = simulateSegment!(m, algorithm; merge=merge, kwargs...) + solution = simulateSegment!(m, algorithm; kwargs...) + + # Terminate simulation of current segment + finalStates = solution.u[end] + finalTime = solution.t[end] + m.result_x = solution + if m.eventHandler.restart != Modia.FullRestart + eh.terminalOfAllSegments = true + end + terminate!(m, finalStates, finalTime) + eh.terminalOfAllSegments = false + + # Raise an error, if simulation was not successful + if !(solution.retcode == :Default || solution.retcode == :Success || solution.retcode == :Terminated) + error("\nsolution = simulate!(", m.modelName, ", ...) failed with solution.retcode = :$(solution.retcode) at time = $finalTime.\n") + end + if m.eventHandler.restart != Modia.FullRestart break end + + # Re-initialize model for FullRestart m.options.startTime = m.time - end + reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) + + # Evaluate instantiate functions + removeHiddenStatesAndExtraResults!(m) + removeHiddenCrossingFunctions!(m.eventHandler) + for fc in m.instantiatedFunctions + logInstantiatedFunctionCalls = false + Core.eval(m.modelModule, :($(fc[1])($m, $(fc[2]), $(fc[3]), log=$logInstantiatedFunctionCalls))) + end + m.x_start = initialStateVector!(m.equationInfo, FloatType) + resizeStatesAndResults!(m) + + # Initialize auxiliary arrays for event iteration + m.x_init .= FloatType(0) + m.der_x_visible .= FloatType(0) + m.x_hidden .= FloatType(0) + m.der_x_hidden .= FloatType(0) + m.der_x_full .= FloatType(0) + + if m.options.logStates + # List init/start values + x_table = DataFrames.DataFrame(state=String[], init=Any[], unit=String[]) #, nominal=String[]) + for xe_info in m.equationInfo.x_info + xe_init = get_xe(m.x_start, xe_info) + if hasParticles(xe_init) + xe_init = string(minimum(xe_init)) * " .. " * string(maximum(xe_init)) + end + # xe_nominal = isnan(xe_info.nominal) ? "" : xe_info.nominal + push!(x_table, (xe_info.x_name, xe_init, xe_info.unit)) #, xe_nominal)) + end + show(stdout, x_table; allrows=true, allcols=true, rowlabel = Symbol("#"), summary=false, eltypes=false) + println("\n") + end + + # Initialize model, linearEquations and compute and store all variables at the initial time + if m.options.log + println(" Reinitialization due to FullRestart at time = ", m.time, " s") + end + + # Perform event iteration + m.isInitial = true + eh.initial = true + for i in eachindex(m.x_init) + m.x_init[i] = deepcopy(m.x_start[i]) + end + eventIteration!(m, m.x_init, m.options.startTime) + m.success = false # is set to true at the first outputs! call. + eh.fullRestart = false + eh.initial = false + m.isInitial = false + m.storeResult = false + eh.afterSimulationStart = true + end # --------------------------------------------------------- End of core simulation loop ------------------------------ disable_timer!(m.timer) @@ -301,6 +376,9 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end println(" nTimeEvents = ", eh.nTimeEvents) println(" nStateEvents = ", eh.nStateEvents) + if eh.nFullRestartEvents > 0 + println(" nFullRestartEvents = ", eh.nFullRestartEvents) + end println(" nRestartEvents = ", eh.nRestartEvents) end if m.options.logTiming @@ -371,7 +449,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end -function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; merge=nothing, kwargs...) where {FloatType,TimeType} +function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; kwargs...) where {FloatType,TimeType} solution = nothing sizesOfLinearEquationSystems = Int[length(leq.b) for leq in m.linearEquations] @@ -482,22 +560,10 @@ function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=miss end m.storeResult = false - # Final update of instantiatedModel - m.result_x = solution if ismissing(algorithm) m.algorithmName = getAlgorithmName(solution.alg) end - # Terminate simulation - finalStates = solution.u[end] - finalTime = solution.t[end] - terminate!(m, finalStates, finalTime) - - # Raise an error, if simulation was not successful - if !(solution.retcode == :Default || solution.retcode == :Success || solution.retcode == :Terminated) - error("\nsolution = simulate!(", m.modelName, ", ...) failed with solution.retcode = :$(solution.retcode) at time = $finalTime.\n") - end - return solution end From 8885cd6750cdd8ed196a1b7568d6f9ebce32bd3d Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 7 Jun 2022 01:42:49 +0200 Subject: [PATCH 32/63] Modia restructured --- src/CodeGeneration.jl | 921 ++++++++++++++++++------------------ src/EquationAndStateInfo.jl | 163 +++---- src/EvaluateParameters.jl | 4 +- src/EventHandler.jl | 17 +- src/Modia.jl | 4 +- src/ModiaLang.jl | 19 +- src/Result.jl | 277 +++++++++++ src/SimulateAndPlot.jl | 113 ++--- src/StateSelection.jl | 4 +- test/TestLinearSystems.jl | 14 +- 10 files changed, 885 insertions(+), 651 deletions(-) create mode 100644 src/Result.jl diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index bb3155e..b5768b9 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -239,39 +239,6 @@ mutable struct SimulationOptions{FloatType,TimeType} end - -""" - @enum ResultStore RESULT_CODE RESULT_EXTRA RESULT_X RESULT_DER_X RESULT_ZERO - -SimulationModel field name where result is stored: - -- RESULT_CODE : stored in `result_code` (variables known before code is compiled) -- RESULT_EXTRA: stored in `result_extra` (variables known after code is compiled) -- RESULT_X : stored in `result_x` (return argument of DifferentialEquations.solve(...)) -- RESULT_DER_X: stored in `result_der_x` -- RESULT_ZERO : value is zero -""" -@enum ResultStore RESULT_CODE RESULT_EXTRA RESULT_X RESULT_DER_X RESULT_ZERO - - -struct ResultInfo - store::ResultStore # Location where variable is stored - index::Int # Index, depending on store-type - # store = RESULT_CODE : result_code[ti][index] - # = RESULT_EXTRA: result_extra[ti][index] - # = RESULT_X : result_x[ti][ibeg:iend] - # ibeg = equationInfo.x_info[index].startIndex - # iend = ibeg + equationInfo.x_info[index].length-1 - # = RESULT_DER_X: result_der_x[ti][ibeg:iend] - # ibeg = equationInfo.x_info[index].startIndex - # iend = ibeg + equationInfo.x_info[index].length-1 - # = RESULT_ZERO : not stored (value is zero; index = 0) - negate::Bool # = true, if result must be negated - - ResultInfo(store, index=0, negate=false) = new(store, index, negate) -end - - struct LinearEquationsCopyInfoForDAEMode ileq::Int # Index of LinearEquations() index::Vector{Int} # Copy: leq.x[i] = dae_der_x[index[i]] @@ -284,7 +251,7 @@ end """ simulationModel = SimulationModel{FloatType,TimeType}( modelModule, modelName, getDerivatives!, equationInfo, x_startValues, - parameters, variableNames; + parameters, timeName, w_invariant_names; vSolvedWithInitValuesAndUnit::OrderedDict{String,Any}(), vEliminated::Vector{Int}=Int[], vProperty::Vector{Int}=Int[], @@ -301,7 +268,8 @@ end - `equationInfo::Modia.EquationInfo`: Information about the states and the equations. - `x_startValues`:: Deprecated (is no longer used). - `parameters`: A hierarchical NamedTuple of (key, value) pairs defining the parameter and init/start values. -- variableNames: A vector of variable names. A name can be a Symbol or a String. +- `timeName`: Name of time (as Symbol) +- `w_invariant_names`: A vector of variable names (as vector of symbols or Expr) """ mutable struct SimulationModel{FloatType,TimeType} # Available before propagateEvaluateAndInstantiate!(..) called (= partiallyInstantedModel) @@ -313,7 +281,7 @@ mutable struct SimulationModel{FloatType,TimeType} cpuLast::UInt64 # Last time from time_ns() options::SimulationOptions{FloatType,TimeType} getDerivatives!::Function - equationInfo::Modia.EquationInfo + initialEquationInfo::Modia.EquationInfo linearEquations::Vector{Modia.LinearEquations{FloatType}} eventHandler::EventHandler{FloatType,TimeType} vSolvedWithInitValuesAndUnit::OrderedDict{String,Any} # Dictionary of (names, init values with units) for all explicitly solved variables with init-values defined @@ -350,44 +318,37 @@ mutable struct SimulationModel{FloatType,TimeType} # = false, either before first outputs!(..) call or at first outputs!(..) after init!(..) and # an error was triggered and simulate!(..) should be returned with nothing. unitless::Bool # = true, if simulation is performed without units. - - result_info::OrderedDict{String,ResultInfo} # key : Full path name of result variables - # value: Storage location and index into the storage. - result_code::Vector{Tuple} # result_code[ti][j] is result of variable with index j at time instant ti - n_result_code::Int # Number of result_code variables - result_extra::Vector{Vector{Any}} # result_extra[ti][j] is extra result of variable with index j at time instant ti - result_extra_info::OrderedDict{String,ResultInfo} # Extra result variables info (needed to remove extra results before a simulate!(..., merge=...)) - result_extra_temp::Vector{Any} # Memory to store temporarily references to extra results; length(result_extra_temp) = length(result_extra_info) - result_x::Union{Any,Missing} # Return value of DifferentialEquations.solve(..) (is a struct) - result_der_x::Vector{Vector{FloatType}} # result_der_x[ti][j] is der_x[j] at time instant ti - + initialResult::Result # Initial result data structure (includes all invariant variable definitions and empty result vectors) parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor + + # Available after propagateEvaluateAndInstantiate!(..) called + equationInfo::Modia.EquationInfo + result::Result # Result data structure upto current time instant instantiateFunctions::Vector{Tuple{Union{Expr,Symbol},OrderedDict{Symbol,Any},String}} # All definitions `_instantiateFunction = Par(functionName = XXX)` in the model to call # `XXX(instantiatedModel, submodel, submodelPath)` in the order occurring during evaluation # of the parameters where, instantiatedFunctions[i] = (XXX, submodel, submodelPath) - - # Available after propagateEvaluateAndInstantiate!(..) called + nsegment::Int # Current simulation segment evaluatedParameters::OrderedDict{Symbol,Any} # Evaluated parameters nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) nextPre::AbstractVector nextHold::AbstractVector x_vec::Vector{Vector{FloatType}} # x_vec[i] holds the actual values of (visible) state vector element - # equationInfo.x_info[equationInfo.nx_infoFixed+i:equationInfo.nx_infoVisible] + # equationInfo.x_info[equationInfo.nx_info_fixedLength+i:equationInfo.nx_info_invariant] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) - der_x_visible::Vector{FloatType} # Derivatives of states x or x_init that correspond to visible states - # This vector is filled with derivatives of visible states with appendVariable!(m.der_x_visible, ...) calls, - # including derivatives of x_vec[i] - x_hidden::Vector{FloatType} # A copy of the states x that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) - der_x_hidden::Vector{FloatType} # Derivatives of states x or x_init that correspond to hidden states (defined in functions and not visible in getDerivatives!(..)) - der_x_full::Vector{FloatType} # Derivatives of states x (needed in DAE mode) + x_segment::Vector{FloatType} # A copy of the current segment states + der_x_invariant::Vector{FloatType} # Derivatives of states x or x_init that correspond to invariant states + # This vector is filled with derivatives of invariants states with appendVariable!(m.der_x_invariant, ...) calls, + # including derivatives of x_vec[i] + der_x_segment::Vector{FloatType} # Derivatives of states x or x_init that correspond to segment states (defined in functions and not visible in getDerivatives!(..)) + der_x::Vector{FloatType} # Derivatives of states x function SimulationModel{FloatType,TimeType}(modelModule, modelName, buildDict, getDerivatives!, equationInfo, previousVars, preVars, holdVars, - parameterDefinition, variableNames; + parameterDefinition, timeName, w_invariant_names; unitless::Bool=true, nz::Int = 0, nAfter::Int = 0, @@ -395,6 +356,7 @@ mutable struct SimulationModel{FloatType,TimeType} vEliminated::Vector{Int} = Int[], vProperty::Vector{Int} = Int[], var_name::Function = v -> nothing) where {FloatType,TimeType} + # Construct data structure for linear equations linearEquations = Modia.LinearEquations{FloatType}[] for leq in equationInfo.linearEquations @@ -430,92 +392,24 @@ mutable struct SimulationModel{FloatType,TimeType} algorithmName = missing sundials = false addEventPointsDueToDEBug = false - success = false - - # Result data structure - result_info = OrderedDict{String, ResultInfo}() - result_code = Tuple[] - n_result_code = length(variableNames) - result_extra = Vector{Any}[] - result_extra_info = OrderedDict{String, ResultInfo}() - result_extra_temp = Any[] - result_x = missing - result_der_x = Vector{FloatType}[] + success = false + # Initialize other data + initialResult = Result{FloatType,TimeType}(string(timeName), equationInfo, w_invariant_names, vEliminated, vProperty, var_name) parameters = deepcopy(parameterDefinition) - instantiateFunctions = Tuple{Any,String}[] - obj = new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!, - equationInfo, linearEquations, eventHandler, - vSolvedWithInitValuesAndUnit2, - previous, previous_names, previous_dict, - pre, pre_names, pre_dict, - hold, hold_names, hold_dict, - isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, - odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, - result_info, result_code, n_result_code, result_extra, result_extra_info, result_extra_temp, result_x, result_der_x, parameters, instantiateFunctions) - - evaluatedParameters = propagateEvaluateAndInstantiate!(obj, log=false) - if isnothing(evaluatedParameters) - return nothing - end - obj.evaluatedParameters = evaluatedParameters - obj.nextPrevious = deepcopy(previous) - obj.nextPre = deepcopy(pre) - obj.nextHold = deepcopy(hold) - - obj.x_start = initialStateVector!(equationInfo, FloatType) - nx = length(obj.x_start) - nxHidden = nx-equationInfo.nxVisible - - # Provide storage for x_vec and utility vectors - obj.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_infoFixed+1:equationInfo.nx_infoVisible] - obj.x_init = zeros(FloatType,nx) - obj.der_x_visible = zeros(FloatType,equationInfo.nxVisible) - obj.x_hidden = zeros(FloatType, nxHidden) - obj.der_x_hidden = zeros(FloatType, nxHidden) - obj.der_x_full = zeros(FloatType,nx) - - # Define result - # Store visible x and der_x - for xe_index = 1:equationInfo.nx_infoVisible - xe_info = equationInfo.x_info[xe_index] - result_info[xe_info.x_name] = ResultInfo(RESULT_X, xe_index) - end - for xe_index = 1:equationInfo.nx_infoVisible - xe_info = equationInfo.x_info[xe_index] - result_info[xe_info.der_x_name] = ResultInfo(RESULT_DER_X, xe_index) - end - - # Store result_code variables - for (i, name) in enumerate(variableNames) - str_name = string(name) - if !haskey(result_info, str_name) - result_info[str_name] = ResultInfo(RESULT_CODE, i) - end - end - - # Store eliminated variables - for v in vEliminated - name = var_name(v) - if ModiaBase.isZero(vProperty, v) - result_info[name] = ResultInfo(RESULT_ZERO) - elseif ModiaBase.isAlias(vProperty, v) - name2 = var_name( ModiaBase.alias(vProperty, v) ) - result_info[name] = result_info[name2] - else # negated alias - name2 = var_name( ModiaBase.negAlias(vProperty, v) ) - info2 = result_info[name2] - result_info[name] = ResultInfo(info2.store, info2.index, true) - end - end - - # Add hidden states/state derivatives and extra results - addHiddenStatesAndExtraResultsTo_result_info!(obj) - return obj + new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!, + equationInfo, linearEquations, eventHandler, + vSolvedWithInitValuesAndUnit2, + previous, previous_names, previous_dict, + pre, pre_names, pre_dict, + hold, hold_names, hold_dict, + isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, + odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, + initialResult, parameters) end - +#= function SimulationModel{FloatType,TimeType}(m::SimulationModel) where {FloatType,TimeType} # Construct data structure for linear equations linearEquations = Modia.LinearEquations{FloatType}[] @@ -535,7 +429,21 @@ mutable struct SimulationModel{FloatType,TimeType} daeCopyInfo = LinearEquationsCopyInfoForDAEMode[] algorithmName = missing success = false - nx = m.equationInfo.nx + nx = m.equationInfo.nx + nxInvariant = m.equationInfo.nxInvariant + nxSegment = nx-nxInvariant + + emptyResult!(m.result) + result = deepcopy(m.result) + nsegment = 1 + + x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] + x_start = convert(Vector{FloatType}, m.x_start) + x_init = zeros(FloatType, nx) + x_segment = zeros(FloatType, nxSegment) + der_x_invariant = zeros(FloatType, nxInvariant) + der_x_segment = zeros(FloatType, nxSegment) + der_x = zeros(FloatType, nx) new(m.modelModule, m.modelName, deepcopy(m.buildDict), TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), deepcopy(m.options), m.getDerivatives!, deepcopy(m.equationInfo), deepcopy(linearEquations), @@ -547,14 +455,12 @@ mutable struct SimulationModel{FloatType,TimeType} isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, true, LinearEquationsCopyInfoForDAEMode[], odeIntegrator, daeCopyInfo, m.sundials, m.addEventPointsDueToDEBug, success, m.unitless, - m.result_info, Tuple[], m.n_result_code, Vector{Any}[], deepcopy(m.result_extra_info), - Vector{Any}(nothing,length(m.result_extra_info)), missing, Vector{FloatType}[], + result, nsegment, deepcopy(m.parameters), deepcopy(m.instantiateFunctions), deepcopy(m.evaluatedParameters), deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), - zeros(FloatType,0), deepcopy(m.x_vec), - convert(Vector{FloatType}, m.x_start), zeros(FloatType,nx), zeros(FloatType,equationInfo.nxVisible), zeros(FloatType,nx-equationInfo.nxVisible), - zeros(FloatType,nx)) + x_vec, x_start, x_init, x_segment, der_x_invariant, der_x_segment, der_x) end +=# end @@ -576,89 +482,6 @@ after( m::SimulationModel, args...; kwargs...) = Modia.after!( m.eventHandle pre( m::SimulationModel, i) = m.pre[i] -function emptyResult!(m::SimulationModel)::Nothing - empty!(m.result_code) - empty!(m.result_extra) - empty!(m.result_der_x) - m.result_x = missing - return nothing -end - -function get_xinfo(m::SimulationModel, x_index::Int)::Tuple{Int, Int, String} - xinfo = m.equationInfo.x_info[x_index] - ibeg = xinfo.startIndex - iend = ibeg + xinfo.length-1 - return (ibeg, iend, xinfo.unit) -end - - -""" - x_hidden_startIndex = newHiddenState!( - m::SimulationModel, - x_name::String, - der_x_name::String, - startOrInit; # Scalar or Vector - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false) - -Add new hidden state to instantiated model and return its index that allows fast copying to x and der(x) vectors. -""" -newHiddenState!(m::SimulationModel, - x_name::String, - der_x_name::String, - startOrInit; - stateCategory::StateCategory = XD, - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false)::Int = newHiddenState!(m.equationInfo, x_name, der_x_name, startOrInit; - stateCategory = stateCategory, unit = unit, fixed = fixed, - nominal = nominal, unbounded = unbounded) - -""" - x_startIndex = getStateStartIndexFromHiddenStateStartIndex(instantiatedModel::SimulationModel, x_hidden_startIndex) - -Return the startindex of hidden staten with respect to x-vector, given the startIndex with respect to the x_hidden vector. -""" -getStateStartIndexFromHiddenStateStartIndex(m::SimulationModel, x_hidden_startIndex::Int) = m.equationInfo.nxVisible + x_hidden_startIndex - - -""" - addHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{FloatType}) - -Copy state from `m` at index `x_hidden_startIndex` into pre-allocated vector `xi`. -""" -@inline function addHiddenState!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, xi::Vector{Float64})::Nothing where {FloatType,TimeType} - copyto!(xi, 1, m.x_hidden, x_hidden_startIndex, length(xi)) - return nothing -end - - -""" - scalar_x_hidden = getScalarHiddenState(m::SimulationModel, x_hidden_startIndex::Int) - -Return scalar hidden state scalar_x_hidden = m.x_hidden[x_hidden_startIndex]. -""" -getScalarHiddenState(m::SimulationModel, x_hidden_startIndex::Int) = m.x_hidden[x_hidden_startIndex] - - -""" - copyToHiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, der_x::Union{FloatType,Vector{FloatType}}) - -Copy hidden state derivative `der_x` into `m` starting at index `x_hidden_startIndex`. -""" -@inline function copyToHiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, der_x::FloatType)::Nothing where {FloatType,TimeType} - m.der_x_hidden[x_hidden_startIndex] = der_x - return nothing -end -@inline function copyToHiddenStateDerivative!(m::SimulationModel{FloatType,TimeType}, x_hidden_startIndex::Int, der_x::Vector{FloatType})::Nothing where {FloatType,TimeType} - copyto!(m.der_x_hidden, x_hidden_startIndex, der_x, 1, length(der_x)) - return nothing -end - - """ v_zero = reinit(instantiatedModel, _x, j, v_new, _leqMode; v_threshold=0.01) @@ -706,8 +529,6 @@ function reinit(m::SimulationModel, x, j, v_new, leqMode; v_threshold=0.01) end - - """ floatType = getFloatType(simulationModel::SimulationModel) @@ -819,62 +640,73 @@ and the function returns `nothing`. `name` can be a time-varying variable or a parameter. """ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit::Bool=true) where {FloatType,TimeType} - if haskey(m.result_info, name) - # Time varying variable stored in m.result_xxx - resInfo = m.result_info[name] - if ismissing(m.result_x) || length(m.result_x.t) == 0 + result = m.result + if haskey(result.info, name) + # Time varying variable stored in m.result + resInfo = result.info[name] + if length(result.t) == 0 @info "getLastValue(model,\"$name\"): No results yet available." return nothing end - if resInfo.store == RESULT_CODE - value = m.result_code[end][resInfo.index] - if !unit - value = stripUnit(value) + if resInfo.kind == RESULT_ELIMINATED + value = getLastValue(m, resInfo.aliasName, unit=unit) + if resInfo.aliasNegate + value *= -1 end - elseif resInfo.store == RESULT_EXTRA - value = m.result_extra[end][resInfo.index] + elseif resInfo.kind == RESULT_CONSTANT + value = resInfo.value if !unit value = stripUnit(value) end - elseif resInfo.store == RESULT_X - (ibeg,iend,xunit) = get_xinfo(m, resInfo.index) - if ibeg==iend - value = m.result_x[end][ibeg] - else - value = m.result_x[end][ibeg:iend] + elseif resInfo.kind == RESULT_T + value = result.t[end][end] + if unit && resInfo.unit != "" + value *= uparse(resInfo.unit) end - if unit && !m.unitless && xunit != "" - value = value*uparse(xunit) + + elseif resInfo.kind == RESULT_X + locationID = resInfo.locationID[end] + segment = locationID.segment + ibeg = locationID.index + iend = ibeg + prod(locationID.size) - 1 + value = ibeg == iend ? result.x[segment][end][ibeg] : result.x[segment][end][ibeg:iend] + if unit && resInfo.unit != "" + value *= uparse(resInfo.unit) end - elseif resInfo.store == RESULT_DER_X - (ibeg,iend,xunit) = get_x_indices(m, resInfo.index) - if ibeg==iend - value = m.result_der_x[end][ibeg] - else - value = m.result_der_x[end][ibeg:iend] + elseif resInfo.kind == RESULT_DER_X + locationID = resInfo.locationID[end] + segment = locationID.segment + ibeg = locationID.index + iend = ibeg + prod(locationID.size) - 1 + value = ibeg == iend ? result.der_x[segment][end][ibeg] : result.der_x[segment][end][ibeg:iend] + if unit && resInfo.unit != "" + value *= uparse(resInfo.unit) end - if unit && !m.unitless - if xunit == "" - value = value/u"s" - else - value = value*(uparse(xunit)/u"s") - end + + elseif resInfo.kind == RESULT_W_INVARIANT + locationID = resInfo.locationID[end] + @show name + @show resInfo + @show locationID + @show result.w_invariant + value = result.w_invariant[locationID.segment][end][locationID.index] + if !unit + value = stripUnit(value) end - elseif resInfo.store == RESULT_ZERO - # Type, size and unit is not known (needs to be fixed) - value = convert(FloatType, 0) + elseif resInfo.kind == RESULT_W_SEGMENT + locationID = resInfo.locationID[end] + value = result.w_segment[locationID.segment][end][locationID.index] + if unit && resInfo.unit != "" && eltype(value) <: AbstractFloat + value *= uparse(resInfo.unit) + end else - error("Bug in getLastValue(...), name = $name, resInfo.store = $resInfo.store.") - end - - if resInfo.negate - value = -value + error("Bug in getLastValue(...), name = $name, resInfo.kind = $(resInfo.kind).") end else @@ -1026,6 +858,15 @@ isInitial(m::SimulationModel) = m.eventHandler.initial initial( m::SimulationModel) = m.eventHandler.initial +""" + isFirstInitialOfAllSegments(instantiatedModel) + +Return true, if **initialization phase** of simulation of the **first segment** +of a segmented simulation. +""" +isFirstInitialOfAllSegments(m::SimulationModel) = m.eventHandler.firstInitialOfAllSegments + + """ isTerminal(instantiatedModel) @@ -1035,6 +876,15 @@ isTerminal(m::SimulationModel) = m.eventHandler.terminal terminal( m::SimulationModel) = m.eventHandler.terminal +""" + isTerminalOfAllSegments(instantiatedModel) + +Return true, if **terminal phase** of simulation of the **last segment** +of a segmented simulation. +""" +isTerminalOfAllSegments(m::SimulationModel) = m.eventHandler.terminalOfAllSegments + + """ isEvent(instantiatedModel) @@ -1061,6 +911,14 @@ Return true, if first iteration directly after initialization where initial=true isFirstEventIterationDirectlyAfterInitial(m::SimulationModel) = m.eventHandler.firstEventIterationDirectlyAfterInitial +""" + isFullRestart(instantiatedModel) + +Return true, if **FullRestart event** of a segmented simulation. +""" +isFullRestart(m::SimulationModel) = m.eventHandler.fullRestart + + """ isAfterSimulationStart(instantiatedModel) @@ -1085,10 +943,6 @@ Return true, if **results shall be stored**. storeResults(m::SimulationModel) = m.storeResult -isFirstInitialOfAllSegments(m::SimulationModel) = m.eventHandler.firstInitialOfAllSegments -isTerminalOfAllSegments(m::SimulationModel) = m.eventHandler.isTerminalOfAllSegments - - """ setNextEvent!(instantiatedModel, nextEventTime) @@ -1106,26 +960,6 @@ Return current simulation time. getTime(m::SimulationModel) = m.time -""" - zStartIndex = newZeroCrossings(instantiatedModel, nz) - -Add nz new zero crossing functions and return the start index with respect to -instantiatedModel.eventHandler.z. -""" -function newZeroCrossings(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} - eh = m.eventHandler - zStartIndex = eh.nz + 1 - eh.nz += nz - resize!(eh.z, eh.nz) - resize!(eh.zPositive, eh.nz) - for i = zStartIndex:eh.nz - eh.z[i] = convert(F, 1.0) - eh.zPositive[i] = false - end - return zStartIndex -end - - get_xe(x, xe_info) = xe_info.length == 1 ? x[xe_info.startIndex] : x[xe_info.startIndex:xe_info.startIndex + xe_info.length-1] #function set_xe!(x, xe_info, value)::Nothing @@ -1152,43 +986,26 @@ function invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing eqInfo = m.equationInfo x_vec = m.x_vec j = 1 - for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible + for i in eqInfo.nx_info_fixedLength+1:eqInfo.nx_info_invariant xe = eqInfo.x_info[i] copyto!(x_vec[j], 1, x, xe.startIndex, xe.length) j += 1 end end - copyto!(m.x_hidden, 1, x, m.equationInfo.nxVisible+1, m.equationInfo.nxHidden) - empty!(m.der_x_visible) - m.der_x_hidden .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 + copyto!(m.x_segment, 1, x, m.equationInfo.nxInvariant+1, m.equationInfo.nxSegment) + empty!(m.der_x_invariant) + m.der_x_segment .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 Base.invokelatest(m.getDerivatives!, x, m, t) - @assert(length(m.der_x_visible) + length(m.der_x_hidden) == length(x)) + @assert(length(m.der_x_invariant) + length(m.der_x_segment) == length(x)) end return nothing end -function resizeStatesAndResults!(m::SimulationModel{FloatType,TimeType})::Nothing where {FloatType,TimeType} - nx = length(m.x_start) - nxHidden = nx - m.equationInfo.nxVisible - resize!(m.x_init, nx) - resize!(m.der_x_visible, m.equationInfo.nxVisible) - resize!(m.x_hidden , nxHidden) - resize!(m.der_x_hidden , nxHidden) - resize!(m.der_x_full , nx) - eqInfo = m.equationInfo - m.x_vec = [zeros(FloatType, eqInfo.x_info[i].length) for i in eqInfo.nx_infoFixed+1:eqInfo.nx_infoVisible] - addHiddenStatesAndExtraResultsTo_result_info!(m) - return nothing -end - - - """ success = init!(simulationModel) - Initialize `simulationModel::SimulationModel` at `startTime`. In particular: - Empty result data structure. @@ -1207,29 +1024,43 @@ Initialize `simulationModel::SimulationModel` at `startTime`. In particular: If initialization is successful return true, otherwise false. """ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,TimeType} - emptyResult!(m) - eh = m.eventHandler - - # Apply updates from merge Map and propagate/instantiate/evaluate the resulting evaluatedParameters + m.equationInfo = deepcopy(m.initialEquationInfo) + m.result = deepcopy(m.initialResult) + equationInfo = m.equationInfo + result = m.result + eh = m.eventHandler + m.instantiateFunctions = Tuple{Any,String}[] + m.nsegment = 1 + newResultSegment!(result) if length(m.options.merge) > 0 - removeHiddenStatesAndExtraResults!(m) - removeHiddenCrossingFunctions!(m.eventHandler) m.parameters = mergeModels(m.parameters, m.options.merge) - evaluatedParameters = propagateEvaluateAndInstantiate!(m) - if isnothing(evaluatedParameters) - return false - end - m.evaluatedParameters = evaluatedParameters - m.x_start = initialStateVector!(m.equationInfo, FloatType) - resizeStatesAndResults!(m) + end + evaluatedParameters = propagateEvaluateAndInstantiate!(m, log=false) + if isnothing(evaluatedParameters) + return false + end + m.evaluatedParameters = evaluatedParameters + m.nextPrevious = deepcopy(m.previous) + m.nextPre = deepcopy(m.pre) + m.nextHold = deepcopy(m.hold) + m.x_start = initialStateVector!(m) + nx = length(m.x_start) + nxSegment = nx-equationInfo.nxInvariant + + # Update locationIDs of all states and state derivatives (indices are known, after initialStateVector!(..) was called + for xe_info in equationInfo.x_info + locationID = LocationID(1, xe_info.startIndex, size(xe_info.startOrInit)) + push!(result.info[xe_info.x_name ].locationID, locationID) + push!(result.info[xe_info.der_x_name].locationID, locationID) end - # Initialize auxiliary arrays for event iteration - m.x_init .= FloatType(0) - m.der_x_visible .= FloatType(0) - m.x_hidden .= FloatType(0) - m.der_x_hidden .= FloatType(0) - m.der_x_full .= FloatType(0) + # Provide storage for x and der_x utility vectors + m.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] + m.x_init = zeros(FloatType,nx) + m.x_segment = zeros(FloatType, nxSegment) + m.der_x_invariant = zeros(FloatType,equationInfo.nxInvariant) + m.der_x_segment = zeros(FloatType, nxSegment) + m.der_x = zeros(FloatType,nx) # Log parameters if m.options.logParameters @@ -1263,12 +1094,9 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Perform initial event iteration m.nGetDerivatives = 0 - m.nf = 0 - m.isInitial = true - eh.initial = true -# m.storeResult = true -# m.getDerivatives!(m.der_x, m.x_start, m, startTime) -# Base.invokelatest(m.getDerivatives!, m.der_x, m.x_start, m, startTime) + m.nf = 0 + m.isInitial = true + eh.initial = true for i in eachindex(m.x_init) m.x_init[i] = deepcopy(m.x_start[i]) end @@ -1278,10 +1106,100 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti m.isInitial = false m.storeResult = false eh.afterSimulationStart = true + return true end +""" + initFullRestart!(instantiatedModel) + +Re-initialize `instantiatedModel` after a `FullRestart` event. +""" +function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where {FloatType,TimeType} + if m.options.log + println(" Reinitialization due to FullRestart at time = ", m.time, " s") + end + eh = m.eventHandler + result = m.result + removeSegmentStates!(m.equationInfo) + empty!(result.alias_segment_names) + empty!(result.w_segment_names) + empty!(result.w_segment_temp) + newResultSegment!(m.result) + m.nsegment += 1 + m.options.startTime = m.time + reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) + + # Evaluate instantiate functions + for fc in m.instantiatedFunctions + logInstantiatedFunctionCalls = false + Core.eval(m.modelModule, :($(fc[1])($m, $(fc[2]), $(fc[3]), log=$logInstantiatedFunctionCalls))) + end + + # Get initial state vector + m.x_start = initialStateVector!(m.equationInfo, m.result, FloatType) + + # Resize states and results + nx = length(m.x_start) + nxSegment = nx - m.equationInfo.nxInvariant + resize!(m.x_init , nx) + resize!(m.x_segment , nxSegment) + resize!(m.der_x_invariant, m.equationInfo.nxInvariant) + resize!(m.der_x_segment , nxSegment) + resize!(m.der_x , nx) + m.x_init .= FloatType(0) + m.x_segment .= FloatType(0) + m.der_x_invariant .= FloatType(0) + m.der_x_segment .= FloatType(0) + m.der_x .= FloatType(0) + + # Update locationIDs for x_segment and der_x_segment + eqInfo = m.equationInfo + x_info = eqInfo.x_info + resultInfo = m.result.info + nsegment = m.nsegment + @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) + for i = eqInfo.nx_info_invariant+1:length(x_info) + xi_info = x_info[i] + resInfo = resultInfo[xi_info.x_name] + push!(resInfo.locationID, LocationID(nsegment, resInfo.startIndex, size(resInfo.startOrInit))) + resInfo = resultInfo[xi_info.der_x_name] + push!(resInfo.locationID, LocationID(nsegment, resInfo.startIndex, size(resInfo.startOrInit))) + end + eqInfo.status = EquationInfo_After_All_States_Are_Known + + if m.options.logStates + # List init/start values + x_table = DataFrames.DataFrame(state=String[], init=Any[], unit=String[]) #, nominal=String[]) + for xe_info in m.equationInfo.x_info + xe_init = get_xe(m.x_start, xe_info) + if hasParticles(xe_init) + xe_init = string(minimum(xe_init)) * " .. " * string(maximum(xe_init)) + end + # xe_nominal = isnan(xe_info.nominal) ? "" : xe_info.nominal + push!(x_table, (xe_info.x_name, xe_init, xe_info.unit)) #, xe_nominal)) + end + show(stdout, x_table; allrows=true, allcols=true, rowlabel = Symbol("#"), summary=false, eltypes=false) + println("\n") + end + + # Perform event iteration + m.isInitial = true + eh.initial = true + for i in eachindex(m.x_init) + m.x_init[i] = deepcopy(m.x_start[i]) + end + eventIteration!(m, m.x_init, m.options.startTime) + m.success = false # is set to true at the first outputs! call. + eh.fullRestart = false + eh.initial = false + m.isInitial = false + m.storeResult = false + eh.afterSimulationStart = true + return nothing +end + """ success = check_vSolvedWithInitValuesAndUnit(m::SimulationModel) @@ -1359,27 +1277,24 @@ function outputs!(x, t, integrator)::Nothing invokelatest_getDerivatives_without_der_x!(x, m, t) else if t==m.options.startTime - m.der_x_full .= integrator.du # Since IDA gives an error for integrator(t, Val{1]}) at the initial time instant + m.der_x .= integrator.du # Since IDA gives an error for integrator(t, Val{1]}) at the initial time instant else - integrator(m.der_x_full, t, Val{1}) # Compute derx by interpolation + integrator(m.der_x, t, Val{1}) # Compute derx by interpolation end # Copy derx to linearEquations for copyInfo in m.daeCopyInfo leq = m.linearEquations[ copyInfo.ileq ] for i in 1:length(copyInfo.index) - leq.x[i] = m.der_x_full[ copyInfo.index[i] ] + leq.x[i] = m.der_x[ copyInfo.index[i] ] end end m.solve_leq = false invokelatest_getDerivatives_without_der_x!(x, m, t) m.solve_leq = true end - copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) - push!(m.result_der_x, deepcopy(m.der_x_full)) m.storeResult = false if !m.success - m.result_x = integrator.sol m.success = check_vSolvedWithInitValuesAndUnit(m) if !m.success DifferentialEquations.terminate!(integrator) @@ -1414,17 +1329,17 @@ end """ - copyDerivatives!(der_x, der_x_visible, der_x_hidden) + copyDerivatives!(der_x, der_x_invariant, der_x_segment) -Copy der_x_visible and der_x_hidden to der_x (der_x .= [der_x_visible, der_x_hidden]) +Copy der_x_invariant and der_x_segment to der_x (der_x .= [der_x_invariant, der_x_segment]) """ -@inline function copyDerivatives!(der_x, der_x_visible, der_x_hidden)::Nothing - if length(der_x_hidden) == 0 - der_x .= der_x_visible +@inline function copyDerivatives!(der_x, der_x_invariant, der_x_segment)::Nothing + if length(der_x_segment) == 0 + der_x .= der_x_invariant else - @assert(length(der_x) == length(der_x_visible) + length(der_x_hidden)) - unsafe_copyto!(der_x, 1, der_x_visible, 1, length(der_x_visible)) - unsafe_copyto!(der_x, length(der_x_visible)+1, der_x_hidden, 1, length(der_x_hidden)) + @assert(length(der_x) == length(der_x_invariant) + length(der_x_segment)) + unsafe_copyto!(der_x, 1, der_x_invariant, 1, length(der_x_invariant)) + unsafe_copyto!(der_x, length(der_x_invariant)+1, der_x_segment, 1, length(der_x_segment)) end return nothing end @@ -1438,8 +1353,8 @@ DifferentialEquations callback function to get the derivatives. function derivatives!(der_x, x, m, t) m.nf += 1 invokelatest_getDerivatives_without_der_x!(x, m, t) - #println("t = $t, m.der_x_hidden = ", m.der_x_hidden) - copyDerivatives!(der_x, m.der_x_visible, m.der_x_hidden) + #println("t = $t, m.der_x_segment = ", m.der_x_segment) + copyDerivatives!(der_x, m.der_x_invariant, m.der_x_segment) return nothing end @@ -1465,8 +1380,8 @@ function DAEresidualsForODE!(residuals, derx, x, m, t)::Nothing invokelatest_getDerivatives_without_der_x!(x, m, t) m.solve_leq = true - copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) - residuals .= m.der_x_full .- derx + copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segment) + residuals .= m.der_x .- derx # Get residuals from linearEquations for copyInfo in m.daeCopyInfo @@ -1501,7 +1416,7 @@ function affectEvent!(integrator, stateEvent::Bool, eventIndex::Int)::Nothing sol_t = integrator.sol.t sol_x = integrator.sol.u ilast = length(sol_t) - for i = length(m.result_code)+1:ilast # -1 + for i = length(m.result.t[end])+1:ilast # -1 outputs!(sol_x[i], sol_t[i], integrator) end # A better solution is needed. @@ -1685,113 +1600,238 @@ function resizeLinearEquations!(m::SimulationModel{FloatType,TimeType}, evaluate end - - """ - addToResult!(simulationModel, der_x, variableValues...) + addToResult!(instantiatedModel, x, time, w_invariant...) -Add `variableValues...` to `simulationModel::SimulationModel`. -It is assumed that the first variable in `variableValues` is `time`. +Add result of current time instant (`time, x, der_x, w_invariant, w_segment`) to `instantiatedModel`. """ -@inline function addToResult!(m::SimulationModel, variableValues...)::Nothing - @assert(length(variableValues) == m.n_result_code) - push!(m.result_code , deepcopy(variableValues)) - push!(m.result_extra, deepcopy(m.result_extra_temp)) +function addToResult!(m::SimulationModel, x, time, w_invariant...)::Nothing + @assert(length(w_invariant) == m.result.n_w_invariant) + copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segment) + result = m.result + push!(result.t[ end], time) + push!(result.x[ end], deepcopy(x)) + push!(result.der_x[ end], deepcopy(m.der_x)) + push!(result.w_invariant[end], deepcopy(w_invariant)) + push!(result.w_segment[ end], deepcopy(m.result.w_segment_temp)) return nothing end """ - addHiddenStatesAndExtraResultsTo_result_info!(simulationModel) - -Add hidden states and its derivatives, as well as extra results to result_info. -""" -function addHiddenStatesAndExtraResultsTo_result_info!(m::SimulationModel)::Nothing - result_info = m.result_info + startIndex = new_x_segment_variable!(instantiatedModel::SimulationModel, + x_name::String, der_x_name::String, startOrInit, x_unit::String=""; + nominal::Float64 = NaN, unbounded::Bool = false)::Int + +Reserve storage location for a new x_segment and der_x_segment variable. The returned startIndex is used + +- to copy state values from instantiatedModel.x_segment[startIndex:startIndex+prod(dims(startOrInit))-1] into the internal states +- to copy internal state derivative values to instantiatedModel.der_x_segment[startIndex:startIndex+prod(dims(startOrInit))-1] + +Value startOrInit is the start/init value used during re-initialization of the new segment with initFullRestart!(..). +""" +function new_x_segment_variable!(eqInfo::EquationInfo, result::Result, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; + nominal::Float64 = NaN, unbounded::Bool = false)::Int + @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) + new_result_info = true + if haskey(result.info, x_name) + # State was already defined in one of the previous segments + new_result_info = false + x_info = result.info[x_name] + @assert(x_info.kind == RESULT_X) + @assert(x_info.type == typeof(startOrInit)) + @assert(x_info.unit == x_unit) + @assert(x_info.ndims == ndims(startOrInit)) + @assert(x_info.signalKind == ModiaResult.Continuous) + @assert(!x_info.invariant) + @assert(eqInfo.x_dict, x_name) + + @assert(haskey(result.info, der_x_name)) + der_x_info = result.info[der_x_name] + @assert(der_x_info.kind == RESULT_DER_X) + @assert(der_x_info.type == typeof(startOrInit)) + #@assert(der_x_info.unit == der_x_unit) + @assert(der_x_info.ndims == ndims(startOrInit)) + @assert(der_x_info.signalKind == ModiaResult.Continuous) + @assert(!der_x_info.invariant) + @assert(eqInfo.der_x_dict, der_x_name) + end - # Add hidden x and der_x to result_info - eqInfo = m.equationInfo - for xe_index = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) - xe_info = eqInfo.x_info[xe_index] - result_info[xe_info.x_name] = ResultInfo(RESULT_X, xe_index) + x_segment_startIndex = eqInfo.nxSegment+1 + xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), + XD, x_unit, startOrInit, true, nominal, unbounded, + x_segment_startIndex = x_segment_startIndex) + push!(eqInfo.x_info, xi_info) + x_infoIndex = length(eqInfo.x_info) + eqInfo.x_dict[x_name] = x_infoIndex + eqInfo.der_x_dict[der_x_name] = x_infoIndex + eqInfo.nxSegment += length(startOrInit) + + if new_result_info + # result.info can be only partially instantiated, because x_startIndex is only known + # after function initialStateVector!(...) was called. + t_unit = result.info[result.timeName].unit + der_x_unit = x_unit == "" ? unitAsString(unit(1/uparse(t_unit))) : unitAsString(unit(uparse(x_unit)/uparse(t_unit))) + result.info[x_name] = ResultInfo(RESULT_X , startOrInit, x_unit , false) + result.info[der_x_name] = ResultInfo(RESULT_DER_X, startOrInit, der_x_unit, false) end - for xe_index = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) - xe_info = eqInfo.x_info[xe_index] - result_info[xe_info.der_x_name] = ResultInfo(RESULT_DER_X, xe_index) + return x_segment_startIndex +end +new_x_segment_variable!(m::SimulationModel, args...; kwargs...) = new_x_segment_variable!(m.equationInfo, m.result, args...; kwargs...) + + +""" + index = new_w_segment_variable!(partiallyInstantiatedModel::SimulationModel, name::String, + w_segment_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int + +Reserve storage location for a new w_segment variable. The returned `index` is +used to store the w_segment value at communication points in the result data structure. +Value w_segment_default is stored as default value and defines type and (fixed) size of the variable +in this segment. +""" +function new_w_segment_variable!(m::SimulationModel, name::String, w_segment_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int + result = m.result + w_size = size(w_segment_default) + + if haskey(result.info, name) + # Variable was already defined in one of the previous segments + v_info = result.info[name] + @assert(!haskey(result.w_segment_names, name)) + @assert(v_info.kind == RESULT_W_SEGMENT) + @assert(v_info.type == typeof(w_segment_default)) + @assert(v_info.unit == unit) + @assert(v_info.ndims == ndims(w_segment_default)) + @assert(v_info.signalKind == signalKind) + @assert(!v_info.invariant) + push!(result.w_segment_names, name) + push!(result.w_segment_temp, deepcopy(w_segment_default)) + w_segment_index = length(result_w_segment_temp) + push!(v_info.locationID, LocationID(m.nsegment, w_segment_index, size(w_segment_default))) + else + # Variable is defined the first time in the segmented simulation + push!(result.w_segment_names, name) + push!(result.w_segment_temp, deepcopy(w_segment_default)) + w_segment_index = length(result.w_segment_temp) + result.info[name] = ResultInfo(RESULT_W_SEGMENT, w_segment_default, unit, signalKind, m.nsegment, w_segment_index) end - - # Add extra results to result_info - merge!(result_info, m.result_extra_info) - @assert(length(m.result_extra_info) == length(m.result_extra_temp)) - return nothing + println("new_w_segment_variable: w_segment_temp = ", result.w_segment_temp) + return w_segment_index end """ - removeHiddenStatesAndExtraResults!(simulationModel) + new_alias_segment_variable!(partiallyInstantiatedModel, name, aliasName, aliasNegate=false) -Remove hidden states, their derivatives, as well as extra result from result_info, -and remove hidden states from equationInfo. +Define new alias segment variable. """ -function removeHiddenStatesAndExtraResults!(m::SimulationModel)::Nothing - # Remove hiddens states and their derivatives from result_info - x_info = m.equationInfo.x_info - for xe_index = m.equationInfo.nx_infoVisible+1:length(x_info) - delete!(m.result_info, x_info[xe_index].x_name) - delete!(m.result_info, x_info[xe_index].der_x_name) +function new_alias_segment_variable!(m::SimulationModel, name::String, aliasName::String, aliasNegate::Bool=false)::Int + result = m.result + w_size = size(w_segment_default) + + if haskey(result.info, name) + error("new_alias_segment_variable!(...): $name is already defined") + elseif !haskey(result.info, aliasName) + error("new_alias_segment_variable!(...): $name should be made an alias to $aliasName, but this name is not defined") end + result.info[name] = ResultInfo(RESULT_ELIMINATED, aliasName, aliasNegate) + push!(result.alias_segment_names, name) + return nothing +end - # Remove hidden states from equationInfo - removeHiddenStates!(m.equationInfo) - # Remove extra results from result_info - for (name,index) in m.result_extra_info - delete!(m.result_info, name) +""" + startIndex = new_z_segment_variable!(instantiatedModel, nz) + +Reserve storage location for nz new segment zero crossing function and return the startIndex to +copy it in the vectors of zero crossings +""" +function new_z_segment_variable!(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} + eh = m.eventHandler + zStartIndex = eh.nz + 1 + eh.nz += nz + resize!(eh.z, eh.nz) + resize!(eh.zPositive, eh.nz) + for i = zStartIndex:eh.nz + eh.z[i] = convert(F, 1.0) + eh.zPositive[i] = false end - empty!(m.result_extra_info) - m.result_extra_temp .= nothing - resize!(m.result_extra_temp , 0) - return nothing + return zStartIndex end +""" + value = Modia.get_scalar_x_segment_value(instantiatedModel, startIndex) +Return scalar segment state value from instantiatedModel given `startIndex` +(returned from `new_x_segment_variable!(..)`). """ - extraResult_index = newExtraResult!(partiallyInstantiatedModel::SimulationModel, name::String, defaultExtraResult)::Int +get_scalar_x_segment_value(m::SimulationModel, startIndex::Int) = m.x_segment[startIndex] + -Reserve storage location for one extra result variable. The returned extraResult_index is -used to store extra results at communication points in the result data structure. -Value defaultExtraResult is stored as default value for the extra result -(`addExtraResult!(.., extraResult)`: `defaultExtraResult` and `extraResult` must have the same type and size) """ -function newExtraResult!(m::SimulationModel, name::String, defaultExtraResult)::Int - if haskey(m.result_info, name) || haskey(m.result_extra_info, name) - error("Trying to add extra result variable $name but this name is already in use!") - end - extraResult_index = length(m.result_extra_info)+1 - m.result_extra_info[name] = ResultInfo(RESULT_EXTRA, extraResult_index) - push!(m.result_extra_temp, defaultExtraResult) - return extraResult_index + value = Modia.get_SVector3_x_segment_value(instantiatedModel, startIndex) + +Return SVector{3,FloatType}(..) segment state value from instantiatedModel given `startIndex` +(returned from `new_x_segment_variable!(..)`). +""" +@inline get_SVector3_x_segment_value(m::SimulationModel{FloatType,TimeType}, startIndex::Int) where {FloatType,TimeType} = begin + x_segment = m.x_segment + return SVector{3,FloatType}(x_segment[startIndex], x_segment[startIndex+1], x_segment[startIndex+2]) end +""" + Modia.get_Vector_x_segment_value!(instantiatedModel::SimulationModel, startIndex, xi::Vector{FloatType})::Nothing +Copy state from `instantiatedModel` at index `startIndex` into pre-allocated vector `xi`. """ - addExtraResult!(instantiatedModel::SimulationModel, extraResult_index::Int, extraResult)::Nothing +@inline function get_Vector_x_segment_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, xi::Vector{FloatType})::Nothing where {FloatType,TimeType} + copyto!(xi, 1, m.x_segment, startIndex, length(xi)) + return nothing +end + -Store deepcopy(extraResult) at extraResult_index in instantiatedModel. """ -@inline function addExtraResult!(m::SimulationModel, extraResult_index::Int, extraResult)::Nothing - m.result_extra_temp[extraResult_index] = extraResult + Modia.add_der_x_segment_value!(instantiatedModel, startIndex, der_x_segment_value::[FloatType|Vector{FloatType}]) + +Copy scalar or array segment state derivative value `der_x_segment_value` into `instantiatedModel` starting at index `startIndex` +(returned from `new_x_segment_variable!(..)`). +""" +@inline function add_der_x_segment_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segment::FloatType)::Nothing where {FloatType,TimeType} + m.der_x_segment[startIndex] = der_x_segment_value + return nothing +end +@inline function add_der_x_segment_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segment_value::Vector{FloatType})::Nothing where {FloatType,TimeType} + copyto!(m.der_x_segment, startIndex, der_x_segment_value, 1, length(der_x_segment_value)) return nothing end +""" + Modia.add_w_segment_value!(instantiatedModel::SimulationModel, index::Int, w_segment_value)::Nothing + +Store deepcopy(w_segment_value) at index in instantiatedModel. +""" +@inline function add_w_segment_value!(m::SimulationModel, index::Int, w_segment_value)::Nothing + w_segment_temp = m.result.w_segment_temp + @assert(typeof(w_segment_value) == typeof(w_segment_temp[index])) + @assert(size( w_segment_value) == size( w_segment_temp[index])) + w_segment_temp[index] = deepcopy(w_segment_value) + return nothing +end +function initialStateVector!(m::SimulationModel{FloatType,TimeType})::Vector{FloatType} where {FloatType,TimeType} + if length(m.equationInfo.x_info) == 0 + # Handle systems with only algebraic variables, by introducing a dummy + # differential equation der_x[1] = -x[1], with state name _dummy_x + new_x_segment_variable!(m, "_dummy_x", "der(_dummy_x)", FloatType(0)) + end + return initialStateVector!(m.equationInfo, FloatType) +end """ - code = generate_getDerivatives!(AST, equationInfo, parameters, variables, functionName; + code = generate_getDerivatives!(AST, equationInfo, parameters, timeName, w_invariant_names, functionName; hasUnits=false) Return the code of the `getDerivatives!` function as `Expr` using the @@ -1807,7 +1847,9 @@ Symbol `functionName` as function name. By `eval(code)` or - `parameters`: Vector of parameter names (as vector of symbols) -- `variables`: Vector of variable names (as vector of symbols). The first entry is expected to be time, so `variables[1] = :time`. +- `timeName`: Name of time (as symbol) + +- `w_invariant_names`: Vector of variable names (as vector of symbols or Expr). - `functionName::Function`: The name of the function that shall be generated. @@ -1819,7 +1861,7 @@ Symbol `functionName` as function name. By `eval(code)` or - `hasUnits::Bool`: = true, if variables have units. Note, the units of the state vector are defined in equationinfo. """ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equationInfo::Modia.EquationInfo, - parameters, variables, previousVars, preVars, holdVars, functionName::Symbol; + parameters, timeName, w_invariant_names, previousVars, preVars, holdVars, functionName::Symbol; pre::Vector{Symbol} = Symbol[], hasUnits=false) # Generate code to copy x to struct and struct to der_x @@ -1828,12 +1870,9 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati code_der_x = Expr[] #code_p = Expr[] - if length(x_info) == 1 && x_info[1].x_name == "_dummy_x" && x_info[1].der_x_name == "der(_dummy_x)" - # Explicitly solved pure algebraic variables. Introduce dummy equation - push!(code_der_x, :( Modia.appendVariable!(_m.der_x_visible, -_x[1]) )) - else + if length(x_info) > 0 i1 = 1 - for i in 1:equationInfo.nx_infoFixed + for i in 1:equationInfo.nx_info_fixedLength xe = x_info[i] x_name = xe.x_name_julia # x_name = Meta.parse("m."*xe.x_name) @@ -1866,7 +1905,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati end i1 = 0 - for i in equationInfo.nx_infoFixed+1:equationInfo.nx_infoVisible + for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant # x-element is a dynamic vector (length can change before initialization) xe = x_info[i] x_name = xe.x_name_julia @@ -1879,22 +1918,17 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati end end - for i in 1:equationInfo.nx_infoVisible + for i in 1:equationInfo.nx_info_invariant xe = equationInfo.x_info[i] der_x_name = xe.der_x_name_julia if hasUnits - push!(code_der_x, :( Modia.appendVariable!(_m.der_x_visible, Modia.stripUnit( $der_x_name )) )) + push!(code_der_x, :( Modia.appendVariable!(_m.der_x_invariant, Modia.stripUnit( $der_x_name )) )) else - push!(code_der_x, :( Modia.appendVariable!(_m.der_x_visible, $der_x_name) )) + push!(code_der_x, :( Modia.appendVariable!(_m.der_x_invariant, $der_x_name) )) end end end - #for (i,pi) in enumerate(parameters) - # push!(code_p, :( $pi = _m.p[$i] ) ) - #end - - timeName = variables[1] if hasUnits code_time = :( $timeName = _time*upreferred(u"s") ) else @@ -1924,17 +1958,6 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati push!(code_pre, :( _m.nextPre[$i] = $preName )) end - # Code for deepcopy of vectors with pre-allocated memory (no longer needed, since deepCopy of everything inside addToResult!) - #code_copy = Expr[] - #for leq_tuple in equationInfo.linearEquations - # x_vec_julia_names = leq_tuple[2] - # for name in x_vec_julia_names - # push!(code_copy, :( $name = deepcopy($name) )) - # end - #end - # if _m.storeResult - # $(code_copy...) - # Generate code of the function # temporarily removed: _m.time = $TimeType(Modia.getValue(_time)) code = quote @@ -1954,7 +1977,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati $(code_pre...) if Modia.storeResults(_m) - Modia.TimerOutputs.@timeit _m.timer "Modia addToResult!" Modia.addToResult!(_m, $(variables...)) + Modia.TimerOutputs.@timeit _m.timer "Modia addToResult!" Modia.addToResult!(_m, _x, _time, $(w_invariant_names...)) end return nothing end diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 68643d5..c40b2a3 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -506,7 +506,7 @@ end """ xe_info = StateElementInfo(x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, startOrInit, fixed, nominal, unbounded; - startIndex=-1) + startIndex=-1, x_segment_startIndex=-1) Return an instance of the mutable struct `StateElementInfo` that defines the information for one element of the state vector. @@ -526,7 +526,8 @@ for one element of the state vector. Only relevant for ode=false, otherwise ignored. - nominal: Nominal value (NaN if determined via startOrInit value) - unbounded: false or true -- startIndex: = -1, if not yet known. If hidden state, startIndex with respect to x_hidden. +- startIndex: = -1, if not yet known. startIndex with respect to x. +- x_segment_startIndex: =-1, if not yet known. startIndex with respect to x_segment. """ mutable struct StateElementInfo x_name::String # Modia name of x-element or "" if no name @@ -550,8 +551,8 @@ mutable struct StateElementInfo # = false, if vector length::Int # length of x-element or -1 if not yet known startIndex::Int # start index of state with respect to x-vector or -1 if not yet known - x_hidden_startIndex::Int # start index of hidden state with respect to x_hidden vector - # or -1, if it is no hidden state (for a hidden state, x_hidden_startIndex + x_segment_startIndex::Int # start index of segment state with respect to x_segment vector + # or -1, if it is no segment state (for a segment state, x_segment_startIndex # is consistently set when it is added via newHiddenState(..)). end @@ -560,11 +561,11 @@ end # Constructor for code-generation StateElementInfo(x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, startOrInit, fixed, nominal, unbounded; - startIndex = -1, x_hidden_startIndex=-1) = StateElementInfo( + startIndex = -1, x_segment_startIndex=-1) = StateElementInfo( x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, deepcopy(startOrInit), fixed, nominal, unbounded, isFixedLengthStartOrInit(startOrInit, x_name), !(startOrInit isa AbstractArray), - startOrInit isa Nothing ? 1 : length(startOrInit), startIndex, x_hidden_startIndex) + startOrInit isa Nothing ? 1 : length(startOrInit), startIndex, x_segment_startIndex) function Base.show(io::IO, xe_info::StateElementInfo) print(io, "Modia.StateElementInfo(") @@ -586,7 +587,7 @@ function Base.show(io::IO, xe_info::StateElementInfo) print(io, ",", xe_info.scalar) print(io, ",", xe_info.length) print(io, ",", xe_info.startIndex) - print(io, ",", xe_info.x_hidden_startIndex) + print(io, ",", xe_info.x_segment_startIndex) print(io, ")") return nothing end @@ -613,7 +614,7 @@ function get_x_table(x_info::Vector{StateElementInfo}) end -@enum EquationInfoStatus EquationInfo_Instantiated EquationInfo_Initialized_Before_Code_Generation EquationInfo_After_All_States_Are_Known +@enum EquationInfoStatus EquationInfo_Instantiated EquationInfo_Initialized_Before_All_States_Are_Known EquationInfo_After_All_States_Are_Known """ eqInfo = EquationInfo() @@ -643,17 +644,17 @@ mutable struct EquationInfo # it is checked whether the calculated values and the start values of # these variables agree. If this is not the case, an error is triggered. nx::Int # = length(x) or -1 if not yet known - # This variable is updated once all states are known. - nxVisible::Int # = number of visible x-elements (so x[1:nxVisible] are visible states) or -1 if not yet known - # This variable is updated once all states are known. - nxHidden::Int # = number of hidden x-elements (x[nxVisible+1:nxVisible+nxHidden]. - # This variable is always updated consistently via function newHiddenState!(..) - # (nxHidden=0, if there are no hidden states yet). - nx_infoFixed::Int # x_info[1:nx_infoFixed] are states with fixed length (does not change after compilation) or -1 if not yet known - nx_infoVisible::Int # x_info[1:nx_infoVisible] are states that are visible in getDerivatives!(..) or -1 if not yet known - # x_info[nx_infoVisible+1:end] are states defined in functions that are not visible in getDerivatives!(..) - #x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] - # # or empty vector, if not yet known. + # This variable is updated once all states are known. + nxInvariant::Int # = number of invariant x-elements (so x[1:nxInvariant] are invariant states) or -1 if not yet known + # This variable is updated once all states are known. + nxSegment::Int # = number of segment x-elements (x[nxInvariant+1:nxInvariant+nxSegment]). + # This variable is always updated consistently via function new_x_segment_variable!(..) + # (nxSegment=0, if there are no segment states yet). + nx_info_fixedLength::Int # x_info[1:nx_info_fixedLength] are states with fixed length (does not change after compilation) or -1 if not yet known + nx_info_invariant::Int # x_info[1:nx_info_invariant] are states that are visible in getDerivatives!(..) or -1 if not yet known + # x_info[nx_info_invariant+1:end] are states defined in functions that are not visible in getDerivatives!(..) + #x_infoByIndex::Vector{Int} # i = x_infoByIndex[j] -> x_info[i] + # # or empty vector, if not yet known. x_dict::OrderedCollections.OrderedDict{String,Int} # x_dict[x_name] returns the index of x_name with respect to x_info der_x_dict::OrderedCollections.OrderedDict{String,Int} # der_x_dict[der_x_name] returns the index of der_x_name with respect to x_info defaultParameterAndStartValues::Union{AbstractDict,Nothing} # Dictionary of default parameter and default start values. @@ -666,41 +667,41 @@ mutable struct EquationInfo linearEquations = Tuple{Vector{String},AbstractVector,Vector{Int},Int,Bool}[] vSolvedWithFixedTrue = String[] nx = -1 - nxVisible = -1 - nxHidden = 0 - nx_infoFixed = -1 - nx_infoVisible = -1 + nxInvariant = -1 + nxSegment = 0 + nx_info_fixedLength = -1 + nx_info_invariant = -1 x_dict = OrderedCollections.OrderedDict{String,Int}() der_x_dict = OrderedCollections.OrderedDict{String,Int}() defaultParameterAndStartValues = nothing new(EquationInfo_Instantiated, ode, nz, x_info, residualCategories, linearEquations, vSolvedWithFixedTrue, - nx, nxVisible, nxHidden, nx_infoFixed, nx_infoVisible, x_dict, der_x_dict, + nx, nxInvariant, nxSegment, nx_info_fixedLength, nx_info_invariant, x_dict, der_x_dict, defaultParameterAndStartValues) end end """ - initEquationInfo!(eqInfo::EquationInfo, nx_infoFixed) + initEquationInfo!(eqInfo::EquationInfo, nx_info_fixedLength) Initialize `eqInfo` before code generation. -`nx_infoFixed` are the number of states with fixed length (do not change after compilation). +`nx_info_fixedLength` are the number of states with fixed length (do not change after compilation). The following variables get a consistent value: ``` eqInfo.x_dict[x_name] = ..., eqInfo.der_x_dict[der_x_name] = ..., -eqInfo.nx, eqInfo.nxVisible, -eqInfo.nx_infoFixed, eqInfo.nx_infoVisible, +eqInfo.nx, eqInfo.nxInvariant, +eqInfo.nx_info_fixedLength, eqInfo.nx_info_invariant, eqInfo.x_info[:].startIndex. ``` -This function must be called before hidden states are set (eqInfo.nxHidden=0). +This function must be called before segment states are set (eqInfo.nxSegment=0). """ -function initEquationInfo!(eqInfo::EquationInfo, nx_infoFixed::Int)::Nothing +function initEquationInfo!(eqInfo::EquationInfo, nx_info_fixedLength::Int)::Nothing @assert(eqInfo.status == EquationInfo_Instantiated) - @assert(eqInfo.nxHidden == 0) + @assert(eqInfo.nxSegment == 0) x_dict = eqInfo.x_dict der_x_dict = eqInfo.der_x_dict startIndex = 1 @@ -710,63 +711,34 @@ function initEquationInfo!(eqInfo::EquationInfo, nx_infoFixed::Int)::Nothing xi_info.startIndex = startIndex startIndex += xi_info.length end - eqInfo.nx = startIndex - 1 - eqInfo.nxVisible = eqInfo.nx - eqInfo.nx_infoFixed = nx_infoFixed - eqInfo.nx_infoVisible = length(eqInfo.x_info) + eqInfo.nx = startIndex - 1 + eqInfo.nxInvariant = eqInfo.nx + eqInfo.nx_info_fixedLength = nx_info_fixedLength + eqInfo.nx_info_invariant = length(eqInfo.x_info) - eqInfo.status = EquationInfo_Initialized_Before_Code_Generation + eqInfo.status = EquationInfo_Initialized_Before_All_States_Are_Known return nothing end -function newHiddenState!( - eqInfo::EquationInfo, - x_name::String, - der_x_name::String, - startOrInit; - stateCategory::StateCategory = XD, - unit::String = "", - fixed::Bool = true, - nominal::Float64 = NaN, - unbounded::Bool = false)::Int - @assert(eqInfo.status == EquationInfo_Initialized_Before_Code_Generation) - if haskey(eqInfo.x_dict, x_name) || - haskey(eqInfo.der_x_dict, der_x_name) - error("Trying to add hidden state x_name=$x_name, der_x_name=$der_x_name but one or both names are already in use!") - end - - x_hidden_startIndex = eqInfo.nxHidden+1 - xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), - stateCategory, unit, startOrInit, fixed, nominal, unbounded, - x_hidden_startIndex = x_hidden_startIndex) - push!(eqInfo.x_info, xi_info) - x_infoIndex = length(eqInfo.x_info) - eqInfo.x_dict[x_name] = x_infoIndex - eqInfo.der_x_dict[der_x_name] = x_infoIndex - eqInfo.nxHidden += length(startOrInit) - return x_hidden_startIndex -end - - """ - removeHiddenStates!(eqInfo::EquationInfo) + removeSegmentStates!(eqInfo::EquationInfo) -Remove all hidden (non-visible) states from `eqInfo`. +Remove all segment states from `eqInfo`. """ -function removeHiddenStates!(eqInfo::EquationInfo)::Nothing +function removeSegmentStates!(eqInfo::EquationInfo)::Nothing @assert(eqInfo.status == EquationInfo_After_All_States_Are_Known) - if eqInfo.nx > eqInfo.nxVisible - for i = eqInfo.nx_infoVisible+1:length(eqInfo.x_info) + if eqInfo.nx > eqInfo.nxInvariant + for i = eqInfo.nx_info_invariant+1:length(eqInfo.x_info) xi_info = eqInfo.x_info[i] delete!(eqInfo.x_dict , xi_info.x_name) delete!(eqInfo.der_x_dict, xi_info.der_x_name) end - resize!(eqInfo.x_info, eqInfo.nx_infoVisible) - eqInfo.nx = eqInfo.nxVisible + resize!(eqInfo.x_info, eqInfo.nx_info_invariant) + eqInfo.nx = eqInfo.nxInvariant end - eqInfo.nxHidden = 0 - eqInfo.status = EquationInfo_Initialized_Before_Code_Generation + eqInfo.nxSegment = 0 + eqInfo.status = EquationInfo_Initialized_Before_All_States_Are_Known return nothing end @@ -774,45 +746,40 @@ end """ x_start = initialStateVector!(eqInfo::EquationInfo, FloatType)::Vector{FloatType} -The function updates `eqInfo` (e.g. sets eqInfo.nx, eqInfo.nxVisible) and returns the initial state vector x_start. +The function updates `eqInfo` (e.g. sets eqInfo.nx, eqInfo.nxInvariant) and returns the initial state vector x_start. This function must be called, after all states are known (after calling propagateEvaluateAndInstantiate!(..)). """ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{FloatType} - @assert(eqInfo.status == EquationInfo_Initialized_Before_Code_Generation) - nx_infoFixed = eqInfo.nx_infoFixed - x_info = eqInfo.x_info - - if length(x_info) == 0 - # Handle systems with only algebraic variables, by introducing a dummy - # differential equation der_x[1] = -x[1], with state name _dummy_x - newHiddenState!(eqInfo, "_dummy_x", "der(_dummy_x)", FloatType(0.0)) - startIndex = 1 - elseif nx_infoFixed == 0 + @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) + nx_info_fixedLength = eqInfo.nx_info_fixedLength + x_info = eqInfo.x_info + + if nx_info_fixedLength == 0 startIndex = 1 else - xi_info = x_info[nx_infoFixed] + xi_info = x_info[nx_info_fixedLength] startIndex = xi_info.startIndex + xi_info.length end - # Set startIndex for visible states where the size was not fixed before code generation - for i = nx_infoFixed+1:eqInfo.nx_infoVisible + # Set startIndex for invariant states where the size was not fixed before code generation + for i = nx_info_fixedLength+1:eqInfo.nx_info_invariant xi_info = x_info[i] xi_info.length = length(xi_info.startOrInit) xi_info.startIndex = startIndex startIndex += xi_info.length end - eqInfo.nxVisible = startIndex - 1 + eqInfo.nxInvariant = startIndex - 1 - # Set startIndex for hidden states - for i = eqInfo.nx_infoVisible+1:length(x_info) + # Set startIndex for segment states + for i = eqInfo.nx_info_invariant+1:length(x_info) xi_info = x_info[i] xi_info.length = length(xi_info.startOrInit) xi_info.startIndex = startIndex startIndex += xi_info.length end eqInfo.nx = startIndex - 1 - @assert(eqInfo.nx == eqInfo.nxVisible + eqInfo.nxHidden) + @assert(eqInfo.nx == eqInfo.nxInvariant + eqInfo.nxSegment) # Construct x_start x_start = zeros(FloatType, eqInfo.nx) @@ -904,12 +871,12 @@ function Base.show(io::IO, eqInfo::EquationInfo; indent=4) if eqInfo.nx >= 0 nx = eqInfo.nx - nxVisible = eqInfo.nxVisible - nxHidden = eqInfo.nxHidden - nx_infoFixed = eqInfo.nx_infoFixed - nx_infoVisible = eqInfo.nx_infoVisible - print(io, ",\n", indentation2, "nx = $nx, nxVisible = $nxVisible, nxHidden = $nxHidden") - print(io, ",\n", indentation2, "nx_infoFixed = $nx_infoFixed, nx_infoVisible = $nx_infoVisible") + nxInvariant = eqInfo.nxInvariant + nxSegment = eqInfo.nxSegment + nx_info_fixedLength = eqInfo.nx_info_fixedLength + nx_info_invariant = eqInfo.nx_info_invariant + print(io, ",\n", indentation2, "nx = $nx, nxInvariant = $nxInvariant, nxSegment = $nxSegment") + print(io, ",\n", indentation2, "nx_info_fixedLength = $nx_info_fixedLength, nx_info_invariant = $nx_info_invariant") end if !isnothing(eqInfo.defaultParameterAndStartValues) diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 1eb5c57..97977eb 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -337,7 +337,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType xe_info = eqInfo.x_info[j] x_value = current[k] len = hasParticles(x_value) ? 1 : length(x_value) - if j <= eqInfo.nx_infoFixed && len != xe_info.length + if j <= eqInfo.nx_info_fixedLength && len != xe_info.length printstyled("Model error: ", bold=true, color=:red) printstyled("Length of ", xe_info.x_name, " shall be changed from ", xe_info.length, " to $len\n", @@ -375,7 +375,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType # (1) Generate an instance of subModel and store it in buildDict[path] # (2) Define subModel states and store them in xxx if log - println(" 13: +++ Instantiated $path: $instantiateFunction will be called to instantiate sub-model and define hidden states\n\n") + println(" 13: +++ Instantiated $path: $instantiateFunction will be called to instantiate sub-model and define varying states\n\n") end Core.eval(modelModule, :($instantiateFunction($m, $current, $path, log=$log))) push!(m.instantiateFunctions, (instantiateFunction, current, path)) diff --git a/src/EventHandler.jl b/src/EventHandler.jl index a01845d..69f2991 100644 --- a/src/EventHandler.jl +++ b/src/EventHandler.jl @@ -71,8 +71,8 @@ mutable struct EventHandler{FloatType,TimeType} # For state events: zEps::FloatType # Epsilon for zero-crossing hysteresis nz::Int # Number of event indicators - nzVisible::Int # Number of event indicators defined in visible model equations - # More event indicators can be defined by objects that are not visible in the generated code, i.e. nz >= nzVisible + nzInvariant::Int # Number of event indicators defined in visible model equations + # More event indicators can be defined by objects that are not visible in the generated code, i.e. nz >= nzInvariant # These event indicators are defined in propagateEvaluateAndInstantiate!(..) via _instantiateFunction(..) z::Vector{FloatType} # Vector of event indicators (zero crossings). If one of z[i] passes # zero, that is beforeEvent(z[i])*z[i] < 0, an event is triggered @@ -117,11 +117,11 @@ end #EventHandler{FloatType}(; kwargs...) where {FloatType} = EventHandler{FloatType,Float64}(; kwargs...) -function removeHiddenCrossingFunctions!(eh::EventHandler{FloatType,TimeType})::Nothing where {FloatType,TimeType} - if eh.nz > eh.nzVisible - resize!(eh.z, eh.nzVisible) - resize!(eh.zPositive, eh.nzVisible) - eh.nz = eh.nzVisible +function removeSegmentCrossingFunctions!(eh::EventHandler)::Nothing + if eh.nz > eh.nzInvariant + resize!(eh.z, eh.nzInvariant) + resize!(eh.zPositive, eh.nzInvariant) + eh.nz = eh.nzInvariant end return nothing end @@ -159,9 +159,11 @@ function reinitEventHandler!(eh::EventHandler{FloatType,TimeType}, stopTime::Tim eh.zPositive .= false eh.after .= false + removeSegmentCrossingFunctions!(eh) return nothing end + function reinitEventHandlerForFullRestart!(eh::EventHandler{FloatType,TimeType}, currentTime::TimeType, stopTime::TimeType, logEvents::Bool)::Nothing where {FloatType,TimeType} eh.nRestartEvents += 1 eh.nFullRestartEvents += 1 @@ -188,6 +190,7 @@ function reinitEventHandlerForFullRestart!(eh::EventHandler{FloatType,TimeType}, eh.zPositive .= false eh.after .= false + removeSegmentCrossingFunctions!(eh) return nothing end diff --git a/src/Modia.jl b/src/Modia.jl index 31374c0..a0c61f9 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-05-31" +const Date = "2022-06-06" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -169,8 +169,8 @@ Return modelPath of submodel as string. """ modelPathAsString(modelPath::Union{Expr,Symbol,Nothing}) = isnothing(modelPath) ? "" : string(modelPath) - include("EquationAndStateInfo.jl") +include("Result.jl") include("StateSelection.jl") include("ModelCollections.jl") diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index f569a1a..9710af5 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -715,21 +715,22 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod holdVars = Symbol.(holdVars) # Variables added to result - result_code_names = vcat(:time, setdiff([Symbol(u) for u in unknowns], - [Symbol(h) for h in hideResults], - Symbol[Symbol(xi_info.x_name_julia) for xi_info in equationInfo.x_info], - Symbol[Symbol(xi_info.der_x_name_julia) for xi_info in equationInfo.x_info])) + timeName = :time + w_invariant_names = setdiff([Symbol(u) for u in unknowns], + [Symbol(h) for h in hideResults], + Symbol[Symbol(xi_info.x_name_julia) for xi_info in equationInfo.x_info], + Symbol[Symbol(xi_info.der_x_name_julia) for xi_info in equationInfo.x_info]) if true # logTiming # println("Generate code") if useNewCodeGeneration - @timeit to "generate_getDerivativesNew!" code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], result_code_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) + @timeit to "generate_getDerivativesNew!" code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], timeName, w_invariant_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) else - @timeit to "generate_getDerivatives!" code = generate_getDerivatives!(FloatType, TimeType, AST, equationInfo, [:(_p)], result_code_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) + @timeit to "generate_getDerivatives!" code = generate_getDerivatives!(FloatType, TimeType, AST, equationInfo, [:(_p)], timeName, w_invariant_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) end else -# code = generate_getDerivatives!(AST, equationInfo, Symbol.(keys(parameters)), result_code_names, :getDerivatives, hasUnits = !unitless) - code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], result_code_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) +# code = generate_getDerivatives!(AST, equationInfo, Symbol.(keys(parameters)), timeName, w_invariant_names, :getDerivatives, hasUnits = !unitless) + code = generate_getDerivativesNew!(AST, newFunctions, modelModule, equationInfo, [:(_p)], timeName, w_invariant_names, previousVars, preVars, holdVars, :getDerivatives, hasUnits = !unitless) end if logCode #@show mappedParameters @@ -765,7 +766,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # println("Build SimulationModel") model = @timeit to "build SimulationModel" SimulationModel{FloatType,TimeType}(modelModule, name, buildDict, getDerivatives, equationInfo, previousVars, preVars, holdVars, - mappedParameters, result_code_names; + mappedParameters, timeName, w_invariant_names; vSolvedWithInitValuesAndUnit, vEliminated, vProperty, var_name = (v)->string(unknownsWithEliminated[v]), nz=nCrossingFunctions, nAfter=nAfter, unitless=unitless) diff --git a/src/Result.jl b/src/Result.jl new file mode 100644 index 0000000..eab5ce3 --- /dev/null +++ b/src/Result.jl @@ -0,0 +1,277 @@ +# License for this file: MIT (expat) +# Copyright 2022, DLR Institute of System Dynamics and Control +# +# Modia result datastrucure and functions operating on results. + +using OrderedCollections: OrderedDict, OrderedSet +import ModiaResult + +""" + @enum ResultKind RESULT_ELIMINATED RESULT_CONSTANT_INVARIANT RESULT_CONSTANT_SEGMENT RESULT_T RESULT_X RESULT_DER_X RESULT_W_INVARIANT RESULT_W_SEGMENT + +Kind of result variable. + +| ResultKind value | Description | +|:-------------------|:------------------------------------------------------------------------| +| RESULT_ELIMINATED | Variable is eliminated - alias info stored in result.info | +| RESULT_CONSTANT | Variable is constant all the time - value stored in result.info | +| RESULT_T | Independent variable (usually time) - stored in result.t | +| RESULT_X | State (invariant/segment variable) - stored in result.x | +| RESULT_DER_X | State derivative (invariant/segment variable) - stored in result.der_x | +| RESULT_W_INVARIANT | Invariant algebraic variable - stored in result.w_invariant | +| RESULT_W_SEGMENT | Segment algebraic variable - stored in result.w_segment | +""" +@enum ResultKind RESULT_ELIMINATED RESULT_CONSTANT RESULT_T RESULT_X RESULT_DER_X RESULT_W_INVARIANT RESULT_W_SEGMENT + + +""" + locationID = LocationID(index, size) # Location id of invariant variable + locationID = LocationID(segment, index, size) # Location id of segment variable + +Return a new location id (defining the location of the values of a variable with respect to ResultKind). +""" +struct LocationID + segment::Int # Index of simulation segment (= -1, if invariant variable) + index::Int # Index or start index with respect to simulation segment (= -1, if time (RESULT_T)) + size::Tuple # Dimensions with respect to simulation segment. size=(): scalar variable or size now known + + LocationID(index, size) = new(-1, index, size) + LocationID(segment, index, size) = new(segment, index, size) +end + + +""" + info = ResultInfo(kind, aliasName; negate=false) # Define alias ResultInfo + info = ResultInfo(kind, value, unit) # Define constant ResultInfo + info = ResultInfo(kind, default, unit, invariant) # Define partial ResultInfo of x or der_x + info = ResultInfo(kind, default, unit, signalKind, index) # Define ResultInfo for invariant variable + info = ResultInfo(kind, default, unit, signalKind, segment, index) # Define ResultInfo for segment variable + +Return info how to access a result variable. +""" +struct ResultInfo + kind::ResultKind # Kind of result variable in simulation segment sk at time instant ti and (invariant or varying) index: + # = RESULT_ELIMINATED : Variable is eliminated. Alias info is stored in result.info + # = RESULT_CONSTANT : Variable is constant all the time. Value is stored in result.info + # = RESULT_T : result.t[ sk][ti] + # = RESULT_X : result.x[ sk][ti][index:index+prod(dims)-1] + # = RESULT_DER_X : result.der_x[ sk][ti][index:index+prod(dims)-1] + # = RESULT_W_INVARIANT: result.w_invariant[sk][ti][index] + # = RESULT_W_SEGMENT : result.w_segment[ sk][ti][index] + + # Only if kind = RESULT_ELIMINATED + aliasName::String # Name of non-eliminated variable + aliasNegate::Bool # = true, if info[aliasName] signal must be negated + + # Only if kind = RESULT_CONSTANT + value::Union{Any,Nothing} # Value of constant variable (without unit) + + # For all kinds with exception of RESULT_ELIMINATED and RESULT_W_INVARIANT + type::Union{DataType,Nothing} # Type of variable (to make sure that the type is not changing) + unit::String # Unit of variable as a parseable string. + ndims::Int # Number of dimensions (= length(dims); to make sure that ndims is not changing) + # ndims = -1, if type=nothing + + # For all kinds with exception of RESULT_ELIMINATED and RESULT_CONSTANT + signalKind::ModiaResult.SignalType # Kind of signal + invariant::Bool # = true, invariant variable + # = false, segment variable + + # For all kinds with exception of RESULT_ELIMINATED, RESULT_CONSTANT and RESULT_T + locationID::Vector{LocationID} # if invariant = true : locationID[1] is location for all segments + # if invariant = false: locationID[i] is segment specific location + + ResultInfo(kind::ResultKind, aliasName::String; negate::Bool=false) = begin + @assert(kind == RESULT_ELIMINATED) + (kind, aliasName, negate) + end + ResultInfo(kind::ResultKind, value, unit::String) = begin + @assert(kind == RESULT_CONSTANT) + (kind, "", false, value, typeof(value), unit, ndims(value)) + end + ResultInfo(kind::ResultKind, default, unit::String, invariant::Bool) = begin + @assert(kind == RESULT_X || kind == RESULT_DER_X ) + new(kind, "", false, nothing, typeof(default), unit, ndims(default), ModiaResult.Continuous, invariant, LocationID[]) + end + ResultInfo(kind::ResultKind, default, unit::String, signalKind, index) = begin + @assert(kind != RESULT_ELIMINATED && kind != RESULT_CONSTANT) + new(kind, "", false, nothing, typeof(default), unit, isnothing(default) ? -1 : ndims(default), + signalKind, true, LocationID[LocationID(index , isnothing(default) ? () : size(default))]) + end + ResultInfo(kind::ResultKind, default, unit::String, signalKind, segment, index) = begin + @assert(kind != RESULT_ELIMINATED && kind != RESULT_CONSTANT) + new(kind, "", false, nothing, typeof(default), unit, ndims(default), signalKind, false, LocationID[LocationID(segment,index,size(default))]) + end +end + + +""" + result = Result{FloatType,TimeType}(timeNameAsString, equationInfo, w_invariant_names, vEliminated, vProperty, var_name) + +Return a new result data structure filled with invariant variable definitions. +""" +mutable struct Result{FloatType,TimeType} + # Result access information + info::OrderedDict{String,ResultInfo} # Dictionary with key = variable name and value = info to access variable value + timeName::String # Name of independent variable (usually time) + timeResultInfo::ResultInfo # Reference to result.info[timeName] + n_w_invariant::Int # Number of w_invariant variables + alias_segment_names::OrderedSet{String} # Names of alias_segment results in current segment + w_segment_names::OrderedSet{String} # Names of w_segment results in current segment + w_segment_temp::Vector{Any} # Memory to store temporarily references to w_segment results in current segment; + # length(w_segment_temp) = length(w_segment_names) + t::Vector{Vector{TimeType}} # t[sk][ti] is time instant ti in segment sk + + # A variable v[sk][ti][j] is variable with index j at time instant ti in segment sk + x::Vector{Vector{Vector{FloatType}}} # x[sk][ti][j] - invariant and segment states + der_x::Vector{Vector{Vector{FloatType}}} # der_x[sk][ti][j] - invariant and segment state derivatives + w_invariant::Vector{Vector{Tuple}} # w_invariant[sk][ti][j] - invariant algebraic variables + w_segment::Vector{Vector{Vector{Any}}} # w_segment[sk][ti][j] - segment algebraic variables + + function Result{FloatType,TimeType}(timeNameAsString::String, eqInfo::EquationInfo, w_invariant_names, vEliminated, vProperty, var_name) where {FloatType,TimeType} + info = OrderedDict{String, ResultInfo}() + n_w_invariant = length(w_invariant_names) + alias_segment_names = OrderedSet{String}() + w_segment_names = OrderedSet{String}() + w_segment_temp = Any[] + t = fill(TimeType[],0) + x = fill(Vector{FloatType}[], 0) + der_x = fill(Vector{FloatType}[], 0) + w_invariant = fill(Tuple[],0) + w_segment = fill(Vector{Any}[], 0) + + # Fill info with time + timeResultInfo = ResultInfo(RESULT_T, TimeType(0), "s", ModiaResult.Independent, -1) + info[timeNameAsString] = timeResultInfo + + # Fill info with x_invariant, der_x_invariant (but with dummy locationID, since not yet known) + for i = 1:eqInfo.nx_info_invariant + xi_info = eqInfo.x_info[i] + x_unit = xi_info.unit + der_x_unit = x_unit == "" ? "1/s" : unitAsString(unit(uparse(x_unit)/u"s")) + @assert(!haskey(info, xi_info.x_name)) + @assert(!haskey(info, xi_info.der_x_name)) + if isnothing(xi_info.startOrInit) + xi_info.startOrInit = FloatType(0) + end + info[xi_info.x_name] = ResultInfo(RESULT_X , xi_info.startOrInit, x_unit , true) + info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, xi_info.startOrInit, der_x_unit, true) + end + + # Fill info with w_invariant + for (w_invariant_index, w_invariant_name) in enumerate(w_invariant_names) + name = string(w_invariant_name) + @assert(!haskey(info, name)) + info[name] = ResultInfo(RESULT_W_INVARIANT, nothing, "", ModiaResult.Continuous, w_invariant_index) + end + + # Fill info with eliminated variables + for v in vEliminated + name = var_name(v) + @assert(!haskey(info, name)) + if ModiaBase.isZero(vProperty, v) + info[name] = ResultInfo(RESULT_CONSTANT, FloatType(0), "") + elseif ModiaBase.isAlias(vProperty, v) + aliasName = var_name( ModiaBase.alias(vProperty, v) ) + @assert(haskey(info, aliasName)) + info[name] = ResultInfo(RESULT_ELIMINATED, aliasName) + else # negated alias + negatedAliasName = var_name( ModiaBase.negAlias(vProperty, v) ) + @assert(haskey(info, negatedAliasName)) + info[name] = ResultInfo(RESULT_ELIMINATED, negatedAliasName, negate=true) + end + end + + new(info, timeNameAsString, timeResultInfo, n_w_invariant, alias_segment_names, w_segment_names, w_segment_temp, t, x, der_x, w_invariant, w_segment) + end +end + + +function newResultSegment!(result::Result{FloatType,TimeType})::Nothing where {FloatType,TimeType} + push!(result.t , TimeType[]) + push!(result.x , Vector{FloatType}[]) + push!(result.der_x , Vector{FloatType}[]) + push!(result.w_invariant, Tuple[]) + push!(result.w_segment , Vector{Any}[]) + return nothing +end + + +""" + iterator = SegmentAndIndex(resultInfo::ResultInfo, nSegments::Int) + +Iterate over the segments of result/resultInfo. +""" +struct SegmentAndIndex + resInfo::ResultInfo + nSegments::Int # Number of segments +end + +@inline function getInvariantLocation(resultInfo::ResultInfo, iter::Int)::NTuple{3,Int} + id = resultInfo.locationID[1] + return (iter, id.index, id.index+prod(id.size)-1) +end + +@inline function getSegmentLocation(resultInfo::ResultInfo, iter::Int)::NTuple{3,Int} + id = resultInfo.locationID[iter] + return (id.segment, id.index, id.index+prod(id.size)-1) +end + +Base.iterate(s::SegmentAndIndex, iter=1) = s.resInfo.invariant ? (iter > s.nSegments ? nothing : (getInvariantLocation(s.resInfo,iter), iter+1)) : + (iter > length(s.resInfo.locationID) ? nothing : (getSegmentLocation( s.resInfo,iter), iter+1)) +Base.length(s::SegmentAndIndex) = s.resInfo.invariant ? s.nSegments : length(s.resInfo.locationID) + + +struct Segment + resInfo::ResultInfo + nSegments::Int # Number of segments +end + +Base.iterate(s::Segment, iter=1) = s.resInfo.invariant ? (iter > s.nSegments ? nothing : (iter, iter+1)) : + (iter > length(s.resInfo.locationID) ? nothing : (s.resInfo.locationID[iter].segment, iter+1)) +Base.length(s::Segment) = s.resInfo.invariant ? s.nSegments : length(s.resInfo.locationID) + + +function rawSignal(result::Result, name::AbstractString; unitless=true)::Tuple{AbstractVector, AbstractVector, ModiaResult.SignalType} + nSegments = length(result.t) + resInfo = result.info[name] + negate = false + + if resInfo.kind == RESULT_ELIMINATED + resInfo = result.info[resInfo.aliasName] + negate = result.info[resInfo.aliasNegate] + end + + tSig = [ result.t[sk] for sk in Segment(resInfo,nSegments) ] + + if resInfo.kind == RESULT_T + sig = result.t + elseif resInfo.kind == RESULT_X + sig = [ [ibeg==iend ? x_ti[ibeg] : x_ti[ibeg:iend] for x_ti in result.x[sk]] for (sk,ibeg,iend) in SegmentAndIndex(resInfo,nSegments) ] + elseif resInfo.kind == RESULT_DER_X + sig = [ [ibeg==iend ? der_x_ti[ibeg] : der_x_ti[ibeg:iend] for der_x_ti in result.der_x[sk]] for (sk,ibeg,iend) in SegmentAndIndex(resInfo,nSegments) ] + elseif resInfo.kind == RESULT_W_INVARIANT + sig = [ [w_ti[index] for w_ti in result.w_invariant[sk]] for (sk,index,dummy) in SegmentAndIndex(resInfo,nSegments) ] + elseif resInfo.kind == RESULT_W_SEGMENT + sig = [ [w_ti[index] for w_ti in result.w_segment[sk]] for (sk,index,dummy) in SegmentAndIndex(resInfo,nSegments) ] + elseif resInfo.kind == RESULT_CONSTANT + sig = [ ModiaResult.OneValueVector(resInfo.value, length(result.t[sk])) for sk = 1:length(result.t) ] + else + error("Bug in Modia.rawSignal: name=\"$name\" has ResultInfo=$resInfo, but ResultInof.kind = $(resInfo.kind) is not known.") + end + + if negate + sig *= -1 + end + if resInfo.kind == RESULT_W_INVARIANT + # Result has already unit, if compiled with unitless=false + if unitless && !m.unitless + sig = stripUnit(sig) + end + elseif !unitless && resInfo.unit != "" + sig *= uparse(resInfo.unit) + end + return (tSig, sig, resInfo.signalKind) +end + + diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index adf3226..a8d3ef4 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -222,6 +222,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me m.options = options m.time = options.startTime m.isInitial = true + m.nsegment = 1 reinitEventHandler!(m.eventHandler, m.options.stopTime, m.options.logEvents) if ismissing(algorithm) && FloatType == Float64 @@ -265,7 +266,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me # Terminate simulation of current segment finalStates = solution.u[end] finalTime = solution.t[end] - m.result_x = solution + #m.result_x = solution if m.eventHandler.restart != Modia.FullRestart eh.terminalOfAllSegments = true end @@ -282,59 +283,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end # Re-initialize model for FullRestart - m.options.startTime = m.time - reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) - - # Evaluate instantiate functions - removeHiddenStatesAndExtraResults!(m) - removeHiddenCrossingFunctions!(m.eventHandler) - for fc in m.instantiatedFunctions - logInstantiatedFunctionCalls = false - Core.eval(m.modelModule, :($(fc[1])($m, $(fc[2]), $(fc[3]), log=$logInstantiatedFunctionCalls))) - end - m.x_start = initialStateVector!(m.equationInfo, FloatType) - resizeStatesAndResults!(m) - - # Initialize auxiliary arrays for event iteration - m.x_init .= FloatType(0) - m.der_x_visible .= FloatType(0) - m.x_hidden .= FloatType(0) - m.der_x_hidden .= FloatType(0) - m.der_x_full .= FloatType(0) - - if m.options.logStates - # List init/start values - x_table = DataFrames.DataFrame(state=String[], init=Any[], unit=String[]) #, nominal=String[]) - for xe_info in m.equationInfo.x_info - xe_init = get_xe(m.x_start, xe_info) - if hasParticles(xe_init) - xe_init = string(minimum(xe_init)) * " .. " * string(maximum(xe_init)) - end - # xe_nominal = isnan(xe_info.nominal) ? "" : xe_info.nominal - push!(x_table, (xe_info.x_name, xe_init, xe_info.unit)) #, xe_nominal)) - end - show(stdout, x_table; allrows=true, allcols=true, rowlabel = Symbol("#"), summary=false, eltypes=false) - println("\n") - end - - # Initialize model, linearEquations and compute and store all variables at the initial time - if m.options.log - println(" Reinitialization due to FullRestart at time = ", m.time, " s") - end - # Perform event iteration - m.isInitial = true - eh.initial = true - for i in eachindex(m.x_init) - m.x_init[i] = deepcopy(m.x_start[i]) - end - eventIteration!(m, m.x_init, m.options.startTime) - m.success = false # is set to true at the first outputs! call. - eh.fullRestart = false - eh.initial = false - m.isInitial = false - m.storeResult = false - eh.afterSimulationStart = true end # --------------------------------------------------------- End of core simulation loop ------------------------------ disable_timer!(m.timer) @@ -357,7 +306,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me println(" linearSystemSizes = ", Int[length(leq.b) for leq in m.linearEquations]) println(" useRecursiveFactorization = ", useRecursiveFactorization) println(" odeModeLinearSystems = ", Bool[leq.odeMode for leq in m.linearEquations]) - println(" nResults = ", length(m.result_x.t)) + println(" nResults = ", length(m.result.t[end])) println(" nGetDerivatives = ", m.nGetDerivatives, " (total number of getDerivatives! calls)") println(" nf = ", m.nf, " (number of getDerivatives! calls from integrator)") # solution.destats.nf println(" nZeroCrossings = ", eh.nZeroCrossings, " (number of getDerivatives! calls for zero crossing detection)") @@ -474,8 +423,8 @@ function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=miss m.odeIntegrator = false nx = length(m.x_init) differential_vars = eh.nz > 0 ? fill(true, nx) : nothing # due to DifferentialEquations issue #549 - copyDerivatives!(m.der_x_full, m.der_x_visible, m.der_x_hidden) - TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x_full, m.x_init, tspan, m, differential_vars = differential_vars) + copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segment) + TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x, m.x_init, tspan, m, differential_vars = differential_vars) empty!(m.daeCopyInfo) if length(sizesOfLinearEquationSystems) > 0 && maximum(sizesOfLinearEquationSystems) >= options.nlinearMinForDAE # Prepare data structure to efficiently perform copy operations for DAE integrator @@ -555,7 +504,8 @@ function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=miss sol_t = solution.t sol_x = solution.u m.storeResult = true - for i = length(m.result_code)+1:length(sol_t) +# for i = length(m.result_code)+1:length(sol_t) + for i = length(m.result.t[end])+1:length(sol_t) invokelatest_getDerivatives_without_der_x!(sol_x[i], m, sol_t[i]) end m.storeResult = false @@ -669,22 +619,21 @@ end # Provide the overloaded ModiaResult Abstract Interface for the results of SimulationModel #------------------------------------------------------------------------------------------------ -ModiaResult.timeSignalName( m::SimulationModel) = "time" -ModiaResult.hasOneTimeSignal(m::SimulationModel) = true +ModiaResult.timeSignalName( m::SimulationModel) = m.result.timeName +ModiaResult.hasOneTimeSignal(m::SimulationModel) = length(m.result.t) == 1 """ - hasSignal(instantiatedModel, name::AbstractString) + hasSignal(instantiatedModel::Modia.SimulationModel, name::AbstractString) Return true if time-varying variable `name` (for example `name = "a.b.c"`) is defined in the instantiateModel that can be accessed and can be used for plotting. """ ModiaResult.hasSignal(m::SimulationModel, name::AbstractString) = begin - # m.save_x_in_solution ? name == "time" || haskey(m.equationInfo.x_dict, name) : - if isnothing(m) || ismissing(m) || ismissing(m.result_x) || ismissing(m.result_code) || ismissing(m.result_extra) || ismissing(m.result_der_x) + if isnothing(m) || ismissing(m) || ismissing(m.result) return false end - haskey(m.result_info, name) || !ismissing(get_value(m.evaluatedParameters, name)) + haskey(m.result.info, name) || !ismissing(get_value(m.evaluatedParameters, name)) end @@ -695,7 +644,7 @@ Return true if parameter `name` (for example `name = "a.b.c"`) is defined in the instantiateModel. """ hasParameter(m::SimulationModel, name::AbstractString) = begin - if isnothing(m) || ismissing(m) || ismissing(m.result_x) || ismissing(m.result_code) || ismissing(m.result_extra) || ismissing(m.result_der_x) + if isnothing(m) || ismissing(m) || ismissing(m.result) return false end !ismissing(get_value(m.evaluatedParameters, name)) @@ -750,7 +699,7 @@ end Return the names of the time-varying variables of an [`@instantiateModel`](@ref) that are present in the result (e.g. can be accessed for plotting). """ -ModiaResult.signalNames(m::SimulationModel) = collect(keys(m.result_info)) +ModiaResult.signalNames(m::SimulationModel) = collect(keys(m.result.info)) #= @@ -774,6 +723,17 @@ end Get raw signal of result from an instantiated model of Modia. """ function ModiaResult.rawSignal(m::SimulationModel, name::AbstractString) + if haskey(m.result.info, name) + return rawSignal(m.result, name, unitless=m.unitless) + else + value = get_value(m.evaluatedParameters, name) + if ismissing(value) + error("rawSignal: \"$name\" not in result and not a parameter of model $(m.modelName))") + end + signal = [ ModiaResult.OneValueVector(value, length(tk)) for tk in m.result.t ] + return (m.result.t, signal, ModiaResult.Continuous) + end +#= tsig = m.result_x.t if !m.unitless tsig = tsig*u"s" @@ -851,15 +811,8 @@ function ModiaResult.rawSignal(m::SimulationModel, name::AbstractString) else error("Bug in SimulateAndPlot.jl (rawSignal(..)): name=\"$name\", resInfo=$resInfo") end - - else - value = get_value(m.evaluatedParameters, name) - if ismissing(value) - error("rawSignal: \"$name\" not in result of model $(m.modelName))") - end - signal = ModiaResult.OneValueVector(value, length(tsig)) - return ([tsig], [signal], ModiaResult.Continuous) end +=# end @@ -995,6 +948,11 @@ function get_result(m::SimulationModel, name::AbstractString; unit=true) #resIndex = m.variables[name] #ysig = ResultView(m.result, abs(resIndex), resIndex < 0) + #if ModiaResult.timeSignalName(m) != 1 + if length(m.result.t) > 1 + error("Error in Modia.get_result(\"$name\"), because function cannot be used for a segmented simulation with more as one segment.") + end + (tsig2, ysig2, ysigType) = ModiaResult.rawSignal(m, name) ysig = ysig2[1] ysig = unit ? ysig : stripUnit.(ysig) @@ -1025,7 +983,12 @@ function setEvaluatedParametersInDataFrame!(obj::OrderedDict{Symbol,Any}, result return nothing end + function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) + if length(m.result.t) > 1 + error("Error in Modia.get_result(...), because function cannot be used for a segmented simulation with more as one segment.") + end + dataFrame = DataFrames.DataFrame() (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, "time") @@ -1046,14 +1009,14 @@ function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) end else - for name in keys(m.result_info) + for name in keys(m.result.info) if name != "time" (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) dataFrame[!,name] = signal[1] end end - setEvaluatedParametersInDataFrame!(m.evaluatedParameters, m.result_info, dataFrame, "", length(timeSignal[1])) + setEvaluatedParametersInDataFrame!(m.evaluatedParameters, m.result.info, dataFrame, "", length(timeSignal[1])) end return dataFrame end \ No newline at end of file diff --git a/src/StateSelection.jl b/src/StateSelection.jl index 9890079..7454c5e 100644 --- a/src/StateSelection.jl +++ b/src/StateSelection.jl @@ -1500,7 +1500,7 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} push!(x_vec_fixed , v_fixed) end end - nx_infoFixed = length(x_info) + nx_info_fixedLength = length(x_info) for (i,v) in enumerate(x_vec) v_startOrInit = x_vec_startOrInit[i] v_fixed = x_vec_fixed[i] @@ -1522,7 +1522,7 @@ function getSortedAndSolvedAST(Goriginal, # Typically ::Vector{Vector{Int}} end # Finalize equationInfo - initEquationInfo!(eq.equationInfo, nx_infoFixed) + initEquationInfo!(eq.equationInfo, nx_info_fixedLength) # Print ODE states if logStates diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 77ba824..d662e17 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -61,8 +61,8 @@ LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace mutable struct LinearStateSpaceStruct{FloatType} path::String # Path name of instance - x_hidden_startIndex::Int - w_extraResult_index::Int + x_startIndex::Int + w_index::Int A::Matrix{FloatType} B::Matrix{FloatType} C::Matrix{FloatType} @@ -160,11 +160,11 @@ function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationMode end lsBuild::LinearStateSpaceBuild{FloatType} = partiallyInstantiatedModel.buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) - ls.x_hidden_startIndex = Modia.newHiddenState!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) + ls.x_startIndex = Modia.new_x_segment_variable!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) if length(ls.W) > 0 # w = W*x_init ls.w = ls.W*ls.x_init - ls.w_extraResult_index = Modia.newExtraResult!(partiallyInstantiatedModel, path*".w", ls.w) + ls.w_index = Modia.new_w_segment_variable!(partiallyInstantiatedModel, path*".w", ls.w) end lsBuild.ls = ls return nothing @@ -173,11 +173,11 @@ end function openLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls - Modia.addHiddenState!(instantiatedModel, ls.x_hidden_startIndex, ls.x) + Modia.get_Vector_x_segment_value!(instantiatedModel, ls.x_startIndex, ls.x) if Modia.storeResults(instantiatedModel) && length(ls.W) > 0 # w = W*x mul!(ls.w, ls.W, ls.x) - Modia.addExtraResult!(instantiatedModel, ls.w_extraResult_index, ls.w) + Modia.add_w_segment_value!(instantiatedModel, ls.w_index, ls.w) end return ls end @@ -191,7 +191,7 @@ function computeStateDerivatives!(instantiatedModel, ls, u)::Bool # der_x = A*x + B*u mul!(ls.der_x, ls.A, ls.x) mul!(ls.der_x, ls.B, u, 1.0, 1.0) - Modia.copyToHiddenStateDerivative!(instantiatedModel, ls.x_hidden_startIndex, ls.der_x) + Modia.add_der_x_segment_value!(instantiatedModel, ls.x_startIndex, ls.der_x) return true end From 88da6588593755567dd0d052b94c9d05387afd88 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 22 Jun 2022 23:20:23 +0200 Subject: [PATCH 33/63] segment -> segmented; move result functions in a separate file ModiaResultInterface.jl --- src/CodeGeneration.jl | 266 +++++++++--------- src/EquationAndStateInfo.jl | 44 +-- src/EventHandler.jl | 6 +- src/Modia.jl | 11 +- src/ModiaResultInterface.jl | 297 ++++++++++++++++++++ src/Result.jl | 392 ++++++++++++++++----------- src/SimulateAndPlot.jl | 341 +---------------------- test/TestFilterCircuit.jl | 2 +- test/TestLinearSystems.jl | 8 +- test/TestMultiReturningFunction10.jl | 2 +- test/TestPathPlanning.jl | 4 +- test/TestSignals.jl | 188 +++++++++++++ 12 files changed, 897 insertions(+), 664 deletions(-) create mode 100644 src/ModiaResultInterface.jl create mode 100644 test/TestSignals.jl diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index b5768b9..a5c2ef2 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -328,7 +328,7 @@ mutable struct SimulationModel{FloatType,TimeType} # All definitions `_instantiateFunction = Par(functionName = XXX)` in the model to call # `XXX(instantiatedModel, submodel, submodelPath)` in the order occurring during evaluation # of the parameters where, instantiatedFunctions[i] = (XXX, submodel, submodelPath) - nsegment::Int # Current simulation segment + nsegmented::Int # Current simulation segment evaluatedParameters::OrderedDict{Symbol,Any} # Evaluated parameters nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) nextPre::AbstractVector @@ -338,12 +338,12 @@ mutable struct SimulationModel{FloatType,TimeType} # equationInfo.x_info[equationInfo.nx_info_fixedLength+i:equationInfo.nx_info_invariant] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) - x_segment::Vector{FloatType} # A copy of the current segment states + x_segmented::Vector{FloatType} # A copy of the current segment states der_x_invariant::Vector{FloatType} # Derivatives of states x or x_init that correspond to invariant states # This vector is filled with derivatives of invariants states with appendVariable!(m.der_x_invariant, ...) calls, # including derivatives of x_vec[i] - der_x_segment::Vector{FloatType} # Derivatives of states x or x_init that correspond to segment states (defined in functions and not visible in getDerivatives!(..)) + der_x_segmented::Vector{FloatType} # Derivatives of states x or x_init that correspond to segmented states (defined in functions and not visible in getDerivatives!(..)) der_x::Vector{FloatType} # Derivatives of states x function SimulationModel{FloatType,TimeType}(modelModule, modelName, buildDict, getDerivatives!, equationInfo, @@ -431,18 +431,18 @@ mutable struct SimulationModel{FloatType,TimeType} success = false nx = m.equationInfo.nx nxInvariant = m.equationInfo.nxInvariant - nxSegment = nx-nxInvariant + nxSegmented = nx-nxInvariant emptyResult!(m.result) result = deepcopy(m.result) - nsegment = 1 + nsegmented = 1 x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] x_start = convert(Vector{FloatType}, m.x_start) x_init = zeros(FloatType, nx) - x_segment = zeros(FloatType, nxSegment) + x_segmented = zeros(FloatType, nxSegmented) der_x_invariant = zeros(FloatType, nxInvariant) - der_x_segment = zeros(FloatType, nxSegment) + der_x_segmented = zeros(FloatType, nxSegmented) der_x = zeros(FloatType, nx) new(m.modelModule, m.modelName, deepcopy(m.buildDict), TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), deepcopy(m.options), m.getDerivatives!, @@ -455,10 +455,10 @@ mutable struct SimulationModel{FloatType,TimeType} isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, true, LinearEquationsCopyInfoForDAEMode[], odeIntegrator, daeCopyInfo, m.sundials, m.addEventPointsDueToDEBug, success, m.unitless, - result, nsegment, + result, nsegmented, deepcopy(m.parameters), deepcopy(m.instantiateFunctions), deepcopy(m.evaluatedParameters), deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), - x_vec, x_start, x_init, x_segment, der_x_invariant, der_x_segment, der_x) + x_vec, x_start, x_init, x_segmented, der_x_invariant, der_x_segmented, der_x) end =# end @@ -669,20 +669,20 @@ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit elseif resInfo.kind == RESULT_X locationID = resInfo.locationID[end] - segment = locationID.segment + segmented = locationID.segmented ibeg = locationID.index iend = ibeg + prod(locationID.size) - 1 - value = ibeg == iend ? result.x[segment][end][ibeg] : result.x[segment][end][ibeg:iend] + value = ibeg == iend ? result.x[segmented][end][ibeg] : result.x[segmented][end][ibeg:iend] if unit && resInfo.unit != "" value *= uparse(resInfo.unit) end elseif resInfo.kind == RESULT_DER_X locationID = resInfo.locationID[end] - segment = locationID.segment + segmented = locationID.segmented ibeg = locationID.index iend = ibeg + prod(locationID.size) - 1 - value = ibeg == iend ? result.der_x[segment][end][ibeg] : result.der_x[segment][end][ibeg:iend] + value = ibeg == iend ? result.der_x[segmented][end][ibeg] : result.der_x[segmented][end][ibeg:iend] if unit && resInfo.unit != "" value *= uparse(resInfo.unit) end @@ -693,14 +693,14 @@ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit @show resInfo @show locationID @show result.w_invariant - value = result.w_invariant[locationID.segment][end][locationID.index] + value = result.w_invariant[locationID.segmented][end][locationID.index] if !unit value = stripUnit(value) end - elseif resInfo.kind == RESULT_W_SEGMENT + elseif resInfo.kind == RESULT_W_SEGMENTED locationID = resInfo.locationID[end] - value = result.w_segment[locationID.segment][end][locationID.index] + value = result.w_segmented[locationID.segmented][end][locationID.index] if unit && resInfo.unit != "" && eltype(value) <: AbstractFloat value *= uparse(resInfo.unit) end @@ -859,12 +859,12 @@ initial( m::SimulationModel) = m.eventHandler.initial """ - isFirstInitialOfAllSegments(instantiatedModel) + isFirstInitialOfAllSegmenteds(instantiatedModel) -Return true, if **initialization phase** of simulation of the **first segment** -of a segmented simulation. +Return true, if **initialization phase** of simulation of the **first segmented** +of a segmenteded simulation. """ -isFirstInitialOfAllSegments(m::SimulationModel) = m.eventHandler.firstInitialOfAllSegments +isFirstInitialOfAllSegmenteds(m::SimulationModel) = m.eventHandler.firstInitialOfAllSegments """ @@ -877,12 +877,12 @@ terminal( m::SimulationModel) = m.eventHandler.terminal """ - isTerminalOfAllSegments(instantiatedModel) + isTerminalOfAllSegmenteds(instantiatedModel) -Return true, if **terminal phase** of simulation of the **last segment** -of a segmented simulation. +Return true, if **terminal phase** of simulation of the **last segmented** +of a segmenteded simulation. """ -isTerminalOfAllSegments(m::SimulationModel) = m.eventHandler.terminalOfAllSegments +isTerminalOfAllSegmenteds(m::SimulationModel) = m.eventHandler.terminalOfAllSegments """ @@ -914,7 +914,7 @@ isFirstEventIterationDirectlyAfterInitial(m::SimulationModel) = m.eventHandler.f """ isFullRestart(instantiatedModel) -Return true, if **FullRestart event** of a segmented simulation. +Return true, if **FullRestart event** of a segmenteded simulation. """ isFullRestart(m::SimulationModel) = m.eventHandler.fullRestart @@ -992,12 +992,12 @@ function invokelatest_getDerivatives_without_der_x!(x, m, t)::Nothing j += 1 end end - copyto!(m.x_segment, 1, x, m.equationInfo.nxInvariant+1, m.equationInfo.nxSegment) + copyto!(m.x_segmented, 1, x, m.equationInfo.nxInvariant+1, m.equationInfo.nxSegmented) empty!(m.der_x_invariant) - m.der_x_segment .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 + m.der_x_segmented .= 0 # Handles also the case for a dummy differential equation (if model has no states): der(_dummy_x) = 0.0 Base.invokelatest(m.getDerivatives!, x, m, t) - @assert(length(m.der_x_invariant) + length(m.der_x_segment) == length(x)) + @assert(length(m.der_x_invariant) + length(m.der_x_segmented) == length(x)) end return nothing end @@ -1030,7 +1030,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti result = m.result eh = m.eventHandler m.instantiateFunctions = Tuple{Any,String}[] - m.nsegment = 1 + m.nsegmented = 1 newResultSegment!(result) if length(m.options.merge) > 0 m.parameters = mergeModels(m.parameters, m.options.merge) @@ -1045,11 +1045,11 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti m.nextHold = deepcopy(m.hold) m.x_start = initialStateVector!(m) nx = length(m.x_start) - nxSegment = nx-equationInfo.nxInvariant + nxSegmented = nx-equationInfo.nxInvariant # Update locationIDs of all states and state derivatives (indices are known, after initialStateVector!(..) was called for xe_info in equationInfo.x_info - locationID = LocationID(1, xe_info.startIndex, size(xe_info.startOrInit)) + locationID = ValuesID(1, xe_info.startIndex, size(xe_info.startOrInit)) push!(result.info[xe_info.x_name ].locationID, locationID) push!(result.info[xe_info.der_x_name].locationID, locationID) end @@ -1057,9 +1057,9 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Provide storage for x and der_x utility vectors m.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] m.x_init = zeros(FloatType,nx) - m.x_segment = zeros(FloatType, nxSegment) + m.x_segmented = zeros(FloatType, nxSegmented) m.der_x_invariant = zeros(FloatType,equationInfo.nxInvariant) - m.der_x_segment = zeros(FloatType, nxSegment) + m.der_x_segmented = zeros(FloatType, nxSegmented) m.der_x = zeros(FloatType,nx) # Log parameters @@ -1122,12 +1122,12 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where end eh = m.eventHandler result = m.result - removeSegmentStates!(m.equationInfo) - empty!(result.alias_segment_names) - empty!(result.w_segment_names) - empty!(result.w_segment_temp) + removeSegmentedStates!(m.equationInfo) + empty!(result.alias_segmented_names) + empty!(result.w_segmented_names) + empty!(result.w_segmented_temp) newResultSegment!(m.result) - m.nsegment += 1 + m.nsegmented += 1 m.options.startTime = m.time reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) @@ -1142,30 +1142,30 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where # Resize states and results nx = length(m.x_start) - nxSegment = nx - m.equationInfo.nxInvariant + nxSegmented = nx - m.equationInfo.nxInvariant resize!(m.x_init , nx) - resize!(m.x_segment , nxSegment) + resize!(m.x_segmented , nxSegmented) resize!(m.der_x_invariant, m.equationInfo.nxInvariant) - resize!(m.der_x_segment , nxSegment) + resize!(m.der_x_segmented , nxSegmented) resize!(m.der_x , nx) m.x_init .= FloatType(0) - m.x_segment .= FloatType(0) + m.x_segmented .= FloatType(0) m.der_x_invariant .= FloatType(0) - m.der_x_segment .= FloatType(0) + m.der_x_segmented .= FloatType(0) m.der_x .= FloatType(0) - # Update locationIDs for x_segment and der_x_segment + # Update locationIDs for x_segmented and der_x_segmented eqInfo = m.equationInfo x_info = eqInfo.x_info resultInfo = m.result.info - nsegment = m.nsegment + nsegmented = m.nsegmented @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) for i = eqInfo.nx_info_invariant+1:length(x_info) xi_info = x_info[i] resInfo = resultInfo[xi_info.x_name] - push!(resInfo.locationID, LocationID(nsegment, resInfo.startIndex, size(resInfo.startOrInit))) + push!(resInfo.locationID, ValuesID(nsegmented, resInfo.startIndex, size(resInfo.startOrInit))) resInfo = resultInfo[xi_info.der_x_name] - push!(resInfo.locationID, LocationID(nsegment, resInfo.startIndex, size(resInfo.startOrInit))) + push!(resInfo.locationID, ValuesID(nsegmented, resInfo.startIndex, size(resInfo.startOrInit))) end eqInfo.status = EquationInfo_After_All_States_Are_Known @@ -1329,17 +1329,17 @@ end """ - copyDerivatives!(der_x, der_x_invariant, der_x_segment) + copyDerivatives!(der_x, der_x_invariant, der_x_segmented) -Copy der_x_invariant and der_x_segment to der_x (der_x .= [der_x_invariant, der_x_segment]) +Copy der_x_invariant and der_x_segmented to der_x (der_x .= [der_x_invariant, der_x_segmented]) """ -@inline function copyDerivatives!(der_x, der_x_invariant, der_x_segment)::Nothing - if length(der_x_segment) == 0 +@inline function copyDerivatives!(der_x, der_x_invariant, der_x_segmented)::Nothing + if length(der_x_segmented) == 0 der_x .= der_x_invariant else - @assert(length(der_x) == length(der_x_invariant) + length(der_x_segment)) + @assert(length(der_x) == length(der_x_invariant) + length(der_x_segmented)) unsafe_copyto!(der_x, 1, der_x_invariant, 1, length(der_x_invariant)) - unsafe_copyto!(der_x, length(der_x_invariant)+1, der_x_segment, 1, length(der_x_segment)) + unsafe_copyto!(der_x, length(der_x_invariant)+1, der_x_segmented, 1, length(der_x_segmented)) end return nothing end @@ -1353,8 +1353,8 @@ DifferentialEquations callback function to get the derivatives. function derivatives!(der_x, x, m, t) m.nf += 1 invokelatest_getDerivatives_without_der_x!(x, m, t) - #println("t = $t, m.der_x_segment = ", m.der_x_segment) - copyDerivatives!(der_x, m.der_x_invariant, m.der_x_segment) + #println("t = $t, m.der_x_segmented = ", m.der_x_segmented) + copyDerivatives!(der_x, m.der_x_invariant, m.der_x_segmented) return nothing end @@ -1380,7 +1380,7 @@ function DAEresidualsForODE!(residuals, derx, x, m, t)::Nothing invokelatest_getDerivatives_without_der_x!(x, m, t) m.solve_leq = true - copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segment) + copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segmented) residuals .= m.der_x .- derx # Get residuals from linearEquations @@ -1603,39 +1603,39 @@ end """ addToResult!(instantiatedModel, x, time, w_invariant...) -Add result of current time instant (`time, x, der_x, w_invariant, w_segment`) to `instantiatedModel`. +Add result of current time instant (`time, x, der_x, w_invariant, w_segmented`) to `instantiatedModel`. """ function addToResult!(m::SimulationModel, x, time, w_invariant...)::Nothing @assert(length(w_invariant) == m.result.n_w_invariant) - copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segment) + copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segmented) result = m.result push!(result.t[ end], time) push!(result.x[ end], deepcopy(x)) push!(result.der_x[ end], deepcopy(m.der_x)) push!(result.w_invariant[end], deepcopy(w_invariant)) - push!(result.w_segment[ end], deepcopy(m.result.w_segment_temp)) + push!(result.w_segmented[ end], deepcopy(m.result.w_segmented_temp)) return nothing end """ - startIndex = new_x_segment_variable!(instantiatedModel::SimulationModel, + startIndex = new_x_segmented_variable!(instantiatedModel::SimulationModel, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; nominal::Float64 = NaN, unbounded::Bool = false)::Int -Reserve storage location for a new x_segment and der_x_segment variable. The returned startIndex is used +Reserve storage location for a new x_segmented and der_x_segmented variable. The returned startIndex is used -- to copy state values from instantiatedModel.x_segment[startIndex:startIndex+prod(dims(startOrInit))-1] into the internal states -- to copy internal state derivative values to instantiatedModel.der_x_segment[startIndex:startIndex+prod(dims(startOrInit))-1] +- to copy state values from instantiatedModel.x_segmented[startIndex:startIndex+prod(dims(startOrInit))-1] into the internal states +- to copy internal state derivative values to instantiatedModel.der_x_segmented[startIndex:startIndex+prod(dims(startOrInit))-1] -Value startOrInit is the start/init value used during re-initialization of the new segment with initFullRestart!(..). +Value startOrInit is the start/init value used during re-initialization of the new segmented with initFullRestart!(..). """ -function new_x_segment_variable!(eqInfo::EquationInfo, result::Result, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; +function new_x_segmented_variable!(eqInfo::EquationInfo, result::Result, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; nominal::Float64 = NaN, unbounded::Bool = false)::Int @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) new_result_info = true if haskey(result.info, x_name) - # State was already defined in one of the previous segments + # State was already defined in one of the previous segmenteds new_result_info = false x_info = result.info[x_name] @assert(x_info.kind == RESULT_X) @@ -1657,15 +1657,15 @@ function new_x_segment_variable!(eqInfo::EquationInfo, result::Result, x_name::S @assert(eqInfo.der_x_dict, der_x_name) end - x_segment_startIndex = eqInfo.nxSegment+1 + x_segmented_startIndex = eqInfo.nxSegmented+1 xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), XD, x_unit, startOrInit, true, nominal, unbounded, - x_segment_startIndex = x_segment_startIndex) + x_segmented_startIndex = x_segmented_startIndex) push!(eqInfo.x_info, xi_info) x_infoIndex = length(eqInfo.x_info) eqInfo.x_dict[x_name] = x_infoIndex eqInfo.der_x_dict[der_x_name] = x_infoIndex - eqInfo.nxSegment += length(startOrInit) + eqInfo.nxSegmented += length(startOrInit) if new_result_info # result.info can be only partially instantiated, because x_startIndex is only known @@ -1675,77 +1675,77 @@ function new_x_segment_variable!(eqInfo::EquationInfo, result::Result, x_name::S result.info[x_name] = ResultInfo(RESULT_X , startOrInit, x_unit , false) result.info[der_x_name] = ResultInfo(RESULT_DER_X, startOrInit, der_x_unit, false) end - return x_segment_startIndex + return x_segmented_startIndex end -new_x_segment_variable!(m::SimulationModel, args...; kwargs...) = new_x_segment_variable!(m.equationInfo, m.result, args...; kwargs...) +new_x_segmented_variable!(m::SimulationModel, args...; kwargs...) = new_x_segmented_variable!(m.equationInfo, m.result, args...; kwargs...) """ - index = new_w_segment_variable!(partiallyInstantiatedModel::SimulationModel, name::String, - w_segment_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int + index = new_w_segmented_variable!(partiallyInstantiatedModel::SimulationModel, name::String, + w_segmented_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int -Reserve storage location for a new w_segment variable. The returned `index` is -used to store the w_segment value at communication points in the result data structure. -Value w_segment_default is stored as default value and defines type and (fixed) size of the variable -in this segment. +Reserve storage location for a new w_segmented variable. The returned `index` is +used to store the w_segmented value at communication points in the result data structure. +Value w_segmented_default is stored as default value and defines type and (fixed) size of the variable +in this segmented. """ -function new_w_segment_variable!(m::SimulationModel, name::String, w_segment_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int +function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int result = m.result - w_size = size(w_segment_default) + w_size = size(w_segmented_default) if haskey(result.info, name) - # Variable was already defined in one of the previous segments + # Variable was already defined in one of the previous segmenteds v_info = result.info[name] - @assert(!haskey(result.w_segment_names, name)) - @assert(v_info.kind == RESULT_W_SEGMENT) - @assert(v_info.type == typeof(w_segment_default)) + @assert(!haskey(result.w_segmented_names, name)) + @assert(v_info.kind == RESULT_W_SEGMENTED) + @assert(v_info.type == typeof(w_segmented_default)) @assert(v_info.unit == unit) - @assert(v_info.ndims == ndims(w_segment_default)) + @assert(v_info.ndims == ndims(w_segmented_default)) @assert(v_info.signalKind == signalKind) @assert(!v_info.invariant) - push!(result.w_segment_names, name) - push!(result.w_segment_temp, deepcopy(w_segment_default)) - w_segment_index = length(result_w_segment_temp) - push!(v_info.locationID, LocationID(m.nsegment, w_segment_index, size(w_segment_default))) + push!(result.w_segmented_names, name) + push!(result.w_segmented_temp, deepcopy(w_segmented_default)) + w_segmented_index = length(result_w_segmented_temp) + push!(v_info.locationID, ValuesID(m.nsegmented, w_segmented_index, size(w_segmented_default))) else - # Variable is defined the first time in the segmented simulation - push!(result.w_segment_names, name) - push!(result.w_segment_temp, deepcopy(w_segment_default)) - w_segment_index = length(result.w_segment_temp) - result.info[name] = ResultInfo(RESULT_W_SEGMENT, w_segment_default, unit, signalKind, m.nsegment, w_segment_index) + # Variable is defined the first time in the segmenteded simulation + push!(result.w_segmented_names, name) + push!(result.w_segmented_temp, deepcopy(w_segmented_default)) + w_segmented_index = length(result.w_segmented_temp) + result.info[name] = ResultInfo(RESULT_W_SEGMENTED, w_segmented_default, unit, signalKind, m.nsegmented, w_segmented_index) end - println("new_w_segment_variable: w_segment_temp = ", result.w_segment_temp) - return w_segment_index + println("new_w_segmented_variable: w_segmented_temp = ", result.w_segmented_temp) + return w_segmented_index end """ - new_alias_segment_variable!(partiallyInstantiatedModel, name, aliasName, aliasNegate=false) + new_alias_segmented_variable!(partiallyInstantiatedModel, name, aliasName, aliasNegate=false) -Define new alias segment variable. +Define new alias segmented variable. """ -function new_alias_segment_variable!(m::SimulationModel, name::String, aliasName::String, aliasNegate::Bool=false)::Int +function new_alias_segmented_variable!(m::SimulationModel, name::String, aliasName::String, aliasNegate::Bool=false)::Int result = m.result - w_size = size(w_segment_default) + w_size = size(w_segmented_default) if haskey(result.info, name) - error("new_alias_segment_variable!(...): $name is already defined") + error("new_alias_segmented_variable!(...): $name is already defined") elseif !haskey(result.info, aliasName) - error("new_alias_segment_variable!(...): $name should be made an alias to $aliasName, but this name is not defined") + error("new_alias_segmented_variable!(...): $name should be made an alias to $aliasName, but this name is not defined") end result.info[name] = ResultInfo(RESULT_ELIMINATED, aliasName, aliasNegate) - push!(result.alias_segment_names, name) + push!(result.alias_segmented_names, name) return nothing end """ - startIndex = new_z_segment_variable!(instantiatedModel, nz) + startIndex = new_z_segmented_variable!(instantiatedModel, nz) -Reserve storage location for nz new segment zero crossing function and return the startIndex to +Reserve storage location for nz new segmented zero crossing function and return the startIndex to copy it in the vectors of zero crossings """ -function new_z_segment_variable!(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} +function new_z_segmented_variable!(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} eh = m.eventHandler zStartIndex = eh.nz + 1 eh.nz += nz @@ -1760,62 +1760,62 @@ end """ - value = Modia.get_scalar_x_segment_value(instantiatedModel, startIndex) + value = Modia.get_scalar_x_segmented_value(instantiatedModel, startIndex) -Return scalar segment state value from instantiatedModel given `startIndex` -(returned from `new_x_segment_variable!(..)`). +Return scalar segmented state value from instantiatedModel given `startIndex` +(returned from `new_x_segmented_variable!(..)`). """ -get_scalar_x_segment_value(m::SimulationModel, startIndex::Int) = m.x_segment[startIndex] +get_scalar_x_segmented_value(m::SimulationModel, startIndex::Int) = m.x_segmented[startIndex] """ - value = Modia.get_SVector3_x_segment_value(instantiatedModel, startIndex) + value = Modia.get_SVector3_x_segmented_value(instantiatedModel, startIndex) -Return SVector{3,FloatType}(..) segment state value from instantiatedModel given `startIndex` -(returned from `new_x_segment_variable!(..)`). +Return SVector{3,FloatType}(..) segmented state value from instantiatedModel given `startIndex` +(returned from `new_x_segmented_variable!(..)`). """ -@inline get_SVector3_x_segment_value(m::SimulationModel{FloatType,TimeType}, startIndex::Int) where {FloatType,TimeType} = begin - x_segment = m.x_segment - return SVector{3,FloatType}(x_segment[startIndex], x_segment[startIndex+1], x_segment[startIndex+2]) +@inline get_SVector3_x_segmented_value(m::SimulationModel{FloatType,TimeType}, startIndex::Int) where {FloatType,TimeType} = begin + x_segmented = m.x_segmented + return SVector{3,FloatType}(x_segmented[startIndex], x_segmented[startIndex+1], x_segmented[startIndex+2]) end """ - Modia.get_Vector_x_segment_value!(instantiatedModel::SimulationModel, startIndex, xi::Vector{FloatType})::Nothing + Modia.get_Vector_x_segmented_value!(instantiatedModel::SimulationModel, startIndex, xi::Vector{FloatType})::Nothing Copy state from `instantiatedModel` at index `startIndex` into pre-allocated vector `xi`. """ -@inline function get_Vector_x_segment_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, xi::Vector{FloatType})::Nothing where {FloatType,TimeType} - copyto!(xi, 1, m.x_segment, startIndex, length(xi)) +@inline function get_Vector_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, xi::Vector{FloatType})::Nothing where {FloatType,TimeType} + copyto!(xi, 1, m.x_segmented, startIndex, length(xi)) return nothing end """ - Modia.add_der_x_segment_value!(instantiatedModel, startIndex, der_x_segment_value::[FloatType|Vector{FloatType}]) + Modia.add_der_x_segmented_value!(instantiatedModel, startIndex, der_x_segmented_value::[FloatType|Vector{FloatType}]) -Copy scalar or array segment state derivative value `der_x_segment_value` into `instantiatedModel` starting at index `startIndex` -(returned from `new_x_segment_variable!(..)`). +Copy scalar or array segmented state derivative value `der_x_segmented_value` into `instantiatedModel` starting at index `startIndex` +(returned from `new_x_segmented_variable!(..)`). """ -@inline function add_der_x_segment_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segment::FloatType)::Nothing where {FloatType,TimeType} - m.der_x_segment[startIndex] = der_x_segment_value +@inline function add_der_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segmented::FloatType)::Nothing where {FloatType,TimeType} + m.der_x_segmented[startIndex] = der_x_segmented_value return nothing end -@inline function add_der_x_segment_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segment_value::Vector{FloatType})::Nothing where {FloatType,TimeType} - copyto!(m.der_x_segment, startIndex, der_x_segment_value, 1, length(der_x_segment_value)) +@inline function add_der_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segmented_value::Vector{FloatType})::Nothing where {FloatType,TimeType} + copyto!(m.der_x_segmented, startIndex, der_x_segmented_value, 1, length(der_x_segmented_value)) return nothing end """ - Modia.add_w_segment_value!(instantiatedModel::SimulationModel, index::Int, w_segment_value)::Nothing + Modia.add_w_segmented_value!(instantiatedModel::SimulationModel, index::Int, w_segmented_value)::Nothing -Store deepcopy(w_segment_value) at index in instantiatedModel. +Store deepcopy(w_segmented_value) at index in instantiatedModel. """ -@inline function add_w_segment_value!(m::SimulationModel, index::Int, w_segment_value)::Nothing - w_segment_temp = m.result.w_segment_temp - @assert(typeof(w_segment_value) == typeof(w_segment_temp[index])) - @assert(size( w_segment_value) == size( w_segment_temp[index])) - w_segment_temp[index] = deepcopy(w_segment_value) +@inline function add_w_segmented_value!(m::SimulationModel, index::Int, w_segmented_value)::Nothing + w_segmented_temp = m.result.w_segmented_temp + @assert(typeof(w_segmented_value) == typeof(w_segmented_temp[index])) + @assert(size( w_segmented_value) == size( w_segmented_temp[index])) + w_segmented_temp[index] = deepcopy(w_segmented_value) return nothing end @@ -1824,7 +1824,7 @@ function initialStateVector!(m::SimulationModel{FloatType,TimeType})::Vector{Flo if length(m.equationInfo.x_info) == 0 # Handle systems with only algebraic variables, by introducing a dummy # differential equation der_x[1] = -x[1], with state name _dummy_x - new_x_segment_variable!(m, "_dummy_x", "der(_dummy_x)", FloatType(0)) + new_x_segmented_variable!(m, "_dummy_x", "der(_dummy_x)", FloatType(0)) end return initialStateVector!(m.equationInfo, FloatType) end diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index c40b2a3..5ad270d 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -506,7 +506,7 @@ end """ xe_info = StateElementInfo(x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, startOrInit, fixed, nominal, unbounded; - startIndex=-1, x_segment_startIndex=-1) + startIndex=-1, x_segmented_startIndex=-1) Return an instance of the mutable struct `StateElementInfo` that defines the information for one element of the state vector. @@ -527,7 +527,7 @@ for one element of the state vector. - nominal: Nominal value (NaN if determined via startOrInit value) - unbounded: false or true - startIndex: = -1, if not yet known. startIndex with respect to x. -- x_segment_startIndex: =-1, if not yet known. startIndex with respect to x_segment. +- x_segmented_startIndex: =-1, if not yet known. startIndex with respect to x_segmented. """ mutable struct StateElementInfo x_name::String # Modia name of x-element or "" if no name @@ -551,8 +551,8 @@ mutable struct StateElementInfo # = false, if vector length::Int # length of x-element or -1 if not yet known startIndex::Int # start index of state with respect to x-vector or -1 if not yet known - x_segment_startIndex::Int # start index of segment state with respect to x_segment vector - # or -1, if it is no segment state (for a segment state, x_segment_startIndex + x_segmented_startIndex::Int # start index of segmented state with respect to x_segmented vector + # or -1, if it is no segmented state (for a segmented state, x_segmented_startIndex # is consistently set when it is added via newHiddenState(..)). end @@ -561,11 +561,11 @@ end # Constructor for code-generation StateElementInfo(x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, startOrInit, fixed, nominal, unbounded; - startIndex = -1, x_segment_startIndex=-1) = StateElementInfo( + startIndex = -1, x_segmented_startIndex=-1) = StateElementInfo( x_name, x_name_julia, der_x_name, der_x_name_julia, stateCategory, unit, deepcopy(startOrInit), fixed, nominal, unbounded, isFixedLengthStartOrInit(startOrInit, x_name), !(startOrInit isa AbstractArray), - startOrInit isa Nothing ? 1 : length(startOrInit), startIndex, x_segment_startIndex) + startOrInit isa Nothing ? 1 : length(startOrInit), startIndex, x_segmented_startIndex) function Base.show(io::IO, xe_info::StateElementInfo) print(io, "Modia.StateElementInfo(") @@ -587,7 +587,7 @@ function Base.show(io::IO, xe_info::StateElementInfo) print(io, ",", xe_info.scalar) print(io, ",", xe_info.length) print(io, ",", xe_info.startIndex) - print(io, ",", xe_info.x_segment_startIndex) + print(io, ",", xe_info.x_segmented_startIndex) print(io, ")") return nothing end @@ -647,9 +647,9 @@ mutable struct EquationInfo # This variable is updated once all states are known. nxInvariant::Int # = number of invariant x-elements (so x[1:nxInvariant] are invariant states) or -1 if not yet known # This variable is updated once all states are known. - nxSegment::Int # = number of segment x-elements (x[nxInvariant+1:nxInvariant+nxSegment]). - # This variable is always updated consistently via function new_x_segment_variable!(..) - # (nxSegment=0, if there are no segment states yet). + nxSegmented::Int # = number of segmented x-elements (x[nxInvariant+1:nxInvariant+nxSegmented]). + # This variable is always updated consistently via function new_x_segmented_variable!(..) + # (nxSegmented=0, if there are no segmented states yet). nx_info_fixedLength::Int # x_info[1:nx_info_fixedLength] are states with fixed length (does not change after compilation) or -1 if not yet known nx_info_invariant::Int # x_info[1:nx_info_invariant] are states that are visible in getDerivatives!(..) or -1 if not yet known # x_info[nx_info_invariant+1:end] are states defined in functions that are not visible in getDerivatives!(..) @@ -668,14 +668,14 @@ mutable struct EquationInfo vSolvedWithFixedTrue = String[] nx = -1 nxInvariant = -1 - nxSegment = 0 + nxSegmented = 0 nx_info_fixedLength = -1 nx_info_invariant = -1 x_dict = OrderedCollections.OrderedDict{String,Int}() der_x_dict = OrderedCollections.OrderedDict{String,Int}() defaultParameterAndStartValues = nothing new(EquationInfo_Instantiated, ode, nz, x_info, residualCategories, linearEquations, vSolvedWithFixedTrue, - nx, nxInvariant, nxSegment, nx_info_fixedLength, nx_info_invariant, x_dict, der_x_dict, + nx, nxInvariant, nxSegmented, nx_info_fixedLength, nx_info_invariant, x_dict, der_x_dict, defaultParameterAndStartValues) end end @@ -697,11 +697,11 @@ eqInfo.nx_info_fixedLength, eqInfo.nx_info_invariant, eqInfo.x_info[:].startIndex. ``` -This function must be called before segment states are set (eqInfo.nxSegment=0). +This function must be called before segmented states are set (eqInfo.nxSegmented=0). """ function initEquationInfo!(eqInfo::EquationInfo, nx_info_fixedLength::Int)::Nothing @assert(eqInfo.status == EquationInfo_Instantiated) - @assert(eqInfo.nxSegment == 0) + @assert(eqInfo.nxSegmented == 0) x_dict = eqInfo.x_dict der_x_dict = eqInfo.der_x_dict startIndex = 1 @@ -722,11 +722,11 @@ end """ - removeSegmentStates!(eqInfo::EquationInfo) + removeSegmentedStates!(eqInfo::EquationInfo) -Remove all segment states from `eqInfo`. +Remove all segmented states from `eqInfo`. """ -function removeSegmentStates!(eqInfo::EquationInfo)::Nothing +function removeSegmentedStates!(eqInfo::EquationInfo)::Nothing @assert(eqInfo.status == EquationInfo_After_All_States_Are_Known) if eqInfo.nx > eqInfo.nxInvariant for i = eqInfo.nx_info_invariant+1:length(eqInfo.x_info) @@ -737,7 +737,7 @@ function removeSegmentStates!(eqInfo::EquationInfo)::Nothing resize!(eqInfo.x_info, eqInfo.nx_info_invariant) eqInfo.nx = eqInfo.nxInvariant end - eqInfo.nxSegment = 0 + eqInfo.nxSegmented = 0 eqInfo.status = EquationInfo_Initialized_Before_All_States_Are_Known return nothing end @@ -771,7 +771,7 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa end eqInfo.nxInvariant = startIndex - 1 - # Set startIndex for segment states + # Set startIndex for segmented states for i = eqInfo.nx_info_invariant+1:length(x_info) xi_info = x_info[i] xi_info.length = length(xi_info.startOrInit) @@ -779,7 +779,7 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex += xi_info.length end eqInfo.nx = startIndex - 1 - @assert(eqInfo.nx == eqInfo.nxInvariant + eqInfo.nxSegment) + @assert(eqInfo.nx == eqInfo.nxInvariant + eqInfo.nxSegmented) # Construct x_start x_start = zeros(FloatType, eqInfo.nx) @@ -872,10 +872,10 @@ function Base.show(io::IO, eqInfo::EquationInfo; indent=4) if eqInfo.nx >= 0 nx = eqInfo.nx nxInvariant = eqInfo.nxInvariant - nxSegment = eqInfo.nxSegment + nxSegmented = eqInfo.nxSegmented nx_info_fixedLength = eqInfo.nx_info_fixedLength nx_info_invariant = eqInfo.nx_info_invariant - print(io, ",\n", indentation2, "nx = $nx, nxInvariant = $nxInvariant, nxSegment = $nxSegment") + print(io, ",\n", indentation2, "nx = $nx, nxInvariant = $nxInvariant, nxSegmented = $nxSegmented") print(io, ",\n", indentation2, "nx_info_fixedLength = $nx_info_fixedLength, nx_info_invariant = $nx_info_invariant") end diff --git a/src/EventHandler.jl b/src/EventHandler.jl index 69f2991..031e564 100644 --- a/src/EventHandler.jl +++ b/src/EventHandler.jl @@ -117,7 +117,7 @@ end #EventHandler{FloatType}(; kwargs...) where {FloatType} = EventHandler{FloatType,Float64}(; kwargs...) -function removeSegmentCrossingFunctions!(eh::EventHandler)::Nothing +function removeSegmentedCrossingFunctions!(eh::EventHandler)::Nothing if eh.nz > eh.nzInvariant resize!(eh.z, eh.nzInvariant) resize!(eh.zPositive, eh.nzInvariant) @@ -159,7 +159,7 @@ function reinitEventHandler!(eh::EventHandler{FloatType,TimeType}, stopTime::Tim eh.zPositive .= false eh.after .= false - removeSegmentCrossingFunctions!(eh) + removeSegmentedCrossingFunctions!(eh) return nothing end @@ -190,7 +190,7 @@ function reinitEventHandlerForFullRestart!(eh::EventHandler{FloatType,TimeType}, eh.zPositive .= false eh.after .= false - removeSegmentCrossingFunctions!(eh) + removeSegmentedCrossingFunctions!(eh) return nothing end diff --git a/src/Modia.jl b/src/Modia.jl index a0c61f9..83c0d88 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-06-06" +const Date = "2022-06-10" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -46,8 +46,8 @@ export stripUnit export simulate!, linearize!, get_result export @usingModiaPlot, usePlotPackage, usePreviousPlotPackage, currentPlotPackage -export resultInfo, printResultInfo, rawSignal, getPlotSignal, defaultHeading -export signalNames, timeSignalName, hasOneTimeSignal, hasSignal +export resultInfo, showResultInfo, rawSignal, getPlotSignal, defaultHeading +export signalNames, timeSignalName, hasSignal export hasParameter, getParameter, getEvaluatedParameter export showParameters, showEvaluatedParameters @@ -77,8 +77,8 @@ using ModiaBase.Differentiate import ModiaResult import ModiaResult: usePlotPackage, usePreviousPlotPackage, currentPlotPackage -import ModiaResult: resultInfo, printResultInfo, rawSignal, getPlotSignal, defaultHeading -import ModiaResult: signalNames, timeSignalName, hasOneTimeSignal, hasSignal +import ModiaResult: resultInfo, showResultInfo, getPlotSignal, defaultHeading +import ModiaResult: signalNames, timeSignalName, hasSignal import StaticArrays # Make StaticArrays available for the tests @@ -181,6 +181,7 @@ include("EvaluateParameters.jl") # include("GenerateGetDerivatives.jl") include("Synchronous.jl") include("SimulateAndPlot.jl") +include("ModiaResultInterface.jl") include("ReverseDiffInterface.jl") include("PathPlanning.jl") include("JSONModel.jl") diff --git a/src/ModiaResultInterface.jl b/src/ModiaResultInterface.jl new file mode 100644 index 0000000..3f2e92f --- /dev/null +++ b/src/ModiaResultInterface.jl @@ -0,0 +1,297 @@ +# License for this file: MIT (expat) +# Copyright 2022, DLR Institute of System Dynamics and Control + +#------------------------------------------------------------------------------------------------ +# Provide the overloaded ModiaResult Abstract Interface for the results of SimulationModel +#------------------------------------------------------------------------------------------------ + +""" + hasSignal(instantiatedModel::Modia.SimulationModel, name::AbstractString) + +Return true if time-varying variable `name` (for example `name = "a.b.c"`) +is defined in the instantiateModel that can be accessed and can be used for plotting. +""" +ModiaResult.hasSignal(m::SimulationModel, name::AbstractString) = begin + if isnothing(m) || ismissing(m) || ismissing(m.result) + return false + end + haskey(m.result.info, name) #|| !ismissing(get_value(m.evaluatedParameters, name)) +end + + +""" + timeSignalName(instantiatedModel::Modia.SimulationModel) + +Return the name of the independent variable of the result stored in instantiatedModel. +""" +ModiaResult.timeSignalName(m::SimulationModel) = m.result.timeName + + +""" + names = signalNames(instantiatedModel::Modia.SimulationModel) + +Return the names of the time-varying variables of an +[`@instantiateModel`](@ref) that are present in the result (e.g. can be accessed for plotting). +""" +ModiaResult.signalNames(m::SimulationModel) = collect(keys(m.result.info)) + + +function getVariableType(result::Result, resInfo::ResultInfo)::DataType + if ismissing(resInfo.VariableType) + @assert(resInfo.kind == RESULT_W_INVARIANT) + return typeof( result.w_invariant[1][1][resInfo.id[1].index] ) + else + return resInfo.VariableType + end +end + + +""" + info = SignalInfo(instantiatedModel::SimulationModel, name::AbstractString) + +Return information about signal `name` of the result present in instantiatedModel. +""" +function ModiaResult.SignalInfo(m::SimulationModel, name::AbstractString) + resInfo = m.result.info[name] + if resInfo.kind == RESULT_ELIMINATED + aliasResInfo = m.result.info[resInfo.aliasName] + VariableType = getVariableType(m.result, aliasResInfo) + return ModiaResult.SignalInfo(ModiaResult.Eliminated, VariableType, aliasResInfo.unit, aliasResInfo.value, resInfo.aliasName, resInfo.aliasNegate) + end + + kind = resInfo.kind == RESULT_T ? ModiaResult.Independent : + (resInfo.kind == RESULT_CONSTANT ? ModiaResult.Constant : + ( (resInfo.kind == RESULT_X || resInfo.kind == RESULT_DER_X) && isInvariant(resInfo.id) || (resInfo.W_INVARIANT ? ModiaResult.Invariant : ModiaResult.Segmenteded))) + + VariableType = getVariableType(m.result, resInfo) + return ModiaResult.SignalInfo(kind, VariableType, resInfo.unit, resInfo.value, "", false) +end + + +""" + s = signalValues(instantiatedModel::Modia.SimulationModel, name; unitless=false) + +Return signal `name` of the result present in instantiatedModel. +If `unitless=false`, the signal is returned with its unit. +""" +function ModiaResult.signalValues(m::SimulationModel, name; unitless=false) + if haskey(m.result.info, name) + return signalResultValues(m.result, name; unitless=unitless) + else + value = get_value(m.evaluatedParameters, name) + if ismissing(value) + error("signal(..): \"$name\" not in result and not a parameter of model $(m.modelName))") + end + return ModiaResult.OneValueVector(value, sum(length(tk) for tk in m.result.t)) + end +end + + +function get_algorithmName_for_heading(m::SimulationModel)::String + if ismissing(m.algorithmName) + algorithmName = "???" + else + algorithmName = m.algorithmName + i1 = findfirst("CompositeAlgorithm", algorithmName) + if !isnothing(i1) + i2 = findfirst("Vern" , algorithmName) + i3 = findfirst("Rodas", algorithmName) + success = false + if !isnothing(i2) && !isnothing(i3) + i2b = findnext(',', algorithmName, i2[1]) + i3b = findnext('{', algorithmName, i3[1]) + if !isnothing(i2b) && !isnothing(i3b) + algorithmName = algorithmName[i2[1]:i2b[1]-1] * "(" * algorithmName[i3[1]:i3b[1]-1] * "())" + success = true + end + end + if !success + algorithmName = "CompositeAlgorithm" + end + else + i1 = findfirst('{', algorithmName) + if !isnothing(i1) + algorithmName = algorithmName[1:i1-1] + end + i1 = findlast('.', algorithmName) + if !isnothing(i1) + algorithmName = algorithmName[i1+1:end] + end + end + end + return algorithmName +end + + +""" + leaveName = get_leaveName(pathName::String) + +Return the `leaveName` of `pathName`. +""" +get_leaveName(pathName::String) = + begin + j = findlast('.', pathName); + typeof(j) == Nothing || j >= length(pathName) ? pathName : pathName[j+1:end] + end + + +""" + ModiaResult.defaultHeading(instantiatedModel::Modia.SimulationModel) + +Return default heading of instantiatedModel result as a string +(can be used as default heading for a plot). +""" +function ModiaResult.defaultHeading(m::SimulationModel) + FloatType = get_leaveName( string( typeof( m.x_start[1] ) ) ) + + algorithmName = get_algorithmName_for_heading(m) + if FloatType == "Float64" + heading = m.modelName * " (" * algorithmName * ")" + else + heading = m.modelName * " (" * algorithmName * ", " * FloatType * ")" + end + return heading +end + + + +# For backwards compatibility + +""" + signal = get_result(instantiatedModel, name; unit=true) + dataFrame = get_result(instantiatedModel; onlyStates=false, extraNames=missing) + +- First form: After a successful simulation of `instantiatedModel`, return + the result for the signal `name::String` as vector of points + together with its unit. The time vector has path name `"time"`. + If `unit=false`, the signal is returned, **without unit**. + +- Second form: Return the **complete result** in form of a DataFrame object. + Therefore, the whole functionality of package [DataFrames](https://dataframes.juliadata.org/stable/) + can be used, including storing the result on file in different formats. + Furthermore, also plot can be used on dataFrame. + Parameters and zero-value variables are stored as ModiaResult.OneValueVector inside dataFrame + (are treated as vectors, but actually only the value and the number + of time points is stored). If `onlyStates=true`, then only the states and the signals + identified with `extraNames::Vector{String}` are stored in `dataFrame`. + If `onlyStates=false` and `extraNames` given, then only the signals + identified with `extraNames` are stored in `dataFrame`. + These keyword arguments are useful, if `dataFrame` shall be + utilized as reference result used in compareResults(..). + +In both cases, a **view** on the internal result memory is provided +(so result data is not copied). + +# Example + +```julia +using Modia +@usingModiaPlot +using Unitful + +include("\$(Modia.path)/examples/Pendulum.jl") +using .Model_Pendulum + +pendulum = simulationModel(Pendulum) +simulate!(pendulum, stopTime=7.0) + +# Get one signal from the result and plot with the desired plot package +time = get_result(pendulum, "time") # vector with unit u"s" +phi = get_result(pendulum, "phi") # vector with unit u"rad" + +import PyPlot +PyPlot.figure(4) # Change to figure 4 (or create it, if it does not exist) +PyPlot.clf() # Clear current figure +PyPlot.plot(stripUnit(time), stripUnit(phi), "b--", label="phi in " * string(unit(phi[1]))) +PyPlot.xlabel("time in " * string(unit(time[1]))) +PyPlot.legend() + +# Get complete result and plot one signal +result = get_result(pendulum) +plot(result, "phi") + +# Get only states to be used as reference and compare result with reference +reference = get_result(pendulum, onlyStates=true) +(success, diff, diff_names, max_error, within_tolerance) = + ModiaResult.compareResults(result, reference, tolerance=0.01) +println("Check results: success = $success") +``` +""" +function get_result(m::SimulationModel, name::AbstractString; unit=true) + #(xsig, xsigLegend, ysig, ysigLegend, yIsConstant) = ModiaResult.getPlotSignal(m, "time", name) + + #resIndex = m.variables[name] + #ysig = ResultView(m.result, abs(resIndex), resIndex < 0) + + #if ModiaResult.timeSignalName(m) != 1 + if length(m.result.t) > 1 + error("Error in Modia.get_result(\"$name\"), because function cannot be used for a segmenteded simulation with more as one segmented.") + end + + (tsig2, ysig2, ysigType) = ModiaResult.rawSignal(m, name) + ysig = ysig2[1] + ysig = unit ? ysig : stripUnit.(ysig) + + #= + if yIsConstant + if ndims(ysig) == 1 + ysig = fill(ysig[1], length(xsig)) + else + ysig = fill(ysig[1,:], length(xsig)) + end + end + =# + + return ysig +end + + +function setEvaluatedParametersInDataFrame!(obj::OrderedDict{Symbol,Any}, result_info, dataFrame::DataFrames.DataFrame, path::String, nResult::Int)::Nothing + for (key,value) in zip(keys(obj), obj) + name = appendName(path, key) + if typeof(value) <: OrderedDict{Symbol,Any} + setEvaluatedParametersInDataFrame!(value, result_info, dataFrame, name, nResult) + elseif !haskey(result_info, name) + dataFrame[!,name] = ModiaResult.OneValueVector(value,nResult) + end + end + return nothing +end + + +function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) + if length(m.result.t) > 1 + error("Error in Modia.get_result(...), because function cannot be used for a segmenteded simulation with more as one segmented.") + end + + dataFrame = DataFrames.DataFrame() + + (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, "time") + dataFrame[!,"time"] = timeSignal[1] + + if onlyStates || !ismissing(extraNames) + if onlyStates + for name in keys(m.equationInfo.x_dict) + (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) + dataFrame[!,name] = signal[1] + end + end + if !ismissing(extraNames) + for name in extraNames + (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) + dataFrame[!,name] = signal[1] + end + end + + else + for name in keys(m.result.info) + if name != "time" + (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) + dataFrame[!,name] = signal[1] + end + end + + setEvaluatedParametersInDataFrame!(m.evaluatedParameters, m.result.info, dataFrame, "", length(timeSignal[1])) + end + return dataFrame +end \ No newline at end of file diff --git a/src/Result.jl b/src/Result.jl index eab5ce3..60f9a33 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -7,101 +7,93 @@ using OrderedCollections: OrderedDict, OrderedSet import ModiaResult """ - @enum ResultKind RESULT_ELIMINATED RESULT_CONSTANT_INVARIANT RESULT_CONSTANT_SEGMENT RESULT_T RESULT_X RESULT_DER_X RESULT_W_INVARIANT RESULT_W_SEGMENT + @enum ResultKind RESULT_ELIMINATED RESULT_CONSTANT RESULT_T RESULT_X RESULT_DER_X RESULT_W_INVARIANT RESULT_W_SEGMENTED Kind of result variable. -| ResultKind value | Description | -|:-------------------|:------------------------------------------------------------------------| -| RESULT_ELIMINATED | Variable is eliminated - alias info stored in result.info | -| RESULT_CONSTANT | Variable is constant all the time - value stored in result.info | -| RESULT_T | Independent variable (usually time) - stored in result.t | -| RESULT_X | State (invariant/segment variable) - stored in result.x | -| RESULT_DER_X | State derivative (invariant/segment variable) - stored in result.der_x | -| RESULT_W_INVARIANT | Invariant algebraic variable - stored in result.w_invariant | -| RESULT_W_SEGMENT | Segment algebraic variable - stored in result.w_segment | +| ResultKind value | Description | +|:-------------------|:-------------------------------------------------------------------------| +| RESULT_ELIMINATED | Variable is eliminated - alias info stored in result.info | +| RESULT_CONSTANT | Variable is constant all the time - value stored in result.info | +| RESULT_T | Independent variable (usually time) - stored in result.t | +| RESULT_X | State (invariant/segmented variable) - stored in result.x | +| RESULT_DER_X | State derivative (invariant/segmented variable) - stored in result.der_x | +| RESULT_W_INVARIANT | Invariant algebraic variable - stored in result.w_invariant | +| RESULT_W_SEGMENTED | Segmented algebraic variable - stored in result.w_segmented | """ -@enum ResultKind RESULT_ELIMINATED RESULT_CONSTANT RESULT_T RESULT_X RESULT_DER_X RESULT_W_INVARIANT RESULT_W_SEGMENT +@enum ResultKind RESULT_ELIMINATED RESULT_CONSTANT RESULT_T RESULT_X RESULT_DER_X RESULT_W_INVARIANT RESULT_W_SEGMENTED """ - locationID = LocationID(index, size) # Location id of invariant variable - locationID = LocationID(segment, index, size) # Location id of segment variable + id = ValuesID(index, dims) # ValuesID of invariant variable + id = ValuesID(segment, index, dims) # ValuesID of segmented variable -Return a new location id (defining the location of the values of a variable with respect to ResultKind). +Return a new id that defines where the values of a variable are stored. """ -struct LocationID - segment::Int # Index of simulation segment (= -1, if invariant variable) - index::Int # Index or start index with respect to simulation segment (= -1, if time (RESULT_T)) - size::Tuple # Dimensions with respect to simulation segment. size=(): scalar variable or size now known +struct ValuesID + segment::Int # Index of simulation segment (= -1, if invariant variable) + index::Int # Index or start index with respect to simulation segment + dims::Union{Dims,Missing} # Dimensions with respect to simulation segment (dims=missing, if dimensions not known) - LocationID(index, size) = new(-1, index, size) - LocationID(segment, index, size) = new(segment, index, size) + ValuesID(index, dims) = new(-1, index, dims) + ValuesID(segmented, index, dims) = new(segmented, index, dims) end +hasIinlineValues(kind::ResultKind) = kind == RESULT_X || RESULT_DER_X +hasDims( kind::ResultKind) = kind != RESULT_W_INVARIANT + +isInvariant(id::Vector{ValuesID}) = length(id) == 1 +isSegmented(id::Vector{ValuesID}, t::AbstractVector) = !(length(id) == 1 || length(id) == length(t)) + +index_i(id::Vector{ValuesID}, i::Int) = isInvariant(id) ? id[1].index : id[i].index +dims_i( id::Vector{ValuesID}, i::Int, kind::ResultKind, v::AbstractVector) = hasDims(kind) ? (isInvariant(id) ? id[1].dims : id[i].dims) : + (isInvariant(id) ? size(v[1][1][id[1].index]) : size(v[i][1][id[i].index])) + + """ - info = ResultInfo(kind, aliasName; negate=false) # Define alias ResultInfo - info = ResultInfo(kind, value, unit) # Define constant ResultInfo - info = ResultInfo(kind, default, unit, invariant) # Define partial ResultInfo of x or der_x - info = ResultInfo(kind, default, unit, signalKind, index) # Define ResultInfo for invariant variable - info = ResultInfo(kind, default, unit, signalKind, segment, index) # Define ResultInfo for segment variable + info = ResultInfo(kind, aliasName; negate=false) # Define alias ResultInfo + info = ResultInfo(kind, defaultOrValue, unit) # Define constant ResultInfo or partial ResultInfo of x or der_x + info = ResultInfo(kind, default , unit, index) # Define ResultInfo for invariant variable + info = ResultInfo(kind, default , unit, segment, index) # Define ResultInfo for segmented variable Return info how to access a result variable. """ struct ResultInfo - kind::ResultKind # Kind of result variable in simulation segment sk at time instant ti and (invariant or varying) index: - # = RESULT_ELIMINATED : Variable is eliminated. Alias info is stored in result.info - # = RESULT_CONSTANT : Variable is constant all the time. Value is stored in result.info - # = RESULT_T : result.t[ sk][ti] - # = RESULT_X : result.x[ sk][ti][index:index+prod(dims)-1] - # = RESULT_DER_X : result.der_x[ sk][ti][index:index+prod(dims)-1] - # = RESULT_W_INVARIANT: result.w_invariant[sk][ti][index] - # = RESULT_W_SEGMENT : result.w_segment[ sk][ti][index] - - # Only if kind = RESULT_ELIMINATED - aliasName::String # Name of non-eliminated variable - aliasNegate::Bool # = true, if info[aliasName] signal must be negated - - # Only if kind = RESULT_CONSTANT - value::Union{Any,Nothing} # Value of constant variable (without unit) - - # For all kinds with exception of RESULT_ELIMINATED and RESULT_W_INVARIANT - type::Union{DataType,Nothing} # Type of variable (to make sure that the type is not changing) - unit::String # Unit of variable as a parseable string. - ndims::Int # Number of dimensions (= length(dims); to make sure that ndims is not changing) - # ndims = -1, if type=nothing - - # For all kinds with exception of RESULT_ELIMINATED and RESULT_CONSTANT - signalKind::ModiaResult.SignalType # Kind of signal - invariant::Bool # = true, invariant variable - # = false, segment variable - - # For all kinds with exception of RESULT_ELIMINATED, RESULT_CONSTANT and RESULT_T - locationID::Vector{LocationID} # if invariant = true : locationID[1] is location for all segments - # if invariant = false: locationID[i] is segment specific location - - ResultInfo(kind::ResultKind, aliasName::String; negate::Bool=false) = begin - @assert(kind == RESULT_ELIMINATED) - (kind, aliasName, negate) - end - ResultInfo(kind::ResultKind, value, unit::String) = begin - @assert(kind == RESULT_CONSTANT) - (kind, "", false, value, typeof(value), unit, ndims(value)) - end - ResultInfo(kind::ResultKind, default, unit::String, invariant::Bool) = begin - @assert(kind == RESULT_X || kind == RESULT_DER_X ) - new(kind, "", false, nothing, typeof(default), unit, ndims(default), ModiaResult.Continuous, invariant, LocationID[]) - end - ResultInfo(kind::ResultKind, default, unit::String, signalKind, index) = begin - @assert(kind != RESULT_ELIMINATED && kind != RESULT_CONSTANT) - new(kind, "", false, nothing, typeof(default), unit, isnothing(default) ? -1 : ndims(default), - signalKind, true, LocationID[LocationID(index , isnothing(default) ? () : size(default))]) - end - ResultInfo(kind::ResultKind, default, unit::String, signalKind, segment, index) = begin - @assert(kind != RESULT_ELIMINATED && kind != RESULT_CONSTANT) - new(kind, "", false, nothing, typeof(default), unit, ndims(default), signalKind, false, LocationID[LocationID(segment,index,size(default))]) - end + kind::ResultKind # Kind of result variable in simulation segment sk at time instant ti with index = index_i(..): + # = RESULT_ELIMINATED : Variable is eliminated. Alias info is stored in result.info + # = RESULT_CONSTANT : Variable is constant all the time. Value is stored in result.info + # = RESULT_T : result.t[ sk][ti] + # = RESULT_X : result.x[ sk][ti][index:index+prod(dims_i(..))-1] + # = RESULT_DER_X : result.der_x[ sk][ti][index:index+prod(dims_i(..))-1] + # = RESULT_W_INVARIANT: result.w_invariant[sk][ti][index] + # = RESULT_W_SEGMENTED: result.w_segmented[sk][ti][index] + + aliasName::String # Name of non-eliminated variable + aliasNegate::Bool # = true, if info[aliasName] signal must be negated + value::Union{Any,Missing} # Value of constant variable (without unit) + + VariableType::Union{DataType,Missing} # Type of variable, if known (to make sure that the VariableType is not changing) + unit::String # Unit of variable as a parseable string. If not known, unit="". + id::Vector{ValuesID} # Location of the variable values with respect to ResultKind and Result + + ResultInfo(kind::ResultKind, aliasName::String; negate::Bool=false) = begin + @assert(kind == RESULT_ELIMINATED) + (kind, aliasName, negate, missing, missing, "", ValuesID[]) + end + ResultInfo(kind::ResultKind, defaultOrValue, unit::String) = begin + @assert(kind == RESULT_CONSTANT || kind == RESULT_X || kind == RESULT_DER_X) + if kind == RESULT_CONSTANT + (kind, "", false, defaultOrValue, typeof(defaultOrValue), unit, ValuesID[]) + else + (kind, "", false, missing, typeof(defaultOrValue), unit, ValuesID[]) + end + end + ResultInfo(kind::ResultKind, default, unit::String, index) = ResultInfo(kind,default,unit,-1,index) + ResultInfo(kind::ResultKind, default, unit::String, segment, index) = begin + @assert(kind != RESULT_ELIMINATED && kind != RESULT_CONSTANT) + new(kind, "", false, default, unit, ValuesID[ValuesID(segment,index,ismissing(default) ? missing : size(default))]) + end end @@ -116,53 +108,53 @@ mutable struct Result{FloatType,TimeType} timeName::String # Name of independent variable (usually time) timeResultInfo::ResultInfo # Reference to result.info[timeName] n_w_invariant::Int # Number of w_invariant variables - alias_segment_names::OrderedSet{String} # Names of alias_segment results in current segment - w_segment_names::OrderedSet{String} # Names of w_segment results in current segment - w_segment_temp::Vector{Any} # Memory to store temporarily references to w_segment results in current segment; - # length(w_segment_temp) = length(w_segment_names) + alias_segmented_names::OrderedSet{String} # Names of alias_segmented results in current segment + w_segmented_names::OrderedSet{String} # Names of w_segmented results in current segment + w_segmented_temp::Vector{Any} # Memory to store temporarily references to w_segmented results in current segment + # length(w_segmented_temp) = length(w_segmented_names) t::Vector{Vector{TimeType}} # t[sk][ti] is time instant ti in segment sk - # A variable v[sk][ti][j] is variable with index j at time instant ti in segment sk - x::Vector{Vector{Vector{FloatType}}} # x[sk][ti][j] - invariant and segment states - der_x::Vector{Vector{Vector{FloatType}}} # der_x[sk][ti][j] - invariant and segment state derivatives + # A variable v[sk][ti][j] is variable with index j at time instant ti in segmented sk + x::Vector{Vector{Vector{FloatType}}} # x[sk][ti][j] - invariant and segmented states + der_x::Vector{Vector{Vector{FloatType}}} # der_x[sk][ti][j] - invariant and segmented state derivatives w_invariant::Vector{Vector{Tuple}} # w_invariant[sk][ti][j] - invariant algebraic variables - w_segment::Vector{Vector{Vector{Any}}} # w_segment[sk][ti][j] - segment algebraic variables + w_segmented::Vector{Vector{Vector{Any}}} # w_segmented[sk][ti][j] - segmented algebraic variables function Result{FloatType,TimeType}(timeNameAsString::String, eqInfo::EquationInfo, w_invariant_names, vEliminated, vProperty, var_name) where {FloatType,TimeType} - info = OrderedDict{String, ResultInfo}() - n_w_invariant = length(w_invariant_names) - alias_segment_names = OrderedSet{String}() - w_segment_names = OrderedSet{String}() - w_segment_temp = Any[] - t = fill(TimeType[],0) - x = fill(Vector{FloatType}[], 0) - der_x = fill(Vector{FloatType}[], 0) - w_invariant = fill(Tuple[],0) - w_segment = fill(Vector{Any}[], 0) + info = OrderedDict{String, ResultInfo}() + n_w_invariant = length(w_invariant_names) + alias_segmented_names = OrderedSet{String}() + w_segmented_names = OrderedSet{String}() + w_segmented_temp = Any[] + t = fill(TimeType[],0) + x = fill(Vector{FloatType}[], 0) + der_x = fill(Vector{FloatType}[], 0) + w_invariant = fill(Tuple[],0) + w_segmented = fill(Vector{Any}[], 0) # Fill info with time - timeResultInfo = ResultInfo(RESULT_T, TimeType(0), "s", ModiaResult.Independent, -1) + timeResultInfo = ResultInfo(RESULT_T, TimeType(0), "s", 1) info[timeNameAsString] = timeResultInfo - # Fill info with x_invariant, der_x_invariant (but with dummy locationID, since not yet known) + # Fill info with x_invariant, der_x_invariant (but with dummy id, since not yet known) for i = 1:eqInfo.nx_info_invariant xi_info = eqInfo.x_info[i] - x_unit = xi_info.unit + x_unit = xi_info.unit der_x_unit = x_unit == "" ? "1/s" : unitAsString(unit(uparse(x_unit)/u"s")) @assert(!haskey(info, xi_info.x_name)) @assert(!haskey(info, xi_info.der_x_name)) if isnothing(xi_info.startOrInit) xi_info.startOrInit = FloatType(0) end - info[xi_info.x_name] = ResultInfo(RESULT_X , xi_info.startOrInit, x_unit , true) - info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, xi_info.startOrInit, der_x_unit, true) + info[xi_info.x_name] = ResultInfo(RESULT_X , xi_info.startOrInit, x_unit ) + info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, xi_info.startOrInit, der_x_unit) end # Fill info with w_invariant for (w_invariant_index, w_invariant_name) in enumerate(w_invariant_names) name = string(w_invariant_name) @assert(!haskey(info, name)) - info[name] = ResultInfo(RESULT_W_INVARIANT, nothing, "", ModiaResult.Continuous, w_invariant_index) + info[name] = ResultInfo(RESULT_W_INVARIANT, missing, "", w_invariant_index) end # Fill info with eliminated variables @@ -182,7 +174,7 @@ mutable struct Result{FloatType,TimeType} end end - new(info, timeNameAsString, timeResultInfo, n_w_invariant, alias_segment_names, w_segment_names, w_segment_temp, t, x, der_x, w_invariant, w_segment) + new(info, timeNameAsString, timeResultInfo, n_w_invariant, alias_segmented_names, w_segmented_names, w_segmented_temp, t, x, der_x, w_invariant, w_segmented) end end @@ -192,74 +184,165 @@ function newResultSegment!(result::Result{FloatType,TimeType})::Nothing where {F push!(result.x , Vector{FloatType}[]) push!(result.der_x , Vector{FloatType}[]) push!(result.w_invariant, Tuple[]) - push!(result.w_segment , Vector{Any}[]) + push!(result.w_segmented , Vector{Any}[]) return nothing end -""" - iterator = SegmentAndIndex(resultInfo::ResultInfo, nSegments::Int) - -Iterate over the segments of result/resultInfo. -""" -struct SegmentAndIndex - resInfo::ResultInfo - nSegments::Int # Number of segments -end - -@inline function getInvariantLocation(resultInfo::ResultInfo, iter::Int)::NTuple{3,Int} - id = resultInfo.locationID[1] - return (iter, id.index, id.index+prod(id.size)-1) -end - -@inline function getSegmentLocation(resultInfo::ResultInfo, iter::Int)::NTuple{3,Int} - id = resultInfo.locationID[iter] - return (id.segment, id.index, id.index+prod(id.size)-1) -end - -Base.iterate(s::SegmentAndIndex, iter=1) = s.resInfo.invariant ? (iter > s.nSegments ? nothing : (getInvariantLocation(s.resInfo,iter), iter+1)) : - (iter > length(s.resInfo.locationID) ? nothing : (getSegmentLocation( s.resInfo,iter), iter+1)) -Base.length(s::SegmentAndIndex) = s.resInfo.invariant ? s.nSegments : length(s.resInfo.locationID) - - -struct Segment - resInfo::ResultInfo - nSegments::Int # Number of segments +dims_range(dims::Dims) = Tuple([1:i for i in dims]) +dims_i( inlineValues::Bool, id::Vector{ValuesID}, k::Int, s::AbstractVector) = inlineValues ? id[k].dims : size( s[k][1][id[k].index]) +ndims_i(inlineValues::Bool, id::Vector{ValuesID}, k::Int, s::AbstractVector) = inlineValues ? length(id[k].dims) : ndims(s[k][1][id[k].index]) + +signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::ResultInfo; log=false, name::AbstractString="") = + signalResultValues(t, s, resultInfo.id, kind == RESULT_X || kind == RESULT_DER_X, resultInfo.VariableType, log=log, name=name) + +function signalResultValues(t::AbstractVector, s::AbstractVector, id::Vector{ValuesID}, inlineValues::Bool, VariableType=Float64; log=false, name::AbstractString="") + @assert(length(id) > 0) + + if length(id) == 1 && ndims_i(inlineValues,id,1,s) == 0 + # Scalar signal that is defined in every segment + index = id[1].index + sc = VariableType[ti[index] for sk in s for ti in sk] + + else + # Find largest dims = dimsMax in all segments + dimsMax::Dims{ndims_i(inlineValues,id,1,s)} = dims_i(inlineValues,id,1,s) + hasMissing::Bool = !(length(id) == 1 || length(id) == length(t)) + if length(id) > 1 + dMax::Vector{Int} = [dimsMax...] + for i = 2:length(id) + dimi = dims_i(inlineValues,id,i,s) + @assert(length(dMax) == length(dimi)) + if dimi != dMax + hasMissing = true + for j = 1:length(dimi) + if dimi[j] > dMax[j] + dMax[j] = dimi[j] + end + end + end + end + dimsMax = Tuple(dMax) + end + + # Allocate memory for target signal + dims1 = sum(size(tk,1) for tk in t) + dims = (dims1, dimsMax...) + if hasMissing + # Allocate target memory with missing values + sc = Array{Union{VariableType,Missing}, length(dims)}(missing, dims) + else + # Allocate target memory with undef values + @assert(length(dimsMax) > 0) + sc = Array{VariableType, length(dims)}(undef, dims) + end + + # Copy subset of s-values to target sc + invariant = length(id) == 1 + segmentOld = 1 + j = 1 + if length(dimsMax) == 0 + # Target is a scalar signal + if invariant + index = id[1].index + end + for k = 1:length(s) + if !invariant + index = id[k].index + segment = id[k].segment + if segmentOld < segment-1 + j = sum(length(t[i]) for i = segmentOld:segment-1) + 1 + segmentOld = segment + end + end + for s_ti in s[k] + sc[j] = s_ti[index] + j += 1 + end + end + else + # Target is not a scalar signal setindex!(A,x,(2,2:4)...) + if inlineValues + if invariant + dims = id[1].dims + dimr = dims_range(dims) + ibeg = id[1].index + iend = ibeg + prod(dims) - 1 + end + for k = 1:length(s) + if !invariant + dims = id[k].dims + dimr = dims_range(dims) + ibeg = id[k].index + iend = ibeg + prod(dims) - 1 + segment = id[k].segment + if segmentOld < segment-1 + j = sum(length(t[i]) for i = segmentOld:segment-1) + 1 + segmentOld = segment + end + end + for s_ti in s[k] + setindex!(sc, reshape(view(s_ti,ibeg:iend),dims), (j,dimr...)...) + j += 1 + end + end + else + if invariant + index = id[1].index + dimr = dims_range( size(s[1][1][index]) ) + end + for k = 1:length(s) + if !invariant + index = id[k].index + dimr = dims_range( size(s[k][1][index]) ) + segment = id[k].segment + if segmentOld < segment-1 + j = sum(length(t[i]) for i = segmentOld:segment-1) + 1 + segmentOld = segment + end + end + for s_ti in s[k] + setindex!(sc, s_ti[index], (j,dimr...)...) + j += 1 + end + end + end + end + end + + if log + println("$name[id] = $sc") + println("typeof($name[id]) = ", typeof(sc)) + end + return sc end -Base.iterate(s::Segment, iter=1) = s.resInfo.invariant ? (iter > s.nSegments ? nothing : (iter, iter+1)) : - (iter > length(s.resInfo.locationID) ? nothing : (s.resInfo.locationID[iter].segment, iter+1)) -Base.length(s::Segment) = s.resInfo.invariant ? s.nSegments : length(s.resInfo.locationID) - -function rawSignal(result::Result, name::AbstractString; unitless=true)::Tuple{AbstractVector, AbstractVector, ModiaResult.SignalType} - nSegments = length(result.t) - resInfo = result.info[name] - negate = false +function signalResultValues(result::Result, name::AbstractString; unitless=true) + resInfo = result.info[name] + negate = false if resInfo.kind == RESULT_ELIMINATED resInfo = result.info[resInfo.aliasName] negate = result.info[resInfo.aliasNegate] end - tSig = [ result.t[sk] for sk in Segment(resInfo,nSegments) ] - if resInfo.kind == RESULT_T - sig = result.t + sig = signal(result.t, result.t, resInfo) elseif resInfo.kind == RESULT_X - sig = [ [ibeg==iend ? x_ti[ibeg] : x_ti[ibeg:iend] for x_ti in result.x[sk]] for (sk,ibeg,iend) in SegmentAndIndex(resInfo,nSegments) ] + sig = signal(result.t, result.x, resInfo) elseif resInfo.kind == RESULT_DER_X - sig = [ [ibeg==iend ? der_x_ti[ibeg] : der_x_ti[ibeg:iend] for der_x_ti in result.der_x[sk]] for (sk,ibeg,iend) in SegmentAndIndex(resInfo,nSegments) ] + sig = signal(result.t, result.der_x, resInfo) elseif resInfo.kind == RESULT_W_INVARIANT - sig = [ [w_ti[index] for w_ti in result.w_invariant[sk]] for (sk,index,dummy) in SegmentAndIndex(resInfo,nSegments) ] - elseif resInfo.kind == RESULT_W_SEGMENT - sig = [ [w_ti[index] for w_ti in result.w_segment[sk]] for (sk,index,dummy) in SegmentAndIndex(resInfo,nSegments) ] + sig = signal(result.t, result.w_invariant, resInfo) + elseif resInfo.kind == RESULT_W_SEGMENTED + sig = signal(result.t, result.w_segmented, resInfo) elseif resInfo.kind == RESULT_CONSTANT - sig = [ ModiaResult.OneValueVector(resInfo.value, length(result.t[sk])) for sk = 1:length(result.t) ] + sig = ModiaResult.OneValueVector(resInf.value, sum(length(tk) for tk in result.t)) else - error("Bug in Modia.rawSignal: name=\"$name\" has ResultInfo=$resInfo, but ResultInof.kind = $(resInfo.kind) is not known.") + error("Bug in Modia.signal: name=\"$name\" has ResultInfo=$resInfo, but ResultInfo.kind = $(resInfo.kind) is not known.") end - + if negate sig *= -1 end @@ -270,8 +353,7 @@ function rawSignal(result::Result, name::AbstractString; unitless=true)::Tuple{A end elseif !unitless && resInfo.unit != "" sig *= uparse(resInfo.unit) - end - return (tSig, sig, resInfo.signalKind) -end - - + end + + return sig +end \ No newline at end of file diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index a8d3ef4..6a5be02 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -93,7 +93,7 @@ can be used (instead of `import Sundials; simulate!(instantiatedModel, Sundials. The simulation results are stored in `instantiatedModel` and can be plotted with `plot(instantiatedModel, ...)` and the result values -can be retrieved with `rawSignal(..)` or `getPlotSignal(..)`. `printResultInfo(instantiatedModel)` +can be retrieved with `rawSignal(..)` or `getPlotSignal(..)`. `showResultInfo(instantiatedModel)` prints information about the signals in the result file. For more details, see sections [Parameters/Init/Start](@ref), [Results](@ref), [Plotting](@ref). @@ -222,7 +222,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me m.options = options m.time = options.startTime m.isInitial = true - m.nsegment = 1 + m.nsegmented = 1 reinitEventHandler!(m.eventHandler, m.options.stopTime, m.options.logEvents) if ismissing(algorithm) && FloatType == Float64 @@ -423,7 +423,7 @@ function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=miss m.odeIntegrator = false nx = length(m.x_init) differential_vars = eh.nz > 0 ? fill(true, nx) : nothing # due to DifferentialEquations issue #549 - copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segment) + copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segmented) TimerOutputs.@timeit m.timer "DifferentialEquations.DAEProblem" problem = DifferentialEquations.DAEProblem{true}(DAEresidualsForODE!, m.der_x, m.x_init, tspan, m, differential_vars = differential_vars) empty!(m.daeCopyInfo) if length(sizesOfLinearEquationSystems) > 0 && maximum(sizesOfLinearEquationSystems) >= options.nlinearMinForDAE @@ -615,27 +615,6 @@ function linearize!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; end -#------------------------------------------------------------------------------------------------ -# Provide the overloaded ModiaResult Abstract Interface for the results of SimulationModel -#------------------------------------------------------------------------------------------------ - -ModiaResult.timeSignalName( m::SimulationModel) = m.result.timeName -ModiaResult.hasOneTimeSignal(m::SimulationModel) = length(m.result.t) == 1 - - -""" - hasSignal(instantiatedModel::Modia.SimulationModel, name::AbstractString) - -Return true if time-varying variable `name` (for example `name = "a.b.c"`) -is defined in the instantiateModel that can be accessed and can be used for plotting. -""" -ModiaResult.hasSignal(m::SimulationModel, name::AbstractString) = begin - if isnothing(m) || ismissing(m) || ismissing(m.result) - return false - end - haskey(m.result.info, name) || !ismissing(get_value(m.evaluatedParameters, name)) -end - """ hasParameter(instantiatedModel, name::AbstractString) @@ -693,15 +672,6 @@ function showEvaluatedParameters(m::SimulationModel)::Nothing end -""" - names = signalNames(instantiatedModel::Modia.SimulationModel) - -Return the names of the time-varying variables of an -[`@instantiateModel`](@ref) that are present in the result (e.g. can be accessed for plotting). -""" -ModiaResult.signalNames(m::SimulationModel) = collect(keys(m.result.info)) - - #= import ChainRules @@ -715,308 +685,3 @@ function ChainRules.rrule(::typeof(ResultView), v, i) return y, ResultView_pullback end =# - -""" - (timeSignal, signal, signalType) = ModiaResult.rawSignal(instantiatedModel, name) - (timeSignal, signal, signalType) = Modia.rawSignal( instantiatedModel, name) - -Get raw signal of result from an instantiated model of Modia. -""" -function ModiaResult.rawSignal(m::SimulationModel, name::AbstractString) - if haskey(m.result.info, name) - return rawSignal(m.result, name, unitless=m.unitless) - else - value = get_value(m.evaluatedParameters, name) - if ismissing(value) - error("rawSignal: \"$name\" not in result and not a parameter of model $(m.modelName))") - end - signal = [ ModiaResult.OneValueVector(value, length(tk)) for tk in m.result.t ] - return (m.result.t, signal, ModiaResult.Continuous) - end -#= - tsig = m.result_x.t - if !m.unitless - tsig = tsig*u"s" - if !(m.options.desiredResultTimeUnit == NoUnits || - m.options.desiredResultTimeUnit == u"s") - tsig = uconvert.(m.options.desiredResultTimeUnit, tsig) - end - end - - if name == "time" - return ([tsig], [tsig], ModiaResult.Independent) - end - - if haskey(m.result_info, name) - #println("rawSignal: name = $name") - resInfo = m.result_info[name] - - if resInfo.store == RESULT_X - (ibeg,iend,xunit) = get_xinfo(m, resInfo.index) - if ibeg == iend - xSig = [v[ibeg] for v in m.result_x.u] - else - xSig = [v[ibeg:iend] for v in m.result_x.u] - end - if resInfo.negate - xSig *= -1 - end - if !m.unitless && xunit != "" - xSig = xSig*uparse(xunit) - end - return ([tsig], [xSig], ModiaResult.Continuous) - - elseif resInfo.store == RESULT_DER_X - (ibeg,iend,xunit) = get_xinfo(m, resInfo.index) - if ibeg == iend - derxSig = [v[ibeg] for v in m.result_der_x] - else - derxSig = [v[ibeg:iend] for v in m.result_der_x] - end - if resInfo.negate - derxSig *= -1 - end - - if !m.unitless - if xunit == "" - derxSig = derxSig/u"s" - else - derxSig = derxSig*(uparse(xunit)/u"s") - end - end - return ([tsig], [derxSig], ModiaResult.Continuous) - - elseif resInfo.store == RESULT_CODE - signal = ModiaResult.SignalView(m.result_code, resInfo.index, resInfo.negate) - if length(signal) != length(tsig) - lens = length(signal) - lent = length(tsig) - error("Bug in SimulateAndPlot.jl (rawSignal(..)): name=\"$name\",\nlength(signal) = $lens, length(tsig) = $lent") - end - return ([tsig], [signal], ModiaResult.Continuous) - - elseif resInfo.store == RESULT_EXTRA - signal = ModiaResult.SignalView(m.result_extra, resInfo.index, resInfo.negate) - if length(signal) != length(tsig) - lens = length(signal) - lent = length(tsig) - error("Bug in SimulateAndPlot.jl (rawSignal(..)): name=\"$name\",\nlength(signal) = $lens, length(tsig) = $lent") - end - return ([tsig], [signal], ModiaResult.Continuous) - - elseif resInfo.store == RESULT_ZERO - signal = ModiaResult.OneValueVector(0.0, length(tsig)) - return ([tsig], [signal], ModiaResult.Continuous) - - else - error("Bug in SimulateAndPlot.jl (rawSignal(..)): name=\"$name\", resInfo=$resInfo") - end - end -=# -end - - - - -""" - leaveName = get_leaveName(pathName::String) - -Return the `leaveName` of `pathName`. -""" -get_leaveName(pathName::String) = - begin - j = findlast('.', pathName); - typeof(j) == Nothing || j >= length(pathName) ? pathName : pathName[j+1:end] - end - - -function get_algorithmName_for_heading(m::SimulationModel)::String - if ismissing(m.algorithmName) - algorithmName = "???" - else - algorithmName = m.algorithmName - i1 = findfirst("CompositeAlgorithm", algorithmName) - if !isnothing(i1) - i2 = findfirst("Vern" , algorithmName) - i3 = findfirst("Rodas", algorithmName) - success = false - if !isnothing(i2) && !isnothing(i3) - i2b = findnext(',', algorithmName, i2[1]) - i3b = findnext('{', algorithmName, i3[1]) - if !isnothing(i2b) && !isnothing(i3b) - algorithmName = algorithmName[i2[1]:i2b[1]-1] * "(" * algorithmName[i3[1]:i3b[1]-1] * "())" - success = true - end - end - if !success - algorithmName = "CompositeAlgorithm" - end - else - i1 = findfirst('{', algorithmName) - if !isnothing(i1) - algorithmName = algorithmName[1:i1-1] - end - i1 = findlast('.', algorithmName) - if !isnothing(i1) - algorithmName = algorithmName[i1+1:end] - end - end - end - return algorithmName -end - - -function ModiaResult.defaultHeading(m::SimulationModel) - FloatType = get_leaveName( string( typeof( m.x_start[1] ) ) ) - - algorithmName = get_algorithmName_for_heading(m) - if FloatType == "Float64" - heading = m.modelName * " (" * algorithmName * ")" - else - heading = m.modelName * " (" * algorithmName * ", " * FloatType * ")" - end - return heading -end - - - -# For backwards compatibility - -""" - signal = get_result(instantiatedModel, name; unit=true) - dataFrame = get_result(instantiatedModel; onlyStates=false, extraNames=missing) - -- First form: After a successful simulation of `instantiatedModel`, return - the result for the signal `name::String` as vector of points - together with its unit. The time vector has path name `"time"`. - If `unit=false`, the signal is returned, **without unit**. - -- Second form: Return the **complete result** in form of a DataFrame object. - Therefore, the whole functionality of package [DataFrames](https://dataframes.juliadata.org/stable/) - can be used, including storing the result on file in different formats. - Furthermore, also plot can be used on dataFrame. - Parameters and zero-value variables are stored as ModiaResult.OneValueVector inside dataFrame - (are treated as vectors, but actually only the value and the number - of time points is stored). If `onlyStates=true`, then only the states and the signals - identified with `extraNames::Vector{String}` are stored in `dataFrame`. - If `onlyStates=false` and `extraNames` given, then only the signals - identified with `extraNames` are stored in `dataFrame`. - These keyword arguments are useful, if `dataFrame` shall be - utilized as reference result used in compareResults(..). - -In both cases, a **view** on the internal result memory is provided -(so result data is not copied). - -# Example - -```julia -using Modia -@usingModiaPlot -using Unitful - -include("\$(Modia.path)/examples/Pendulum.jl") -using .Model_Pendulum - -pendulum = simulationModel(Pendulum) -simulate!(pendulum, stopTime=7.0) - -# Get one signal from the result and plot with the desired plot package -time = get_result(pendulum, "time") # vector with unit u"s" -phi = get_result(pendulum, "phi") # vector with unit u"rad" - -import PyPlot -PyPlot.figure(4) # Change to figure 4 (or create it, if it does not exist) -PyPlot.clf() # Clear current figure -PyPlot.plot(stripUnit(time), stripUnit(phi), "b--", label="phi in " * string(unit(phi[1]))) -PyPlot.xlabel("time in " * string(unit(time[1]))) -PyPlot.legend() - -# Get complete result and plot one signal -result = get_result(pendulum) -plot(result, "phi") - -# Get only states to be used as reference and compare result with reference -reference = get_result(pendulum, onlyStates=true) -(success, diff, diff_names, max_error, within_tolerance) = - ModiaResult.compareResults(result, reference, tolerance=0.01) -println("Check results: success = $success") -``` -""" -function get_result(m::SimulationModel, name::AbstractString; unit=true) - #(xsig, xsigLegend, ysig, ysigLegend, yIsConstant) = ModiaResult.getPlotSignal(m, "time", name) - - #resIndex = m.variables[name] - #ysig = ResultView(m.result, abs(resIndex), resIndex < 0) - - #if ModiaResult.timeSignalName(m) != 1 - if length(m.result.t) > 1 - error("Error in Modia.get_result(\"$name\"), because function cannot be used for a segmented simulation with more as one segment.") - end - - (tsig2, ysig2, ysigType) = ModiaResult.rawSignal(m, name) - ysig = ysig2[1] - ysig = unit ? ysig : stripUnit.(ysig) - - #= - if yIsConstant - if ndims(ysig) == 1 - ysig = fill(ysig[1], length(xsig)) - else - ysig = fill(ysig[1,:], length(xsig)) - end - end - =# - - return ysig -end - - -function setEvaluatedParametersInDataFrame!(obj::OrderedDict{Symbol,Any}, result_info, dataFrame::DataFrames.DataFrame, path::String, nResult::Int)::Nothing - for (key,value) in zip(keys(obj), obj) - name = appendName(path, key) - if typeof(value) <: OrderedDict{Symbol,Any} - setEvaluatedParametersInDataFrame!(value, result_info, dataFrame, name, nResult) - elseif !haskey(result_info, name) - dataFrame[!,name] = ModiaResult.OneValueVector(value,nResult) - end - end - return nothing -end - - -function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) - if length(m.result.t) > 1 - error("Error in Modia.get_result(...), because function cannot be used for a segmented simulation with more as one segment.") - end - - dataFrame = DataFrames.DataFrame() - - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, "time") - dataFrame[!,"time"] = timeSignal[1] - - if onlyStates || !ismissing(extraNames) - if onlyStates - for name in keys(m.equationInfo.x_dict) - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) - dataFrame[!,name] = signal[1] - end - end - if !ismissing(extraNames) - for name in extraNames - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) - dataFrame[!,name] = signal[1] - end - end - - else - for name in keys(m.result.info) - if name != "time" - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) - dataFrame[!,name] = signal[1] - end - end - - setEvaluatedParametersInDataFrame!(m.evaluatedParameters, m.result.info, dataFrame, "", length(timeSignal[1])) - end - return dataFrame -end \ No newline at end of file diff --git a/test/TestFilterCircuit.jl b/test/TestFilterCircuit.jl index 95929cc..fdf4172 100644 --- a/test/TestFilterCircuit.jl +++ b/test/TestFilterCircuit.jl @@ -24,7 +24,7 @@ filterCircuit = @instantiateModel(FilterCircuit) simulate!(filterCircuit, Tsit5(), stopTime = 10, merge = Map(R = Map(R = 5u"Ω"), C = Map(v = 3.0u"V")), logParameters = true, logStates = true, requiredFinalStates = [7.424843902110655]) -Modia.printResultInfo(filterCircuit) +Modia.showResultInfo(filterCircuit) # Test access functions @testset "Test variable access functions (TestFilterCircuit.jl)" begin currentNames = signalNames(filterCircuit) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index d662e17..454d6c3 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -205,7 +205,7 @@ SSTest = Model( ssTest = @instantiateModel(SSTest, logCode=true) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, requiredFinalStates = [1.987867388853733]) -Modia.printResultInfo(ssTest) +Modia.showResultInfo(ssTest) plot(ssTest, ("ss.x", "ss.u","ss.w", "y"), figure=1) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, @@ -219,7 +219,7 @@ simulate!(ssTest, stopTime=1.0, log=false, logStates=true, 0.9 1.0], x_init=[0.3,0.4])), # two states requiredFinalStates = [1.98786636233743, 1.9892145443000466]) -Modia.printResultInfo(ssTest) +Modia.showResultInfo(ssTest) plot(ssTest, ("ss.x", "ss.u", "y", "ss.w"), figure=2) @@ -247,7 +247,7 @@ SSTest2 = Model( ) ssTest2 = @instantiateModel(SSTest2, logCode=false) simulate!(ssTest2, stopTime=1.0, log=true, logStates=true) -printResultInfo(ssTest2) +showResultInfo(ssTest2) plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), ("submodel.ss.u", "ss.u", "y1", "y2", "submodel.ss.w"), @@ -264,7 +264,7 @@ simulate!(ssTest2, stopTime=1.0, log=false, logStates=true, C=[0.5 0.5 0.5;], x_init=[0.35,0.45,0.55])) ) -printResultInfo(ssTest2) +showResultInfo(ssTest2) println("\n... Check functions for parameters and signals") showParameters( ssTest2) diff --git a/test/TestMultiReturningFunction10.jl b/test/TestMultiReturningFunction10.jl index 77ed2a6..6c1d249 100644 --- a/test/TestMultiReturningFunction10.jl +++ b/test/TestMultiReturningFunction10.jl @@ -98,7 +98,7 @@ Pendulum = MyModelWithBuild(_buildOption = "MyBuildOption", pendulum = @instantiateModel(Pendulum , unitless=true, log=false, logDetails=false, logCode=true, logStateSelection=false) simulate!(pendulum, stopTime = 2.0, log=true) -printResultInfo(pendulum) +showResultInfo(pendulum) plot(pendulum, [("phi1", "w1"), "der(w1)", "qdd"]) diff --git a/test/TestPathPlanning.jl b/test/TestPathPlanning.jl index 50479e7..f68a21a 100644 --- a/test/TestPathPlanning.jl +++ b/test/TestPathPlanning.jl @@ -15,7 +15,7 @@ const ptp_path = PTP_path(["angle1", "angle2", "angle3"], angles = zeros(3) getPosition!(ptp_path, 0.5, angles) # angles = [0.12, 2.24, 3.24] path = getPath(ptp_path) -printResultInfo(path) +showResultInfo(path) plot(path, [("angle1", "angle2", "angle3"), ("der(angle1)", "der(angle2)", "der(angle3)"), @@ -38,7 +38,7 @@ const ptp_path2 = PTP_path{Measurement{Float64}}( angles = zeros(Measurement{Float64}, 3) getPosition!(ptp_path2, nom(0.5), angles) # angles = [0.12, 2.24, 3.24] path2 = getPath(ptp_path2) -printResultInfo(path2) +showResultInfo(path2) plot(path2, [("angle1", "angle2", "angle3"), ("der(angle1)", "der(angle2)", "der(angle3)"), diff --git a/test/TestSignals.jl b/test/TestSignals.jl new file mode 100644 index 0000000..2361ff4 --- /dev/null +++ b/test/TestSignals.jl @@ -0,0 +1,188 @@ +module TestSignals + +using Modia +using Modia: ValuesID +using Modia.Test + +const log = false + +if log + println("\nIndependent Variable") +end +t1 = [0.0, 1.0, 2.0, 3.0] +t2 = [3.0, 4.0, 5.0, 6.0, 7.0] +t3 = [7.0, 8.0, 9.0] +t = [t1, t2, t3] +sig = Modia.signal(t, t, ValuesID[ValuesID(1, ())], true, log=log, name="t") +@test typeof(sig) == Vector{Float64} +@test sig == [0.0, 1.0, 2.0, 3.0, 3.0, 4.0, 5.0, 6.0, 7.0, 7.0, 8.0, 9.0] + + +if log + println("\nInvariant tuple variable: Scalar") +end +ts1 = [(false, 1.0, true), + (false, 2.0, true), + (false, 3.0, true), + (false, 4.0, true)] +ts2 = [(false, 5.0, true), + (false, 6.0, true), + (false, 7.0, true), + (false, 8.0, true), + (false, 9.0, true)] +ts3 = [(false, 10.0, true), + (false, 11.0, true), + (false, 12.0, true)] +ts = [ts1, ts2, ts3] +sig = Modia.signal(t, ts, ValuesID[ValuesID(2, missing)], false, log=log, name="ts") +@test typeof(sig) == Vector{Float64} +@test sig == [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0] + + +if log + println("\nSegmented tuple variable: Scalar") +end +ts_segmented = [ts1, ts3] +sig = Modia.signal(t, ts_segmented, ValuesID[ValuesID(1, 2, missing), + ValuesID(3, 2, missing)], false, log=log, name="ts_segmented") +# sig = [1.0, 2.0, 3.0, 4.0, missing, missing, missing, missing, missing, 10.0, 11.0, 12.0] +@test typeof(sig) == Vector{Union{Missing, Float64}} +@test ismissing.(sig) == Bool[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0] + + +if log + println("\nInvariant tuple variable: Vector") +end +tv1 = [(false, [ 1.1, 1.2, 1.3], true), + (false, [ 2.1, 2.2, 2.3], true), + (false, [ 3.1, 3.2, 3.3], true), + (false, [ 4.1, 4.2, 4.3], true)] +tv2 = [(false, [ 5.1, 5.2, 5.3], true), + (false, [ 6.1, 6.2, 6.3], true), + (false, [ 7.1, 7.2, 7.3], true), + (false, [ 8.1, 8.2, 8.3], true), + (false, [ 9.1, 9.2, 9.3], true)] +tv3 = [(false, [10.1, 10.2, 10.3], true), + (false, [11.1, 11.2, 11.3], true), + (false, [12.1, 12.2, 12.3], true)] +tv = [tv1, tv2, tv3] +sig = Modia.signal(t, tv, ValuesID[ValuesID(2, missing)], false, log=log, name="tv") +@test typeof(sig) == Matrix{Float64} +@test sig == [1.1 1.2 1.3; 2.1 2.2 2.3; 3.1 3.2 3.3; 4.1 4.2 4.3; 5.1 5.2 5.3; 6.1 6.2 6.3; 7.1 7.2 7.3; 8.1 8.2 8.3; 9.1 9.2 9.3; 10.1 10.2 10.3; 11.1 11.2 11.3; 12.1 12.2 12.3] + + +if log + println("\nSegmented tuple variable: Vector") +end +tv_segmented = [tv1, tv3] +sig = Modia.signal(t, tv_segmented, ValuesID[ValuesID(1, 2, missing), + ValuesID(3, 2, missing)], false, log=log, name="tv_segmented") +# sig = [1.1 1.2 1.3; 2.1 2.2 2.3; 3.1 3.2 3.3; 4.1 4.2 4.3; missing missing missing; missing missing missing; missing missing missing; missing missing missing; missing missing missing; 10.0 missing missing; 11.0 missing missing; 12.0 missing missing] +@test typeof(sig) == Matrix{Union{Missing, Float64}} +@test ismissing.(sig) == Bool[0 0 0; 0 0 0; 0 0 0; 0 0 0; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 0 0 0; 0 0 0; 0 0 0] + + +if log + println("\nSegmented tuple variable: Varying Size Vectors") +end +tsv1 = [(false, [ 1.1, 1.2, 1.3], true), + (false, [ 2.1, 2.2, 2.3], true), + (false, [ 3.1, 3.2, 3.3], true), + (false, [ 4.1, 4.2, 4.3], true)] +tsv3 = [(false, [10.0], true), + (false, [11.0], true), + (false, [12.0], true)] +tsv = [tsv1, tsv3] +sig = Modia.signal(t, tsv, ValuesID[ValuesID(1, 2, missing), + ValuesID(3, 2, missing)], false, log=log, name="tsv") +# sig = [1.1 1.2 1.3; 2.1 2.2 2.3; 3.1 3.2 3.3; 4.1 4.2 4.3; missing missing missing; missing missing missing; missing missing missing; missing missing missing; missing missing missing; 10.0 missing missing; 11.0 missing missing; 12.0 missing missing] +@test typeof(sig) == Matrix{Union{Missing, Float64}} +@test ismissing.(sig) == Bool[0 0 0; 0 0 0; 0 0 0; 0 0 0; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 0 1 1; 0 1 1; 0 1 1] + + +if log + println("\nInvariant vector variable: Scalar") +end +v1 = [[-1.0, 1.11, 1.21, 1.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 2.11, 2.21, 2.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 3.11, 3.21, 3.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 4.11, 4.21, 4.31, 1.12, 1.22, 1.32, -2.0]] +v2 = [[-1.0, 5.11, 5.21, 5.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 6.11, 6.21, 6.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 7.11, 7.21, 7.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 8.11, 8.21, 8.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 9.11, 9.21, 9.31, 1.12, 1.22, 1.32, -2.0]] +v3 = [[-1.0, 10.11, 10.21, 10.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 11.11, 11.21, 11.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 12.11, 12.21, 12.31, 1.12, 1.22, 1.32, -2.0]] +v = [v1, v2, v3] +sig = Modia.signal(t, v, ValuesID[ValuesID(2, ())], true, log=log, name="v") +@test typeof(sig) == Vector{Float64} +@test sig == [1.11, 2.11, 3.11, 4.11, 5.11, 6.11, 7.11, 8.11, 9.11, 10.11, 11.11, 12.11] + + +if log + println("\nInvariant vector variable: Vector") +end +sig = Modia.signal(t, v, ValuesID[ValuesID(2, (3,))], true, log=log, name="v") +@test typeof(sig) == Matrix{Float64} +@test sig == [1.11 1.21 1.31; 2.11 2.21 2.31; 3.11 3.21 3.31; 4.11 4.21 4.31; 5.11 5.21 5.31; 6.11 6.21 6.31; 7.11 7.21 7.31; 8.11 8.21 8.31; 9.11 9.21 9.31; 10.11 10.21 10.31; 11.11 11.21 11.31; 12.11 12.21 12.31] + + +if log + println("\nInvariant vector variable: Matrix") +end +sig = Modia.signal(t, v, ValuesID[ValuesID(2, (3,2))], true, log=log, name="v") +@test typeof(sig) == Array{Float64, 3} +@test sig == [1.11 1.21 1.31; 2.11 2.21 2.31; 3.11 3.21 3.31; 4.11 4.21 4.31; 5.11 5.21 5.31; 6.11 6.21 6.31; 7.11 7.21 7.31; 8.11 8.21 8.31; 9.11 9.21 9.31; 10.11 10.21 10.31; 11.11 11.21 11.31; 12.11 12.21 12.31;;; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32] + + +if log + println("\nSegmented vector variable: Scalar") +end +v_segmented = [v1, v3] +sig = Modia.signal(t, v_segmented, ValuesID[ValuesID(1, 2, ()), + ValuesID(3, 2, ())], true, log=log, name="v_segmented") +# sig = [1.11 1.21 1.31; 2.11 2.21 2.31; 3.11 3.21 3.31; 4.11 4.21 4.31; missing missing missing; missing missing missing; missing missing missing; missing missing missing; missing missing missing; 10.11 10.21 10.31; 11.11 11.21 11.31; 12.11 12.21 12.31] +@test typeof(sig) == Vector{Union{Missing, Float64}} +@test ismissing.(sig) == Bool[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0] + + +if log + println("\nSegmented vector variable: Vector") +end +sig = Modia.signal(t, v_segmented, ValuesID[ValuesID(1, 2, (3,)), + ValuesID(3, 2, (3,))], true, log=log, name="v_segmented") +# sig = [1.11 1.21 1.31; 2.11 2.21 2.31; 3.11 3.21 3.31; 4.11 4.21 4.31; missing missing missing; missing missing missing; missing missing missing; missing missing missing; missing missing missing; 10.11 10.21 10.31; 11.11 11.21 11.31; 12.11 12.21 12.31] +@test typeof(sig) == Matrix{Union{Missing, Float64}} +@test ismissing.(sig) == Bool[0 0 0; 0 0 0; 0 0 0; 0 0 0; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 0 0 0; 0 0 0; 0 0 0] + + +if log + println("\nSegmented vector variable: Matrix") +end +sig = Modia.signal(t, v_segmented, ValuesID[ValuesID(1, 2, (3,2)), + ValuesID(3, 2, (3,2))], true, log=log, name="v_segmented") +# sig = [1.11 1.21 1.31; 2.11 2.21 2.31; 3.11 3.21 3.31; 4.11 4.21 4.31; missing missing missing; missing missing missing; missing missing missing; missing missing missing; missing missing missing; 10.11 10.21 10.31; 11.11 11.21 11.31; 12.11 12.21 12.31;;; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32; missing missing missing; missing missing missing; missing missing missing; missing missing missing; missing missing missing; 1.12 1.22 1.32; 1.12 1.22 1.32; 1.12 1.22 1.32] +@test typeof(sig) == Array{Union{Missing, Float64}, 3} +@test ismissing.(sig) == Bool[0 0 0; 0 0 0; 0 0 0; 0 0 0; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 0 0 0; 0 0 0; 0 0 0;;; 0 0 0; 0 0 0; 0 0 0; 0 0 0; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 0 0 0; 0 0 0; 0 0 0] + + +if log + println("\nSegmented vector variable: Varying Size Vectors") +end +vv1 = [[-1.0, 1.11, 1.21, 1.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 2.11, 2.21, 2.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 3.11, 3.21, 3.31, 1.12, 1.22, 1.32, -2.0], + [-1.0, 4.11, 4.21, 4.31, 1.12, 1.22, 1.32, -2.0]] +vv3 = [[-1.0, -3.0, 10.11, -2.0], + [-1.0, -3.0, 11.11, -2.0], + [-1.0, -3.0, 12.11, -2.0]] +vv = [vv1, vv3] +sig = Modia.signal(t, vv, ValuesID[ValuesID(1, 2, (3,)), + ValuesID(3, 3, (1,))], true, log=log, name="vv") +# sig = [1.11 1.21 1.31; 2.11 2.21 2.31; 3.11 3.21 3.31; 4.11 4.21 4.31; missing missing missing; missing missing missing; missing missing missing; missing missing missing; missing missing missing; 10.11 missing missing; 11.11 missing missing; 12.11 missing missing] +@test typeof(sig) == Matrix{Union{Missing, Float64}} +@test ismissing.(sig) == Bool[0 0 0; 0 0 0; 0 0 0; 0 0 0; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 1 1 1; 0 1 1; 0 1 1; 0 1 1] + +end \ No newline at end of file From b1ea9fdc2c97c5d063df3eb85a6135f2b27d24dd Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 24 Jun 2022 20:24:00 +0200 Subject: [PATCH 34/63] Fix issues to get a running Modia version with NoPlot --- Manifest.toml | 407 ++++++++++++++++++++++-------------------- Project.toml | 5 +- src/CodeGeneration.jl | 8 +- src/Result.jl | 14 +- 4 files changed, 233 insertions(+), 201 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 8d14d26..eafa6b4 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -19,51 +19,75 @@ uuid = "ec485272-7323-5ecc-a04f-4719b315124d" version = "0.2.0" [[deps.ArrayInterface]] -deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"] -git-tree-sha1 = "1ee88c4c76caa995a885dc2f22a5d548dfbbc0ba" +deps = ["ArrayInterfaceCore", "Compat", "IfElse", "LinearAlgebra", "Static"] +git-tree-sha1 = "d956c0606a3bc1112a1f99a8b2309b79558d9921" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "3.2.2" +version = "6.0.17" + +[[deps.ArrayInterfaceCore]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "5e732808bcf7bbf730e810a9eaafc52705b38bb5" +uuid = "30b0a656-2188-435a-8636-2ec0e6a096e2" +version = "0.1.13" + +[[deps.ArrayInterfaceGPUArrays]] +deps = ["Adapt", "ArrayInterfaceCore", "GPUArraysCore", "LinearAlgebra"] +git-tree-sha1 = "02ec61006f49c43607a34cbd036b3d68485d38aa" +uuid = "6ba088a2-8465-4c0a-af30-387133b534db" +version = "0.2.0" + +[[deps.ArrayInterfaceOffsetArrays]] +deps = ["ArrayInterface", "OffsetArrays", "Static"] +git-tree-sha1 = "7dce0e2846e7496622f5d2742502d7e029693458" +uuid = "015c0d05-e682-4f19-8f0a-679ce4c54826" +version = "0.1.5" + +[[deps.ArrayInterfaceStaticArrays]] +deps = ["Adapt", "ArrayInterface", "LinearAlgebra", "Static", "StaticArrays"] +git-tree-sha1 = "d7dc30474e73173a990eca86af76cae8790fa9f2" +uuid = "b0d46f97-bff5-4637-a19a-dd75974142cd" +version = "0.1.2" [[deps.ArrayLayouts]] deps = ["FillArrays", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "56c347caf09ad8acb3e261fe75f8e09652b7b05b" +git-tree-sha1 = "26c659b14c4dc109b6b9c3398e4455eebc523814" uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" -version = "0.7.10" +version = "0.8.8" [[deps.Artifacts]] uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [[deps.BandedMatrices]] deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "Random", "SparseArrays"] -git-tree-sha1 = "ce68f8c2162062733f9b4c9e3700d5efc4a8ec47" +git-tree-sha1 = "13223ec65172b18f164e8a8338e4e95d40d54c8c" uuid = "aae01518-5342-5314-be14-df237901396f" -version = "0.16.11" +version = "0.17.2" [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" [[deps.BitTwiddlingConvenienceFunctions]] deps = ["Static"] -git-tree-sha1 = "28bbdbf0354959db89358d1d79d421ff31ef0b5e" +git-tree-sha1 = "eaee37f76339077f86679787a71990c4e465477f" uuid = "62783981-4cbd-42fc-bca8-16325de8dc4b" -version = "0.1.3" +version = "0.1.4" [[deps.BoundaryValueDiffEq]] deps = ["BandedMatrices", "DiffEqBase", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "NLsolve", "Reexport", "SparseArrays"] -git-tree-sha1 = "fe34902ac0c3a35d016617ab7032742865756d7d" +git-tree-sha1 = "d6a331230022493b704e1d5c11f928e2cce2d058" uuid = "764a87c0-6b3e-53db-9096-fe964310641d" -version = "2.7.1" +version = "2.8.0" [[deps.CEnum]] -git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9" +git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" -version = "0.4.1" +version = "0.4.2" [[deps.CPUSummary]] -deps = ["Hwloc", "IfElse", "Preferences", "Static"] -git-tree-sha1 = "2283583c451e880ec11c7fd693613434fb5ffa74" +deps = ["CpuId", "IfElse", "Static"] +git-tree-sha1 = "b1a532a582dd18b34543366322d390e1560d40a9" uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" -version = "0.1.12" +version = "0.1.23" [[deps.Calculus]] deps = ["LinearAlgebra"] @@ -73,26 +97,26 @@ version = "0.5.1" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "c9a6160317d1abe9c44b3beb367fd448117679ca" +git-tree-sha1 = "9489214b993cd42d17f44c36e359bf6a7c919abf" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.13.0" +version = "1.15.0" [[deps.ChangesOfVariables]] deps = ["ChainRulesCore", "LinearAlgebra", "Test"] -git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1" +git-tree-sha1 = "1e315e3f4b0b7ce40feded39c73049692126cf53" uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" -version = "0.1.2" +version = "0.1.3" [[deps.CloseOpenIntervals]] deps = ["ArrayInterface", "Static"] -git-tree-sha1 = "f576084239e6bdf801007c80e27e2cc2cd963fe0" +git-tree-sha1 = "5522c338564580adf5d58d91e43a55db0fa5fb39" uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9" -version = "0.1.6" +version = "0.1.10" [[deps.CommonSolve]] -git-tree-sha1 = "68a0743f578349ada8bc911a5cbd5a2ef6ed6d1f" +git-tree-sha1 = "332a332c97c7071600984b3c31d9067e1a4e6e25" uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" -version = "0.2.0" +version = "0.2.1" [[deps.CommonSubexpressions]] deps = ["MacroTools", "Test"] @@ -102,9 +126,9 @@ version = "0.3.0" [[deps.Compat]] deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "44c37b4636bc54afac5c574d2d02b625349d6582" +git-tree-sha1 = "9be8be1d8a6f44b96482c8af52238ea7987da3e3" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.41.0" +version = "3.45.0" [[deps.CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] @@ -116,33 +140,33 @@ git-tree-sha1 = "f74e9d5388b8620b4cee35d4c5a618dd4dc547f4" uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" version = "1.3.0" +[[deps.CpuId]] +deps = ["Markdown"] +git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" +uuid = "adafc99b-e345-5852-983c-f28acb93d879" +version = "0.3.1" + [[deps.Crayons]] git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" version = "4.1.1" -[[deps.DEDataArrays]] -deps = ["ArrayInterface", "DocStringExtensions", "LinearAlgebra", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] -git-tree-sha1 = "5e5f8f363c8c9a2415ef9185c4e0ff6966c87d52" -uuid = "754358af-613d-5f8d-9788-280bf1605d4c" -version = "0.2.2" - [[deps.DataAPI]] -git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8" +git-tree-sha1 = "fb5f5316dd3fd4c5e7c30a24d50643b73e37cd40" uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" -version = "1.9.0" +version = "1.10.0" [[deps.DataFrames]] deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Reexport", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] -git-tree-sha1 = "ae02104e835f219b8930c7664b8012c93475c340" +git-tree-sha1 = "daa21eb85147f72e41f6352a57fccea377e310a9" uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -version = "1.3.2" +version = "1.3.4" [[deps.DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "3daef5523dd2e769dad2365274f760ff5f282c7d" +git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.11" +version = "0.18.13" [[deps.DataValueInterfaces]] git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" @@ -154,10 +178,10 @@ deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[deps.DelayDiffEq]] -deps = ["ArrayInterface", "DataStructures", "DiffEqBase", "LinearAlgebra", "Logging", "NonlinearSolve", "OrdinaryDiffEq", "Printf", "RecursiveArrayTools", "Reexport", "UnPack"] -git-tree-sha1 = "9b50344853bd81a1a22bfe290781d538f4790244" +deps = ["ArrayInterface", "DataStructures", "DiffEqBase", "LinearAlgebra", "Logging", "NonlinearSolve", "OrdinaryDiffEq", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "UnPack"] +git-tree-sha1 = "078f21d61a6f43a7b3eab4620ac958183e44cee2" uuid = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" -version = "5.35.0" +version = "5.37.0" [[deps.DelimitedFiles]] deps = ["Mmap"] @@ -170,28 +194,28 @@ uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" version = "0.4.0" [[deps.DiffEqBase]] -deps = ["ArrayInterface", "ChainRulesCore", "DEDataArrays", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "IterativeSolvers", "LabelledArrays", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "PreallocationTools", "Printf", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "SuiteSparse", "ZygoteRules"] -git-tree-sha1 = "0dee26eff5f7a4ab0381f43281c9734354ddc93d" +deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "ZygoteRules"] +git-tree-sha1 = "528d97ef168b36e1a90d667e6611be24759aa1ba" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.82.0" +version = "6.90.0" [[deps.DiffEqCallbacks]] -deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "OrdinaryDiffEq", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] -git-tree-sha1 = "c4b99e3a199e293e7290eea94ba89364d47ee557" +deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] +git-tree-sha1 = "cfef2afe8d73ed2d036b0e4b14a3f9b53045c534" uuid = "459566f4-90b8-5000-8ac3-15dfb0a30def" -version = "2.22.0" +version = "2.23.1" [[deps.DiffEqJump]] -deps = ["ArrayInterface", "Compat", "DataStructures", "DiffEqBase", "FunctionWrappers", "Graphs", "LinearAlgebra", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "StaticArrays", "TreeViews", "UnPack"] -git-tree-sha1 = "eec5fd03c26dadc6b20f84d815309d060358e95b" +deps = ["ArrayInterfaceCore", "DataStructures", "DiffEqBase", "DocStringExtensions", "FunctionWrappers", "Graphs", "LinearAlgebra", "Markdown", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "StaticArrays", "TreeViews", "UnPack"] +git-tree-sha1 = "760a048fc34902bfd1b1e4ac4b67162da1f74972" uuid = "c894b116-72e5-5b58-be3c-e6d8d4ac2b12" -version = "8.3.0" +version = "8.6.2" [[deps.DiffEqNoiseProcess]] -deps = ["DiffEqBase", "Distributions", "LinearAlgebra", "Optim", "PoissonRandom", "QuadGK", "Random", "Random123", "RandomNumbers", "RecipesBase", "RecursiveArrayTools", "Requires", "ResettableStacks", "SciMLBase", "StaticArrays", "Statistics"] -git-tree-sha1 = "d6839a44a268c69ef0ed927b22a6f43c8a4c2e73" +deps = ["DiffEqBase", "Distributions", "GPUArraysCore", "LinearAlgebra", "Markdown", "Optim", "PoissonRandom", "QuadGK", "Random", "Random123", "RandomNumbers", "RecipesBase", "RecursiveArrayTools", "ResettableStacks", "SciMLBase", "StaticArrays", "Statistics"] +git-tree-sha1 = "6f3fe6ebe1b6e6e3a9b72739ada313aa17c9bb66" uuid = "77a26b50-5914-5dd7-bc55-306e6241c503" -version = "5.9.0" +version = "5.12.0" [[deps.DiffResults]] deps = ["StaticArrays"] @@ -201,9 +225,9 @@ version = "1.0.3" [[deps.DiffRules]] deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] -git-tree-sha1 = "dd933c4ef7b4c270aacd4eb88fa64c147492acf0" +git-tree-sha1 = "28d605d9a0ac17118fe2c5e9ce0fbb76c3ceb120" uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" -version = "1.10.0" +version = "1.11.0" [[deps.DifferentialEquations]] deps = ["BoundaryValueDiffEq", "DelayDiffEq", "DiffEqBase", "DiffEqCallbacks", "DiffEqJump", "DiffEqNoiseProcess", "LinearAlgebra", "LinearSolve", "OrdinaryDiffEq", "Random", "RecursiveArrayTools", "Reexport", "SteadyStateDiffEq", "StochasticDiffEq", "Sundials"] @@ -223,9 +247,9 @@ uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" [[deps.Distributions]] deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] -git-tree-sha1 = "9d3c0c762d4666db9187f363a76b47f7346e673b" +git-tree-sha1 = "0ec161f87bf4ab164ff96dfacf4be8ffff2375fd" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.49" +version = "0.25.62" [[deps.DocStringExtensions]] deps = ["LibGit2"] @@ -239,15 +263,15 @@ uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" [[deps.DualNumbers]] deps = ["Calculus", "NaNMath", "SpecialFunctions"] -git-tree-sha1 = "90b158083179a6ccbce2c7eb1446d5bf9d7ae571" +git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" -version = "0.6.7" +version = "0.6.8" [[deps.ExponentialUtilities]] -deps = ["ArrayInterface", "LinearAlgebra", "Printf", "Requires", "SparseArrays", "libblastrampoline_jll"] -git-tree-sha1 = "b026981973ccbe38682fbb4ccb0732fd6b1e1207" +deps = ["ArrayInterfaceCore", "GPUArraysCore", "GenericSchur", "LinearAlgebra", "Printf", "SparseArrays", "libblastrampoline_jll"] +git-tree-sha1 = "b40c9037e1a33990466bc5d224ced34b34eebdb0" uuid = "d4d017d3-3776-5f7e-afef-a10c40355c18" -version = "1.13.0" +version = "1.18.0" [[deps.ExprTools]] git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" @@ -255,10 +279,10 @@ uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" version = "0.1.8" [[deps.FastBroadcast]] -deps = ["LinearAlgebra", "Polyester", "Static"] -git-tree-sha1 = "f39bcc05eb0dcbd2c0195762df7a5737041289b9" +deps = ["ArrayInterface", "ArrayInterfaceCore", "LinearAlgebra", "Polyester", "Static", "StrideArraysCore"] +git-tree-sha1 = "81765322b2960b7c92f9280b00956cb8d645d3f7" uuid = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -version = "0.1.14" +version = "0.2.0" [[deps.FastClosures]] git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" @@ -267,15 +291,15 @@ version = "0.3.2" [[deps.FillArrays]] deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] -git-tree-sha1 = "deed294cde3de20ae0b2e0355a6c4e1c6a5ceffc" +git-tree-sha1 = "246621d23d1f43e3b9c368bf3b72b2331a27c286" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "0.12.8" +version = "0.13.2" [[deps.FiniteDiff]] -deps = ["ArrayInterface", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"] -git-tree-sha1 = "56956d1e4c1221000b7781104c58c34019792951" +deps = ["ArrayInterfaceCore", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"] +git-tree-sha1 = "ee13c773ce60d9e95a6c6ea134f25605dce2eda3" uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.11.0" +version = "2.13.0" [[deps.Formatting]] deps = ["Printf"] @@ -285,9 +309,9 @@ version = "0.4.2" [[deps.ForwardDiff]] deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] -git-tree-sha1 = "1bd6fc0c344fc0cbee1f42f8d2e7ec8253dda2d2" +git-tree-sha1 = "2f18915445b248731ec5db4e4a17e451020bf21e" uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "0.10.25" +version = "0.10.30" [[deps.FunctionWrappers]] git-tree-sha1 = "241552bc2209f0fa068b6415b1942cc0aa486bcc" @@ -298,35 +322,35 @@ version = "1.1.2" deps = ["Random"] uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" +[[deps.GPUArraysCore]] +deps = ["Adapt"] +git-tree-sha1 = "4078d3557ab15dd9fe6a0cf6f65e3d4937e98427" +uuid = "46192b85-c4d5-4398-a991-12ede77f4527" +version = "0.1.0" + +[[deps.GenericSchur]] +deps = ["LinearAlgebra", "Printf"] +git-tree-sha1 = "fb69b2a645fa69ba5f474af09221b9308b160ce6" +uuid = "c145ed77-6b09-5dd9-b285-bf645a82121e" +version = "0.5.3" + [[deps.Graphs]] deps = ["ArnoldiMethod", "Compat", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] -git-tree-sha1 = "57c021de207e234108a6f1454003120a1bf350c4" +git-tree-sha1 = "db5c7e27c0d46fd824d470a3c32a4fc6c935fa96" uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" -version = "1.6.0" +version = "1.7.1" [[deps.HostCPUFeatures]] deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"] -git-tree-sha1 = "18be5268cf415b5e27f34980ed25a7d34261aa83" +git-tree-sha1 = "b7b88a4716ac33fe31d6556c02fc60017594343c" uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0" -version = "0.1.7" - -[[deps.Hwloc]] -deps = ["Hwloc_jll"] -git-tree-sha1 = "92d99146066c5c6888d5a3abc871e6a214388b91" -uuid = "0e44f5e4-bd66-52a0-8798-143a42290a1d" -version = "2.0.0" - -[[deps.Hwloc_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "d8bccde6fc8300703673ef9e1383b11403ac1313" -uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8" -version = "2.7.0+0" +version = "0.1.8" [[deps.HypergeometricFunctions]] deps = ["DualNumbers", "LinearAlgebra", "SpecialFunctions", "Test"] -git-tree-sha1 = "65e4589030ef3c44d3b90bdc5aac462b4bb05567" +git-tree-sha1 = "cb7099a0109939f16a4d3b572ba8396b1f6c7c31" uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" -version = "0.3.8" +version = "0.3.10" [[deps.IfElse]] git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" @@ -344,9 +368,9 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[deps.InverseFunctions]] deps = ["Test"] -git-tree-sha1 = "a7254c0acd8e62f1ac75ad24d5db43f5f19f3c65" +git-tree-sha1 = "b3364212fb5d870f724876ffcd34dd8ec6d98918" uuid = "3587e190-3f89-42d0-90ee-14403ec27112" -version = "0.1.2" +version = "0.1.7" [[deps.InvertedIndices]] git-tree-sha1 = "bee5f1ef5bf65df56bdd2e40447590b272a5471f" @@ -389,27 +413,27 @@ version = "0.3.0" [[deps.Krylov]] deps = ["LinearAlgebra", "Printf", "SparseArrays"] -git-tree-sha1 = "a024280a69c49f51ba29d2deb66f07508f0b9b49" +git-tree-sha1 = "7f0a89bd74c30aa7ff96c4bf1bc884c39663a621" uuid = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7" -version = "0.7.13" +version = "0.8.2" [[deps.KrylovKit]] deps = ["LinearAlgebra", "Printf"] -git-tree-sha1 = "0328ad9966ae29ccefb4e1b9bfd8c8867e4360df" +git-tree-sha1 = "49b0c1dd5c292870577b8f58c51072bd558febb9" uuid = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" -version = "0.5.3" +version = "0.5.4" [[deps.LabelledArrays]] -deps = ["ArrayInterface", "ChainRulesCore", "LinearAlgebra", "MacroTools", "StaticArrays"] -git-tree-sha1 = "fbd884a02f8bf98fd90c53c1c9d2b21f9f30f42a" +deps = ["ArrayInterface", "ArrayInterfaceStaticArrays", "ChainRulesCore", "LinearAlgebra", "MacroTools", "StaticArrays"] +git-tree-sha1 = "a63da17ff71f41a1f818e0e1d3c02a32cf4c51f7" uuid = "2ee39098-c373-598a-b85f-a56591580800" -version = "1.8.0" +version = "1.10.2" [[deps.LayoutPointers]] -deps = ["ArrayInterface", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static"] -git-tree-sha1 = "b651f573812d6c36c22c944dd66ef3ab2283dfa1" +deps = ["ArrayInterface", "ArrayInterfaceOffsetArrays", "ArrayInterfaceStaticArrays", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static"] +git-tree-sha1 = "b67e749fb35530979839e7b4b606a97105fe4f1c" uuid = "10f19ff3-798f-405d-979b-55457f8fc047" -version = "0.1.6" +version = "0.1.10" [[deps.LevyArea]] deps = ["LinearAlgebra", "Random", "SpecialFunctions"] @@ -447,25 +471,25 @@ deps = ["Libdl", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [[deps.LinearSolve]] -deps = ["ArrayInterface", "DocStringExtensions", "IterativeSolvers", "KLU", "Krylov", "KrylovKit", "LinearAlgebra", "RecursiveFactorization", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "SuiteSparse", "UnPack"] -git-tree-sha1 = "a25bc80647e44d0e1e1694b47000603497700b18" +deps = ["ArrayInterfaceCore", "DocStringExtensions", "GPUArraysCore", "IterativeSolvers", "KLU", "Krylov", "KrylovKit", "LinearAlgebra", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "SparseArrays", "SuiteSparse", "UnPack"] +git-tree-sha1 = "b3e7461184bd748e5dee98f9b11766be39634fae" uuid = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" -version = "1.13.0" +version = "1.19.0" [[deps.LogExpFunctions]] deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "e5718a00af0ab9756305a0392832c8952c7426c1" +git-tree-sha1 = "09e4b894ce6a976c354a69041a04748180d43637" uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.6" +version = "0.3.15" [[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" [[deps.LoopVectorization]] -deps = ["ArrayInterface", "CPUSummary", "ChainRulesCore", "CloseOpenIntervals", "DocStringExtensions", "ForwardDiff", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "SIMDDualNumbers", "SLEEFPirates", "SpecialFunctions", "Static", "ThreadingUtilities", "UnPack", "VectorizationBase"] -git-tree-sha1 = "077c7c9d746cbe30ac5f001ea4c1277f64cc5dad" +deps = ["ArrayInterface", "ArrayInterfaceCore", "ArrayInterfaceOffsetArrays", "ArrayInterfaceStaticArrays", "CPUSummary", "ChainRulesCore", "CloseOpenIntervals", "DocStringExtensions", "ForwardDiff", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "SIMDDualNumbers", "SIMDTypes", "SLEEFPirates", "SpecialFunctions", "Static", "ThreadingUtilities", "UnPack", "VectorizationBase"] +git-tree-sha1 = "5ea9a0aaf5ded7f0b6e43c96ca1793e60c96af93" uuid = "bdcacae8-1622-11e9-2a5c-532679323890" -version = "0.12.103" +version = "0.12.118" [[deps.MacroTools]] deps = ["Markdown", "Random"] @@ -488,9 +512,9 @@ uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" [[deps.Measurements]] deps = ["Calculus", "LinearAlgebra", "Printf", "RecipesBase", "Requires"] -git-tree-sha1 = "88cd033eb781c698e75ae0b680e5cef1553f0856" +git-tree-sha1 = "dd8b9e6d7be9731fdaecc813acc5c3083496a251" uuid = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" -version = "2.7.1" +version = "2.7.2" [[deps.Missings]] deps = ["DataAPI"] @@ -509,9 +533,9 @@ version = "0.11.0" [[deps.ModiaResult]] deps = ["DataFrames", "Measurements", "MonteCarloMeasurements", "OrderedCollections", "Pkg", "Tables", "Unitful"] -git-tree-sha1 = "8fc8801bf89b9f2efd39952386bda67b3724b0f3" +git-tree-sha1 = "02324a82efdb489c16bb6d008131a1447b125ad5" uuid = "16a87621-1533-42f6-8e19-4a825980cec2" -version = "0.4.1" +version = "0.4.3" [[deps.MonteCarloMeasurements]] deps = ["Distributed", "Distributions", "LinearAlgebra", "MacroTools", "Random", "RecipesBase", "Requires", "SLEEFPirates", "StaticArrays", "Statistics", "StatsBase", "Test"] @@ -548,16 +572,16 @@ version = "0.3.7" uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" [[deps.NonlinearSolve]] -deps = ["ArrayInterface", "FiniteDiff", "ForwardDiff", "IterativeSolvers", "LinearAlgebra", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "StaticArrays", "UnPack"] -git-tree-sha1 = "4e5ee038e5655c8aaa9ac179743c5227d1f0f0f3" +deps = ["ArrayInterfaceCore", "FiniteDiff", "ForwardDiff", "IterativeSolvers", "LinearAlgebra", "RecursiveArrayTools", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "StaticArrays", "UnPack"] +git-tree-sha1 = "8a00c7b9418270f1fa57da319d11febbe5f92101" uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" -version = "0.3.15" +version = "0.3.20" [[deps.OffsetArrays]] deps = ["Adapt"] -git-tree-sha1 = "043017e0bdeff61cfbb7afeb558ab29536bbb5ed" +git-tree-sha1 = "ec2e30596282d722f018ae784b7f44f3b88065e4" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.10.8" +version = "1.12.6" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] @@ -575,9 +599,9 @@ version = "0.5.5+0" [[deps.Optim]] deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] -git-tree-sha1 = "bc0a748740e8bc5eeb9ea6031e6f050de1fc0ba2" +git-tree-sha1 = "7a28efc8e34d5df89fc87343318b0a8add2c4021" uuid = "429524aa-4258-5aef-a3af-852621145aeb" -version = "1.6.2" +version = "1.7.0" [[deps.OrderedCollections]] git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" @@ -585,16 +609,16 @@ uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.4.1" [[deps.OrdinaryDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "d8f30cac5f1d2bf3b9c0012c2f078d850c804ef1" +deps = ["Adapt", "ArrayInterface", "ArrayInterfaceGPUArrays", "ArrayInterfaceStaticArrays", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] +git-tree-sha1 = "5a27d2c7a645935998a9851bdc45c3689e897193" uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -version = "6.7.0" +version = "6.17.0" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "7e2166042d1698b6072352c74cfd1fca2a968253" +git-tree-sha1 = "7f4869861f8dac4990d6808b66b57e5a425cfd99" uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" -version = "0.11.6" +version = "0.11.13" [[deps.Parameters]] deps = ["OrderedCollections", "UnPack"] @@ -604,37 +628,37 @@ version = "0.12.3" [[deps.Parsers]] deps = ["Dates"] -git-tree-sha1 = "85b5da0fa43588c75bb1ff986493443f821c70b7" +git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.2.3" +version = "2.3.2" [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" [[deps.PoissonRandom]] -deps = ["Random", "Statistics", "Test"] -git-tree-sha1 = "44d018211a56626288b5d3f8c6497d28c26dc850" +deps = ["Random"] +git-tree-sha1 = "9ac1bb7c15c39620685a3a7babc0651f5c64c35b" uuid = "e409e4f3-bfea-5376-8464-e040bb5c01ab" -version = "0.4.0" +version = "0.4.1" [[deps.Polyester]] deps = ["ArrayInterface", "BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "ManualMemory", "PolyesterWeave", "Requires", "Static", "StrideArraysCore", "ThreadingUtilities"] -git-tree-sha1 = "ad769d3f29cffb33380ab28318a10c1ccb19c827" +git-tree-sha1 = "bfd5fb3376bc084d202c717bbba8c94696755d87" uuid = "f517fe37-dbe3-4b94-8317-1923a5111588" -version = "0.6.7" +version = "0.6.12" [[deps.PolyesterWeave]] deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] -git-tree-sha1 = "7e597df97e46ffb1c8adbaddfa56908a7a20194b" +git-tree-sha1 = "4cd738fca4d826bef1a87cbe43196b34fa205e6d" uuid = "1d0040c9-8b98-4ee7-8388-3f51789ca0ad" -version = "0.1.5" +version = "0.1.6" [[deps.PooledArrays]] deps = ["DataAPI", "Future"] -git-tree-sha1 = "db3a23166af8aebf4db5ef87ac5b00d36eb771e2" +git-tree-sha1 = "a6062fe4063cdafe78f4a0a81cfffb89721b30e7" uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" -version = "1.4.0" +version = "1.4.2" [[deps.PositiveFactorizations]] deps = ["LinearAlgebra"] @@ -643,16 +667,16 @@ uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" version = "0.2.4" [[deps.PreallocationTools]] -deps = ["Adapt", "ArrayInterface", "ForwardDiff", "LabelledArrays"] -git-tree-sha1 = "6c138c8510111fa47b5d2ed8ada482d97e279bee" +deps = ["Adapt", "ArrayInterfaceCore", "ForwardDiff", "LabelledArrays"] +git-tree-sha1 = "77266c25ab9d48e31ef167eae936e8f6fa0e4754" uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46" -version = "0.2.4" +version = "0.3.2" [[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "de893592a221142f3db370f48290e3a2ef39998f" +git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.2.4" +version = "1.3.0" [[deps.PrettyTables]] deps = ["Crayons", "Formatting", "Markdown", "Reexport", "Tables"] @@ -696,16 +720,16 @@ uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" version = "1.2.1" [[deps.RecursiveArrayTools]] -deps = ["Adapt", "ArrayInterface", "ChainRulesCore", "DocStringExtensions", "FillArrays", "LinearAlgebra", "RecipesBase", "Requires", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "b66df9b4f668b340a6b6b8a7e667a68f586c5561" +deps = ["Adapt", "ArrayInterfaceCore", "ArrayInterfaceStaticArrays", "ChainRulesCore", "DocStringExtensions", "FillArrays", "GPUArraysCore", "LinearAlgebra", "RecipesBase", "StaticArrays", "Statistics", "ZygoteRules"] +git-tree-sha1 = "de1d261ff688a68f296185085aaecf99bc039d80" uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" -version = "2.25.0" +version = "2.30.0" [[deps.RecursiveFactorization]] deps = ["LinearAlgebra", "LoopVectorization", "Polyester", "StrideArraysCore", "TriangularSolve"] -git-tree-sha1 = "7ad4c2ef15b7aecd767b3921c0d255d39b3603ea" +git-tree-sha1 = "3ee71214057e29a8466f5d70cfe745236aa1d9d7" uuid = "f2c3362d-daeb-58d1-803e-2bc74f2840b4" -version = "0.2.9" +version = "0.2.11" [[deps.Reexport]] git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" @@ -741,9 +765,9 @@ uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" [[deps.SIMDDualNumbers]] deps = ["ForwardDiff", "IfElse", "SLEEFPirates", "VectorizationBase"] -git-tree-sha1 = "62c2da6eb66de8bb88081d20528647140d4daa0e" +git-tree-sha1 = "dd4195d308df24f33fb10dde7c22103ba88887fa" uuid = "3cdde19b-5bb0-4aaf-8931-af3e248e098b" -version = "0.1.0" +version = "0.1.1" [[deps.SIMDTypes]] git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" @@ -752,24 +776,24 @@ version = "0.1.0" [[deps.SLEEFPirates]] deps = ["IfElse", "Static", "VectorizationBase"] -git-tree-sha1 = "d4c366b135fc2e1af7a000473e08edc5afd94819" +git-tree-sha1 = "7ee0e13ac7cd77f2c0e93bff8c40c45f05c77a5a" uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" -version = "0.6.31" +version = "0.6.33" [[deps.SciMLBase]] -deps = ["ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "RecipesBase", "RecursiveArrayTools", "StaticArrays", "Statistics", "Tables", "TreeViews"] -git-tree-sha1 = "c086056df381502621dc6b5f1d1a0a1c2d0185e7" +deps = ["ArrayInterfaceCore", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "RecipesBase", "RecursiveArrayTools", "StaticArrays", "Statistics", "Tables", "TreeViews"] +git-tree-sha1 = "e74049cca1ff273cc62697dd3739f7d43e029d93" uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -version = "1.28.0" +version = "1.41.4" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [[deps.Setfield]] deps = ["ConstructionBase", "Future", "MacroTools", "Requires"] -git-tree-sha1 = "38d88503f695eb0301479bc9b0d4320b378bafe5" +git-tree-sha1 = "77172cadd2fdfa0c84c87e3a01215a4ca7723310" uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" -version = "0.8.2" +version = "1.0.0" [[deps.SharedArrays]] deps = ["Distributed", "Mmap", "Random", "Serialization"] @@ -795,28 +819,33 @@ deps = ["LinearAlgebra", "Random"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [[deps.SparseDiffTools]] -deps = ["Adapt", "ArrayInterface", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays", "VertexSafeGraphs"] -git-tree-sha1 = "87efd1676d87706f4079e8e717a7a5f02b6ea1ad" +deps = ["Adapt", "ArrayInterfaceCore", "ArrayInterfaceStaticArrays", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays", "VertexSafeGraphs"] +git-tree-sha1 = "32025c052719c6353f22f7c6de7d7b97b7cd2c88" uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804" -version = "1.20.2" +version = "1.24.0" [[deps.SpecialFunctions]] deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "5ba658aeecaaf96923dce0da9e703bd1fe7666f9" +git-tree-sha1 = "a9e798cae4867e3a41cae2dd9eb60c047f1212db" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.1.4" +version = "2.1.6" [[deps.Static]] deps = ["IfElse"] -git-tree-sha1 = "7f5a513baec6f122401abfc8e9c074fdac54f6c1" +git-tree-sha1 = "5d2c08cef80c7a3a8ba9ca023031a85c263012c5" uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -version = "0.4.1" +version = "0.6.6" [[deps.StaticArrays]] -deps = ["LinearAlgebra", "Random", "Statistics"] -git-tree-sha1 = "74fb527333e72ada2dd9ef77d98e4991fb185f04" +deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] +git-tree-sha1 = "9f8a5dc5944dc7fbbe6eb4180660935653b0a9d9" uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.4.1" +version = "1.5.0" + +[[deps.StaticArraysCore]] +git-tree-sha1 = "6edcea211d224fa551ec8a85debdc6d732f155dc" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.0.0" [[deps.Statistics]] deps = ["LinearAlgebra", "SparseArrays"] @@ -824,39 +853,39 @@ uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" [[deps.StatsAPI]] deps = ["LinearAlgebra"] -git-tree-sha1 = "c3d8ba7f3fa0625b062b82853a7d5229cb728b6b" +git-tree-sha1 = "2c11d7290036fe7aac9038ff312d3b3a2a5bf89e" uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.2.1" +version = "1.4.0" [[deps.StatsBase]] deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "8977b17906b0a1cc74ab2e3a05faa16cf08a8291" +git-tree-sha1 = "642f08bf9ff9e39ccc7b710b2eb9a24971b52b1a" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.33.16" +version = "0.33.17" [[deps.StatsFuns]] deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] -git-tree-sha1 = "25405d7016a47cf2bd6cd91e66f4de437fd54a07" +git-tree-sha1 = "5783b877201a82fc0014cbf381e7e6eb130473a4" uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" -version = "0.9.16" +version = "1.0.1" [[deps.SteadyStateDiffEq]] deps = ["DiffEqBase", "DiffEqCallbacks", "LinearAlgebra", "NLsolve", "Reexport", "SciMLBase"] -git-tree-sha1 = "3e057e1f9f12d18cac32011aed9e61eef6c1c0ce" +git-tree-sha1 = "fa04638e98850332978467a085e58aababfa203a" uuid = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f" -version = "1.6.6" +version = "1.8.0" [[deps.StochasticDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqJump", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "24d8b3ab7e91b351ccbed5e54499a1864a64a6c6" +deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqJump", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] +git-tree-sha1 = "fea4cc29ff7d392ceb29bb64a717e6ed128bb5ff" uuid = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" -version = "6.45.0" +version = "6.49.1" [[deps.StrideArraysCore]] -deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "Requires", "SIMDTypes", "Static", "ThreadingUtilities"] -git-tree-sha1 = "49d616ef230fec080d02ada0ca5639e652cca06b" +deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "SIMDTypes", "Static", "ThreadingUtilities"] +git-tree-sha1 = "367989c5c0c856fdf7e7f6577b384e63104fb854" uuid = "7792a7ef-975c-4747-a70f-980b88e8d1da" -version = "0.2.13" +version = "0.3.14" [[deps.SuiteSparse]] deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] @@ -868,9 +897,9 @@ uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" [[deps.Sundials]] deps = ["CEnum", "DataStructures", "DiffEqBase", "Libdl", "LinearAlgebra", "Logging", "Reexport", "SparseArrays", "Sundials_jll"] -git-tree-sha1 = "76d881c22a2f3f879ad74b5a9018c609969149ab" +git-tree-sha1 = "6549d3b1b5cf86446949c62616675588159ea2fb" uuid = "c3572dad-4567-51f8-b174-8c6c989267f4" -version = "4.9.2" +version = "4.9.4" [[deps.Sundials_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS_jll", "Pkg", "SuiteSparse_jll"] @@ -910,9 +939,9 @@ version = "0.5.0" [[deps.TimerOutputs]] deps = ["ExprTools", "Printf"] -git-tree-sha1 = "97e999be94a7147d0609d0b9fc9feca4bf24d76b" +git-tree-sha1 = "464d64b2510a25e6efe410e7edab14fffdc333df" uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" -version = "0.5.15" +version = "0.5.20" [[deps.TreeViews]] deps = ["Test"] @@ -922,9 +951,9 @@ version = "0.3.0" [[deps.TriangularSolve]] deps = ["CloseOpenIntervals", "IfElse", "LayoutPointers", "LinearAlgebra", "LoopVectorization", "Polyester", "Static", "VectorizationBase"] -git-tree-sha1 = "b8d08f55b02625770c09615d96927b3a8396925e" +git-tree-sha1 = "caf797b6fccbc0d080c44b4cb2319faf78c9d058" uuid = "d5829a12-d9aa-46ab-831f-fb7c9ab06edf" -version = "0.1.11" +version = "0.1.12" [[deps.UUIDs]] deps = ["Random", "SHA"] @@ -945,10 +974,10 @@ uuid = "1986cc42-f94f-5a68-af5c-568840ba703d" version = "1.11.0" [[deps.VectorizationBase]] -deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "Hwloc", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static"] -git-tree-sha1 = "1901efb08ce6c4526ddf7fdfa9181dc3593fe6a2" +deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static"] +git-tree-sha1 = "0453988844dd8ded9d63b3cdfe9e4e26b062c396" uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" -version = "0.21.25" +version = "0.21.37" [[deps.VertexSafeGraphs]] deps = ["Graphs"] diff --git a/Project.toml b/Project.toml index 0e6436b..c376112 100644 --- a/Project.toml +++ b/Project.toml @@ -17,10 +17,11 @@ OrderedCollections = "1" RecursiveFactorization = "0.2" Reexport = "1" StaticArrays = "1" -Sundials = "4.4" +Sundials = "4" TimerOutputs = "0.5" Unitful = "1" julia = "1.7" +DiffEqBase = "= 6.90.0" [deps] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" @@ -44,5 +45,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" + [extras] CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index a5c2ef2..d3ac3e4 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1047,11 +1047,11 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti nx = length(m.x_start) nxSegmented = nx-equationInfo.nxInvariant - # Update locationIDs of all states and state derivatives (indices are known, after initialStateVector!(..) was called + # Update ValueIDs of all states and state derivatives (indices are known, after initialStateVector!(..) was called for xe_info in equationInfo.x_info - locationID = ValuesID(1, xe_info.startIndex, size(xe_info.startOrInit)) - push!(result.info[xe_info.x_name ].locationID, locationID) - push!(result.info[xe_info.der_x_name].locationID, locationID) + valueID = ValuesID(1, xe_info.startIndex, size(xe_info.startOrInit)) + push!(result.info[xe_info.x_name ].id, valueID) + push!(result.info[xe_info.der_x_name].id, valueID) end # Provide storage for x and der_x utility vectors diff --git a/src/Result.jl b/src/Result.jl index 60f9a33..50bb7e8 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -71,28 +71,28 @@ struct ResultInfo aliasName::String # Name of non-eliminated variable aliasNegate::Bool # = true, if info[aliasName] signal must be negated - value::Union{Any,Missing} # Value of constant variable (without unit) + value #::Union{Any,Missing} # Value of constant variable (without unit) - VariableType::Union{DataType,Missing} # Type of variable, if known (to make sure that the VariableType is not changing) + VariableType #::Union{DataType,Missing} # Type of variable, if known (to make sure that the VariableType is not changing) unit::String # Unit of variable as a parseable string. If not known, unit="". id::Vector{ValuesID} # Location of the variable values with respect to ResultKind and Result ResultInfo(kind::ResultKind, aliasName::String; negate::Bool=false) = begin @assert(kind == RESULT_ELIMINATED) - (kind, aliasName, negate, missing, missing, "", ValuesID[]) + new(kind, aliasName, negate, missing, missing, "", ValuesID[]) end ResultInfo(kind::ResultKind, defaultOrValue, unit::String) = begin @assert(kind == RESULT_CONSTANT || kind == RESULT_X || kind == RESULT_DER_X) if kind == RESULT_CONSTANT - (kind, "", false, defaultOrValue, typeof(defaultOrValue), unit, ValuesID[]) + new(kind, "", false, defaultOrValue, typeof(defaultOrValue), unit, ValuesID[]) else - (kind, "", false, missing, typeof(defaultOrValue), unit, ValuesID[]) + new(kind, "", false, missing, typeof(defaultOrValue), unit, ValuesID[]) end end ResultInfo(kind::ResultKind, default, unit::String, index) = ResultInfo(kind,default,unit,-1,index) ResultInfo(kind::ResultKind, default, unit::String, segment, index) = begin @assert(kind != RESULT_ELIMINATED && kind != RESULT_CONSTANT) - new(kind, "", false, default, unit, ValuesID[ValuesID(segment,index,ismissing(default) ? missing : size(default))]) + new(kind, "", false, default, typeof(default), unit, ValuesID[ValuesID(segment,index,ismissing(default) ? missing : size(default))]) end end @@ -149,7 +149,7 @@ mutable struct Result{FloatType,TimeType} info[xi_info.x_name] = ResultInfo(RESULT_X , xi_info.startOrInit, x_unit ) info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, xi_info.startOrInit, der_x_unit) end - + # Fill info with w_invariant for (w_invariant_index, w_invariant_name) in enumerate(w_invariant_names) name = string(w_invariant_name) From aadd4ad7afffab41dc37133a1dbd67a9214ea493 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 26 Jun 2022 11:54:46 +0200 Subject: [PATCH 35/63] ModiaResult replaced by SignalTables --- Manifest.toml | 64 ++--- Project.toml | 4 +- src/CodeGeneration.jl | 138 +++++------ src/EquationAndStateInfo.jl | 6 +- src/Modia.jl | 53 ++++- src/Result.jl | 219 ++++++++---------- ...tInterface.jl => SignalTablesInterface.jl} | 181 +++++++++------ src/SimulateAndPlot.jl | 31 +-- test/TestFirstOrder.jl | 2 +- 9 files changed, 359 insertions(+), 339 deletions(-) rename src/{ModiaResultInterface.jl => SignalTablesInterface.jl} (55%) diff --git a/Manifest.toml b/Manifest.toml index eafa6b4..e52cc1c 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -20,9 +20,9 @@ version = "0.2.0" [[deps.ArrayInterface]] deps = ["ArrayInterfaceCore", "Compat", "IfElse", "LinearAlgebra", "Static"] -git-tree-sha1 = "d956c0606a3bc1112a1f99a8b2309b79558d9921" +git-tree-sha1 = "1d062b8ab719670c16024105ace35e6d32988d4f" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "6.0.17" +version = "6.0.18" [[deps.ArrayInterfaceCore]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] @@ -38,15 +38,21 @@ version = "0.2.0" [[deps.ArrayInterfaceOffsetArrays]] deps = ["ArrayInterface", "OffsetArrays", "Static"] -git-tree-sha1 = "7dce0e2846e7496622f5d2742502d7e029693458" +git-tree-sha1 = "c49f6bad95a30defff7c637731f00934c7289c50" uuid = "015c0d05-e682-4f19-8f0a-679ce4c54826" -version = "0.1.5" +version = "0.1.6" [[deps.ArrayInterfaceStaticArrays]] -deps = ["Adapt", "ArrayInterface", "LinearAlgebra", "Static", "StaticArrays"] -git-tree-sha1 = "d7dc30474e73173a990eca86af76cae8790fa9f2" +deps = ["Adapt", "ArrayInterface", "ArrayInterfaceStaticArraysCore", "LinearAlgebra", "Static", "StaticArrays"] +git-tree-sha1 = "efb000a9f643f018d5154e56814e338b5746c560" uuid = "b0d46f97-bff5-4637-a19a-dd75974142cd" -version = "0.1.2" +version = "0.1.4" + +[[deps.ArrayInterfaceStaticArraysCore]] +deps = ["Adapt", "ArrayInterfaceCore", "LinearAlgebra", "StaticArraysCore"] +git-tree-sha1 = "a1e2cf6ced6505cbad2490532388683f1e88c3ed" +uuid = "dd5226c6-a4d4-4bc7-8575-46859f9c95b9" +version = "0.1.0" [[deps.ArrayLayouts]] deps = ["FillArrays", "LinearAlgebra", "SparseArrays"] @@ -280,9 +286,9 @@ version = "0.1.8" [[deps.FastBroadcast]] deps = ["ArrayInterface", "ArrayInterfaceCore", "LinearAlgebra", "Polyester", "Static", "StrideArraysCore"] -git-tree-sha1 = "81765322b2960b7c92f9280b00956cb8d645d3f7" +git-tree-sha1 = "21cdeff41e5a1822c2acd7fc7934c5f450588e00" uuid = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -version = "0.2.0" +version = "0.2.1" [[deps.FastClosures]] git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" @@ -423,12 +429,6 @@ git-tree-sha1 = "49b0c1dd5c292870577b8f58c51072bd558febb9" uuid = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" version = "0.5.4" -[[deps.LabelledArrays]] -deps = ["ArrayInterface", "ArrayInterfaceStaticArrays", "ChainRulesCore", "LinearAlgebra", "MacroTools", "StaticArrays"] -git-tree-sha1 = "a63da17ff71f41a1f818e0e1d3c02a32cf4c51f7" -uuid = "2ee39098-c373-598a-b85f-a56591580800" -version = "1.10.2" - [[deps.LayoutPointers]] deps = ["ArrayInterface", "ArrayInterfaceOffsetArrays", "ArrayInterfaceStaticArrays", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static"] git-tree-sha1 = "b67e749fb35530979839e7b4b606a97105fe4f1c" @@ -487,9 +487,9 @@ uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" [[deps.LoopVectorization]] deps = ["ArrayInterface", "ArrayInterfaceCore", "ArrayInterfaceOffsetArrays", "ArrayInterfaceStaticArrays", "CPUSummary", "ChainRulesCore", "CloseOpenIntervals", "DocStringExtensions", "ForwardDiff", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "SIMDDualNumbers", "SIMDTypes", "SLEEFPirates", "SpecialFunctions", "Static", "ThreadingUtilities", "UnPack", "VectorizationBase"] -git-tree-sha1 = "5ea9a0aaf5ded7f0b6e43c96ca1793e60c96af93" +git-tree-sha1 = "7bf979d315193570cc2b79b4d2eb4595d68b9352" uuid = "bdcacae8-1622-11e9-2a5c-532679323890" -version = "0.12.118" +version = "0.12.119" [[deps.MacroTools]] deps = ["Markdown", "Random"] @@ -531,12 +531,6 @@ git-tree-sha1 = "57f347bcda8e96732d3f0c2e3a162383fedbeeff" uuid = "ec7bf1ca-419d-4510-bbab-199861c55244" version = "0.11.0" -[[deps.ModiaResult]] -deps = ["DataFrames", "Measurements", "MonteCarloMeasurements", "OrderedCollections", "Pkg", "Tables", "Unitful"] -git-tree-sha1 = "02324a82efdb489c16bb6d008131a1447b125ad5" -uuid = "16a87621-1533-42f6-8e19-4a825980cec2" -version = "0.4.3" - [[deps.MonteCarloMeasurements]] deps = ["Distributed", "Distributions", "LinearAlgebra", "MacroTools", "Random", "RecipesBase", "Requires", "SLEEFPirates", "StaticArrays", "Statistics", "StatsBase", "Test"] git-tree-sha1 = "03619e255664666b352a5e5f6b45e8b00d439870" @@ -610,9 +604,9 @@ version = "1.4.1" [[deps.OrdinaryDiffEq]] deps = ["Adapt", "ArrayInterface", "ArrayInterfaceGPUArrays", "ArrayInterfaceStaticArrays", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "5a27d2c7a645935998a9851bdc45c3689e897193" +git-tree-sha1 = "e92f136d8961446ea0cf1f46bc6335654d49fa8c" uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -version = "6.17.0" +version = "6.18.0" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] @@ -644,9 +638,9 @@ version = "0.4.1" [[deps.Polyester]] deps = ["ArrayInterface", "BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "ManualMemory", "PolyesterWeave", "Requires", "Static", "StrideArraysCore", "ThreadingUtilities"] -git-tree-sha1 = "bfd5fb3376bc084d202c717bbba8c94696755d87" +git-tree-sha1 = "97bbf8dc886d67ff0dd1f56cfc0ee18b7bb7f8ce" uuid = "f517fe37-dbe3-4b94-8317-1923a5111588" -version = "0.6.12" +version = "0.6.13" [[deps.PolyesterWeave]] deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] @@ -667,10 +661,10 @@ uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" version = "0.2.4" [[deps.PreallocationTools]] -deps = ["Adapt", "ArrayInterfaceCore", "ForwardDiff", "LabelledArrays"] -git-tree-sha1 = "77266c25ab9d48e31ef167eae936e8f6fa0e4754" +deps = ["Adapt", "ArrayInterfaceCore", "ForwardDiff"] +git-tree-sha1 = "ba66bf03b84ca3bd0a26aa2bbe96cd9df2f4f9b9" uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46" -version = "0.3.2" +version = "0.4.0" [[deps.Preferences]] deps = ["TOML"] @@ -799,6 +793,12 @@ version = "1.0.0" deps = ["Distributed", "Mmap", "Random", "Serialization"] uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" +[[deps.SignalTables]] +deps = ["DataFrames", "OrderedCollections", "Pkg", "Test", "Unitful"] +git-tree-sha1 = "7ba002d3fb8587dbcdcc44d9d2bd610ce68b26be" +uuid = "3201582d-3078-4276-ba5d-0a1254d79d7c" +version = "0.2.0" + [[deps.SimpleTraits]] deps = ["InteractiveUtils", "MacroTools"] git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" @@ -832,9 +832,9 @@ version = "2.1.6" [[deps.Static]] deps = ["IfElse"] -git-tree-sha1 = "5d2c08cef80c7a3a8ba9ca023031a85c263012c5" +git-tree-sha1 = "11f1b69a28b6e4ca1cc18342bfab7adb7ff3a090" uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -version = "0.6.6" +version = "0.7.3" [[deps.StaticArrays]] deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] diff --git a/Project.toml b/Project.toml index c376112..f27f53c 100644 --- a/Project.toml +++ b/Project.toml @@ -11,11 +11,11 @@ ForwardDiff = "0.10" JSON = "0.21" Measurements = "2" ModiaBase = "0.11" -ModiaResult = "0.4.1" MonteCarloMeasurements = "1" OrderedCollections = "1" RecursiveFactorization = "0.2" Reexport = "1" +SignalTables = "0.2" StaticArrays = "1" Sundials = "4" TimerOutputs = "0.5" @@ -33,12 +33,12 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" ModiaBase = "ec7bf1ca-419d-4510-bbab-199861c55244" -ModiaResult = "16a87621-1533-42f6-8e19-4a825980cec2" MonteCarloMeasurements = "0987c9cc-fe09-11e8-30f0-b96dd679fdca" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RecursiveFactorization = "f2c3362d-daeb-58d1-803e-2bc74f2840b4" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +SignalTables = "3201582d-3078-4276-ba5d-0a1254d79d7c" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index d3ac3e4..08aac17 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -318,17 +318,25 @@ mutable struct SimulationModel{FloatType,TimeType} # = false, either before first outputs!(..) call or at first outputs!(..) after init!(..) and # an error was triggered and simulate!(..) should be returned with nothing. unitless::Bool # = true, if simulation is performed without units. - initialResult::Result # Initial result data structure (includes all invariant variable definitions and empty result vectors) + + timeName::String + w_invariant_names::Vector{String} + vEliminated::Vector{Int} + vProperty::Vector{Int} + var_name::Function + result::Union{Result,Missing} # Result data structure upto current time instant + instantiateResult::Bool # = true, if result shall be newly instantiated in addToResult!(..) + newResultSegment::Bool # = true, if new result segment shall be generated in addToResult!(..) + parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor # Available after propagateEvaluateAndInstantiate!(..) called equationInfo::Modia.EquationInfo - result::Result # Result data structure upto current time instant instantiateFunctions::Vector{Tuple{Union{Expr,Symbol},OrderedDict{Symbol,Any},String}} # All definitions `_instantiateFunction = Par(functionName = XXX)` in the model to call # `XXX(instantiatedModel, submodel, submodelPath)` in the order occurring during evaluation # of the parameters where, instantiatedFunctions[i] = (XXX, submodel, submodelPath) - nsegmented::Int # Current simulation segment + nsegments::Int # Current simulation segment evaluatedParameters::OrderedDict{Symbol,Any} # Evaluated parameters nextPrevious::AbstractVector # nextPrevious[i] is the current value of the variable identified by previous(...., i) nextPre::AbstractVector @@ -338,12 +346,12 @@ mutable struct SimulationModel{FloatType,TimeType} # equationInfo.x_info[equationInfo.nx_info_fixedLength+i:equationInfo.nx_info_invariant] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) - x_segmented::Vector{FloatType} # A copy of the current segment states + x_segmented::Vector{FloatType} # A copy of the current segment states der_x_invariant::Vector{FloatType} # Derivatives of states x or x_init that correspond to invariant states # This vector is filled with derivatives of invariants states with appendVariable!(m.der_x_invariant, ...) calls, # including derivatives of x_vec[i] - der_x_segmented::Vector{FloatType} # Derivatives of states x or x_init that correspond to segmented states (defined in functions and not visible in getDerivatives!(..)) + der_x_segmented::Vector{FloatType} # Derivatives of states x or x_init that correspond to segmented states (defined in functions and not visible in getDerivatives!(..)) der_x::Vector{FloatType} # Derivatives of states x function SimulationModel{FloatType,TimeType}(modelModule, modelName, buildDict, getDerivatives!, equationInfo, @@ -394,8 +402,12 @@ mutable struct SimulationModel{FloatType,TimeType} addEventPointsDueToDEBug = false success = false + w_invariant_names = String[string(name) for name in w_invariant_names] + # Initialize other data - initialResult = Result{FloatType,TimeType}(string(timeName), equationInfo, w_invariant_names, vEliminated, vProperty, var_name) + result = missing + instantiateResult = true + newResultSegment = false parameters = deepcopy(parameterDefinition) new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!, @@ -406,7 +418,7 @@ mutable struct SimulationModel{FloatType,TimeType} hold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, - initialResult, parameters) + string(timeName), w_invariant_names, vEliminated, vProperty, var_name, result, instantiateResult, newResultSegment, parameters) end #= @@ -435,7 +447,7 @@ mutable struct SimulationModel{FloatType,TimeType} emptyResult!(m.result) result = deepcopy(m.result) - nsegmented = 1 + nsegments = 1 x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] x_start = convert(Vector{FloatType}, m.x_start) @@ -455,7 +467,7 @@ mutable struct SimulationModel{FloatType,TimeType} isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, true, LinearEquationsCopyInfoForDAEMode[], odeIntegrator, daeCopyInfo, m.sundials, m.addEventPointsDueToDEBug, success, m.unitless, - result, nsegmented, + result, nsegments, deepcopy(m.parameters), deepcopy(m.instantiateFunctions), deepcopy(m.evaluatedParameters), deepcopy(m.nextPrevious), deepcopy(m.nextPre), deepcopy(m.nextHold), x_vec, x_start, x_init, x_segmented, der_x_invariant, der_x_segmented, der_x) @@ -859,12 +871,12 @@ initial( m::SimulationModel) = m.eventHandler.initial """ - isFirstInitialOfAllSegmenteds(instantiatedModel) + isFirstInitialOfAllSegments(instantiatedModel) Return true, if **initialization phase** of simulation of the **first segmented** of a segmenteded simulation. """ -isFirstInitialOfAllSegmenteds(m::SimulationModel) = m.eventHandler.firstInitialOfAllSegments +isFirstInitialOfAllSegments(m::SimulationModel) = m.eventHandler.firstInitialOfAllSegments """ @@ -1025,13 +1037,11 @@ If initialization is successful return true, otherwise false. """ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,TimeType} m.equationInfo = deepcopy(m.initialEquationInfo) - m.result = deepcopy(m.initialResult) equationInfo = m.equationInfo - result = m.result eh = m.eventHandler m.instantiateFunctions = Tuple{Any,String}[] - m.nsegmented = 1 - newResultSegment!(result) + m.nsegments = 1 + if length(m.options.merge) > 0 m.parameters = mergeModels(m.parameters, m.options.merge) end @@ -1045,21 +1055,14 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti m.nextHold = deepcopy(m.hold) m.x_start = initialStateVector!(m) nx = length(m.x_start) - nxSegmented = nx-equationInfo.nxInvariant - - # Update ValueIDs of all states and state derivatives (indices are known, after initialStateVector!(..) was called - for xe_info in equationInfo.x_info - valueID = ValuesID(1, xe_info.startIndex, size(xe_info.startOrInit)) - push!(result.info[xe_info.x_name ].id, valueID) - push!(result.info[xe_info.der_x_name].id, valueID) - end + nxSegmented = nx-equationInfo.nxInvariant # Provide storage for x and der_x utility vectors m.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] m.x_init = zeros(FloatType,nx) - m.x_segmented = zeros(FloatType, nxSegmented) + m.x_segmented = zeros(FloatType, nxSegmented) m.der_x_invariant = zeros(FloatType,equationInfo.nxInvariant) - m.der_x_segmented = zeros(FloatType, nxSegmented) + m.der_x_segmented = zeros(FloatType, nxSegmented) m.der_x = zeros(FloatType,nx) # Log parameters @@ -1121,13 +1124,9 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where println(" Reinitialization due to FullRestart at time = ", m.time, " s") end eh = m.eventHandler - result = m.result removeSegmentedStates!(m.equationInfo) - empty!(result.alias_segmented_names) - empty!(result.w_segmented_names) - empty!(result.w_segmented_temp) - newResultSegment!(m.result) - m.nsegmented += 1 + m.nsegments += 1 + m.newResultSegment = true m.options.startTime = m.time reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) @@ -1141,34 +1140,19 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where m.x_start = initialStateVector!(m.equationInfo, m.result, FloatType) # Resize states and results - nx = length(m.x_start) + nx = length(m.x_start) nxSegmented = nx - m.equationInfo.nxInvariant resize!(m.x_init , nx) - resize!(m.x_segmented , nxSegmented) + resize!(m.x_segmented , nxSegmented) resize!(m.der_x_invariant, m.equationInfo.nxInvariant) - resize!(m.der_x_segmented , nxSegmented) + resize!(m.der_x_segmented, nxSegmented) resize!(m.der_x , nx) m.x_init .= FloatType(0) - m.x_segmented .= FloatType(0) + m.x_segmented .= FloatType(0) m.der_x_invariant .= FloatType(0) - m.der_x_segmented .= FloatType(0) + m.der_x_segmented .= FloatType(0) m.der_x .= FloatType(0) - # Update locationIDs for x_segmented and der_x_segmented - eqInfo = m.equationInfo - x_info = eqInfo.x_info - resultInfo = m.result.info - nsegmented = m.nsegmented - @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) - for i = eqInfo.nx_info_invariant+1:length(x_info) - xi_info = x_info[i] - resInfo = resultInfo[xi_info.x_name] - push!(resInfo.locationID, ValuesID(nsegmented, resInfo.startIndex, size(resInfo.startOrInit))) - resInfo = resultInfo[xi_info.der_x_name] - push!(resInfo.locationID, ValuesID(nsegmented, resInfo.startIndex, size(resInfo.startOrInit))) - end - eqInfo.status = EquationInfo_After_All_States_Are_Known - if m.options.logStates # List init/start values x_table = DataFrames.DataFrame(state=String[], init=Any[], unit=String[]) #, nominal=String[]) @@ -1605,15 +1589,22 @@ end Add result of current time instant (`time, x, der_x, w_invariant, w_segmented`) to `instantiatedModel`. """ -function addToResult!(m::SimulationModel, x, time, w_invariant...)::Nothing - @assert(length(w_invariant) == m.result.n_w_invariant) +function addToResult!(m::SimulationModel{FloatType,TimeType}, x, time, w_invariant...)::Nothing where {FloatType,TimeType} + if m.instantiateResult + m.instantiateResult = false + m.result = Result{FloatType,TimeType}(m.equationInfo, m.timeName, m.w_invariant_names, w_invariant, m.vEliminated, m.vProperty, m.var_name) + elseif m.newResultSegment + m.newResultSegment = false + @assert(length(w_invariant) == m.result.n_w_invariant) + newResultSegment!(m.result) + end copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segmented) - result = m.result + result::Result = m.result push!(result.t[ end], time) push!(result.x[ end], deepcopy(x)) push!(result.der_x[ end], deepcopy(m.der_x)) push!(result.w_invariant[end], deepcopy(w_invariant)) - push!(result.w_segmented[ end], deepcopy(m.result.w_segmented_temp)) + push!(result.w_segmented[end], deepcopy(m.result.w_segmented_temp)) return nothing end @@ -1639,21 +1630,19 @@ function new_x_segmented_variable!(eqInfo::EquationInfo, result::Result, x_name: new_result_info = false x_info = result.info[x_name] @assert(x_info.kind == RESULT_X) - @assert(x_info.type == typeof(startOrInit)) - @assert(x_info.unit == x_unit) - @assert(x_info.ndims == ndims(startOrInit)) - @assert(x_info.signalKind == ModiaResult.Continuous) - @assert(!x_info.invariant) + #@assert(x_info.type == typeof(startOrInit)) + #@assert(x_info.unit == x_unit) + #@assert(x_info.ndims == ndims(startOrInit)) + #@assert(!x_info.invariant) @assert(eqInfo.x_dict, x_name) @assert(haskey(result.info, der_x_name)) der_x_info = result.info[der_x_name] - @assert(der_x_info.kind == RESULT_DER_X) - @assert(der_x_info.type == typeof(startOrInit)) + #@assert(der_x_info.kind == RESULT_DER_X) + #@assert(der_x_info.type == typeof(startOrInit)) #@assert(der_x_info.unit == der_x_unit) - @assert(der_x_info.ndims == ndims(startOrInit)) - @assert(der_x_info.signalKind == ModiaResult.Continuous) - @assert(!der_x_info.invariant) + #@assert(der_x_info.ndims == ndims(startOrInit)) + #@assert(!der_x_info.invariant) @assert(eqInfo.der_x_dict, der_x_name) end @@ -1682,14 +1671,14 @@ new_x_segmented_variable!(m::SimulationModel, args...; kwargs...) = new_x_segmen """ index = new_w_segmented_variable!(partiallyInstantiatedModel::SimulationModel, name::String, - w_segmented_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int + w_segmented_default, unit::String="")::Int Reserve storage location for a new w_segmented variable. The returned `index` is used to store the w_segmented value at communication points in the result data structure. Value w_segmented_default is stored as default value and defines type and (fixed) size of the variable in this segmented. """ -function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented_default, unit::String=""; signalKind=ModiaResult.Continuous)::Int +function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented_default, unit::String="")::Int result = m.result w_size = size(w_segmented_default) @@ -1698,21 +1687,20 @@ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented v_info = result.info[name] @assert(!haskey(result.w_segmented_names, name)) @assert(v_info.kind == RESULT_W_SEGMENTED) - @assert(v_info.type == typeof(w_segmented_default)) - @assert(v_info.unit == unit) - @assert(v_info.ndims == ndims(w_segmented_default)) - @assert(v_info.signalKind == signalKind) - @assert(!v_info.invariant) + #@assert(v_info.type == typeof(w_segmented_default)) + #@assert(v_info.unit == unit) + #@assert(v_info.ndims == ndims(w_segmented_default)) + #@assert(!v_info.invariant) push!(result.w_segmented_names, name) push!(result.w_segmented_temp, deepcopy(w_segmented_default)) w_segmented_index = length(result_w_segmented_temp) - push!(v_info.locationID, ValuesID(m.nsegmented, w_segmented_index, size(w_segmented_default))) + push!(v_info.id, ValuesID(m.nsegments, w_segmented_index, size(w_segmented_default))) else - # Variable is defined the first time in the segmenteded simulation + # Variable is defined the first time in the segmented simulation push!(result.w_segmented_names, name) push!(result.w_segmented_temp, deepcopy(w_segmented_default)) w_segmented_index = length(result.w_segmented_temp) - result.info[name] = ResultInfo(RESULT_W_SEGMENTED, w_segmented_default, unit, signalKind, m.nsegmented, w_segmented_index) + #result.info[name] = ResultInfo(RESULT_W_SEGMENTED, w_segmented_default, unit, signalKind, m.nsegments, w_segmented_index) end println("new_w_segmented_variable: w_segmented_temp = ", result.w_segmented_temp) return w_segmented_index diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index 5ad270d..bc62916 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -551,7 +551,7 @@ mutable struct StateElementInfo # = false, if vector length::Int # length of x-element or -1 if not yet known startIndex::Int # start index of state with respect to x-vector or -1 if not yet known - x_segmented_startIndex::Int # start index of segmented state with respect to x_segmented vector + x_segmented_startIndex::Int # start index of segmented state with respect to x_segmented vector # or -1, if it is no segmented state (for a segmented state, x_segmented_startIndex # is consistently set when it is added via newHiddenState(..)). end @@ -647,7 +647,7 @@ mutable struct EquationInfo # This variable is updated once all states are known. nxInvariant::Int # = number of invariant x-elements (so x[1:nxInvariant] are invariant states) or -1 if not yet known # This variable is updated once all states are known. - nxSegmented::Int # = number of segmented x-elements (x[nxInvariant+1:nxInvariant+nxSegmented]). + nxSegmented::Int # = number of segmented x-elements (x[nxInvariant+1:nxInvariant+nxSegmented]). # This variable is always updated consistently via function new_x_segmented_variable!(..) # (nxSegmented=0, if there are no segmented states yet). nx_info_fixedLength::Int # x_info[1:nx_info_fixedLength] are states with fixed length (does not change after compilation) or -1 if not yet known @@ -668,7 +668,7 @@ mutable struct EquationInfo vSolvedWithFixedTrue = String[] nx = -1 nxInvariant = -1 - nxSegmented = 0 + nxSegmented = 0 nx_info_fixedLength = -1 nx_info_invariant = -1 x_dict = OrderedCollections.OrderedDict{String,Int}() diff --git a/src/Modia.jl b/src/Modia.jl index 83c0d88..ba61505 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-06-10" +const Date = "2022-06-26" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -36,16 +36,55 @@ experimentalTranslation = false using Reexport +@reexport using SignalTables # export SignalTables symbols @reexport using Unitful # export Unitful symbols @reexport using DifferentialEquations # export DifferentialEquations symbols +import SignalTables: AvailablePlotPackages + +""" + Deprecated: @usingModiaPlot() + +Use instead @usingPlotPackage or SignalTables.@usingPlotPackage +""" +macro usingModiaPlot() + if haskey(ENV, "SignalTablesPlotPackage") + PlotPackage = ENV["SignalTablesPlotPackage"] + if !(PlotPackage in AvailablePlotPackages) + @warn "ENV[\"SignalTablesPlotPackage\"] = \"$PlotPackage\" is not supported!. Using \"SilentNoPlot\"." + @goto USE_NO_PLOT + elseif PlotPackage == "NoPlot" + @goto USE_NO_PLOT + elseif PlotPackage == "SilentNoPlot" + expr = :( import SignalTables.SilentNoPlot: plot, showFigure, saveFigure, closeFigure, closeAllFigures ) + return esc( expr ) + else + PlotPackage = Symbol("SignalTablesInterface_" * PlotPackage) + expr = :(using $PlotPackage) + println("$expr") + return esc( :(using $PlotPackage) ) + end + + else + @warn "No plot package activated. Using \"SilentNoPlot\"." + @goto USE_NO_PLOT + end + + @label USE_NO_PLOT + expr = :( using SignalTables.SilentNoPlot: plot, showFigure, saveFigure, closeFigure, closeAllFigures ) + println("$expr") + return esc( expr ) +end +export @usingModiaPlot + + export ModiaBase export CVODE_BDF, IDA export instantiateModel, @instantiateModel, assert, stringifyDefinition export stripUnit export simulate!, linearize!, get_result -export @usingModiaPlot, usePlotPackage, usePreviousPlotPackage, currentPlotPackage +#export @usingModiaPlot, usePlotPackage, usePreviousPlotPackage, currentPlotPackage export resultInfo, showResultInfo, rawSignal, getPlotSignal, defaultHeading export signalNames, timeSignalName, hasSignal export hasParameter, getParameter, getEvaluatedParameter @@ -75,10 +114,10 @@ using ModiaBase.BLTandPantelidesUtilities using ModiaBase.BLTandPantelides using ModiaBase.Differentiate -import ModiaResult -import ModiaResult: usePlotPackage, usePreviousPlotPackage, currentPlotPackage -import ModiaResult: resultInfo, showResultInfo, getPlotSignal, defaultHeading -import ModiaResult: signalNames, timeSignalName, hasSignal +#import SignalTables +#import SignalTables.: usePlotPackage, usePreviousPlotPackage, currentPlotPackage +#import SignalTables.: resultInfo, showResultInfo, getPlotSignal, getDefaultHeading +#import SignalTables.: signalNames, timeSignalName, hasSignal import StaticArrays # Make StaticArrays available for the tests @@ -181,7 +220,7 @@ include("EvaluateParameters.jl") # include("GenerateGetDerivatives.jl") include("Synchronous.jl") include("SimulateAndPlot.jl") -include("ModiaResultInterface.jl") +include("SignalTablesInterface.jl") include("ReverseDiffInterface.jl") include("PathPlanning.jl") include("JSONModel.jl") diff --git a/src/Result.jl b/src/Result.jl index 50bb7e8..c8f48f5 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -4,7 +4,6 @@ # Modia result datastrucure and functions operating on results. using OrderedCollections: OrderedDict, OrderedSet -import ModiaResult """ @enum ResultKind RESULT_ELIMINATED RESULT_CONSTANT RESULT_T RESULT_X RESULT_DER_X RESULT_W_INVARIANT RESULT_W_SEGMENTED @@ -31,17 +30,17 @@ Kind of result variable. Return a new id that defines where the values of a variable are stored. """ struct ValuesID - segment::Int # Index of simulation segment (= -1, if invariant variable) - index::Int # Index or start index with respect to simulation segment - dims::Union{Dims,Missing} # Dimensions with respect to simulation segment (dims=missing, if dimensions not known) + segment::Int # Index of simulation segment (= -1, if index holds for every segment) + index::Int # Index or start index with respect to simulation segment + dims::Dims # Dimensions with respect to simulation segment - ValuesID(index, dims) = new(-1, index, dims) - ValuesID(segmented, index, dims) = new(segmented, index, dims) + ValuesID(index, dims) = new( -1, index, dims) + ValuesID(segment, index, dims) = new(segment, index, dims) end -hasIinlineValues(kind::ResultKind) = kind == RESULT_X || RESULT_DER_X -hasDims( kind::ResultKind) = kind != RESULT_W_INVARIANT +hasInlineValues(kind::ResultKind) = kind == RESULT_X || RESULT_DER_X +hasDims( kind::ResultKind) = kind != RESULT_W_INVARIANT isInvariant(id::Vector{ValuesID}) = length(id) == 1 isSegmented(id::Vector{ValuesID}, t::AbstractVector) = !(length(id) == 1 || length(id) == length(t)) @@ -49,58 +48,41 @@ isSegmented(id::Vector{ValuesID}, t::AbstractVector) = !(length(id) == 1 || leng index_i(id::Vector{ValuesID}, i::Int) = isInvariant(id) ? id[1].index : id[i].index dims_i( id::Vector{ValuesID}, i::Int, kind::ResultKind, v::AbstractVector) = hasDims(kind) ? (isInvariant(id) ? id[1].dims : id[i].dims) : (isInvariant(id) ? size(v[1][1][id[1].index]) : size(v[i][1][id[i].index])) - -""" - info = ResultInfo(kind, aliasName; negate=false) # Define alias ResultInfo - info = ResultInfo(kind, defaultOrValue, unit) # Define constant ResultInfo or partial ResultInfo of x or der_x - info = ResultInfo(kind, default , unit, index) # Define ResultInfo for invariant variable - info = ResultInfo(kind, default , unit, segment, index) # Define ResultInfo for segmented variable +""" + info = ResultInfo(kind, signal, id) # t, x, der_x, w_invariant, w_segmented + info = ResultInfo(signal, value) # constant + info = ResultInfo(signal, aliasName, aliasNegate) # alias and negative alias + Return info how to access a result variable. """ struct ResultInfo - kind::ResultKind # Kind of result variable in simulation segment sk at time instant ti with index = index_i(..): - # = RESULT_ELIMINATED : Variable is eliminated. Alias info is stored in result.info - # = RESULT_CONSTANT : Variable is constant all the time. Value is stored in result.info - # = RESULT_T : result.t[ sk][ti] - # = RESULT_X : result.x[ sk][ti][index:index+prod(dims_i(..))-1] - # = RESULT_DER_X : result.der_x[ sk][ti][index:index+prod(dims_i(..))-1] - # = RESULT_W_INVARIANT: result.w_invariant[sk][ti][index] - # = RESULT_W_SEGMENTED: result.w_segmented[sk][ti][index] - - aliasName::String # Name of non-eliminated variable - aliasNegate::Bool # = true, if info[aliasName] signal must be negated - value #::Union{Any,Missing} # Value of constant variable (without unit) + kind::ResultKind # Kind of result variable in simulation segment sk at time instant ti with index = index_i(..): + # = RESULT_ELIMINATED : Variable is eliminated. Alias info is stored in result.info + # = RESULT_CONSTANT : Variable is constant all the time. Value is stored in result.info + # = RESULT_T : result.t[ sk][ti] + # = RESULT_X : result.x[ sk][ti][index:index+prod(dims_i(..))-1] + # = RESULT_DER_X : result.der_x[ sk][ti][index:index+prod(dims_i(..))-1] + # = RESULT_W_INVARIANT: result.w_invariant[sk][ti][index] + # = RESULT_W_SEGMENTED: result.w_segmented[sk][ti][index] + signal::SignalTables.SymbolDictType # = Var() or Par() - VariableType #::Union{DataType,Missing} # Type of variable, if known (to make sure that the VariableType is not changing) - unit::String # Unit of variable as a parseable string. If not known, unit="". - id::Vector{ValuesID} # Location of the variable values with respect to ResultKind and Result - - ResultInfo(kind::ResultKind, aliasName::String; negate::Bool=false) = begin - @assert(kind == RESULT_ELIMINATED) - new(kind, aliasName, negate, missing, missing, "", ValuesID[]) - end - ResultInfo(kind::ResultKind, defaultOrValue, unit::String) = begin - @assert(kind == RESULT_CONSTANT || kind == RESULT_X || kind == RESULT_DER_X) - if kind == RESULT_CONSTANT - new(kind, "", false, defaultOrValue, typeof(defaultOrValue), unit, ValuesID[]) - else - new(kind, "", false, missing, typeof(defaultOrValue), unit, ValuesID[]) - end - end - ResultInfo(kind::ResultKind, default, unit::String, index) = ResultInfo(kind,default,unit,-1,index) - ResultInfo(kind::ResultKind, default, unit::String, segment, index) = begin - @assert(kind != RESULT_ELIMINATED && kind != RESULT_CONSTANT) - new(kind, "", false, default, typeof(default), unit, ValuesID[ValuesID(segment,index,ismissing(default) ? missing : size(default))]) - end + aliasName::String # Name of non-eliminated variable + aliasNegate::Bool # = true, if info[aliasName] signal must be negated + id::Vector{ValuesID} # Location of the variable values with respect to ResultKind and Result + value::Any # Value of constant variable (without unit) + + ResultInfo(kind::ResultKind, signal, id::ValuesID) = new(kind , signal, "" , false , ValuesID[id]) + ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[], value) + ResultInfo(signal::SignalTables.SymbolDictType, aliasName::String, aliasNegate::Int) = new(RESULT_ELIMINATED, signal, aliasName, aliasNegate) end """ - result = Result{FloatType,TimeType}(timeNameAsString, equationInfo, w_invariant_names, vEliminated, vProperty, var_name) + result = Result{FloatType,TimeType}(timeNameAsString, equationInfo, w_invariant_names, w_invariant_initial, vEliminated, vProperty, var_name) -Return a new result data structure filled with invariant variable definitions. +Return a new result data structure. """ mutable struct Result{FloatType,TimeType} # Result access information @@ -120,41 +102,51 @@ mutable struct Result{FloatType,TimeType} w_invariant::Vector{Vector{Tuple}} # w_invariant[sk][ti][j] - invariant algebraic variables w_segmented::Vector{Vector{Vector{Any}}} # w_segmented[sk][ti][j] - segmented algebraic variables - function Result{FloatType,TimeType}(timeNameAsString::String, eqInfo::EquationInfo, w_invariant_names, vEliminated, vProperty, var_name) where {FloatType,TimeType} + function Result{FloatType,TimeType}(eqInfo::EquationInfo, timeNameAsString::String, w_invariant_names, w_invariant_initial, vEliminated, vProperty, var_name) where {FloatType,TimeType} + @assert(length(w_invariant_names) == length(w_invariant_initial)) info = OrderedDict{String, ResultInfo}() n_w_invariant = length(w_invariant_names) alias_segmented_names = OrderedSet{String}() w_segmented_names = OrderedSet{String}() w_segmented_temp = Any[] - t = fill(TimeType[],0) - x = fill(Vector{FloatType}[], 0) - der_x = fill(Vector{FloatType}[], 0) - w_invariant = fill(Tuple[],0) - w_segmented = fill(Vector{Any}[], 0) + t = fill(TimeType[],1) + x = fill(Vector{FloatType}[], 1) + der_x = fill(Vector{FloatType}[], 1) + w_invariant = fill(Tuple[], 1) + w_segmented = fill(Vector{Any}[], 1) + # Fill info with time - timeResultInfo = ResultInfo(RESULT_T, TimeType(0), "s", 1) + timeResultInfo = ResultInfo(RESULT_T, Var(_basetype=TimeType, unit="s", independent=true), ValuesID(1,())) info[timeNameAsString] = timeResultInfo - # Fill info with x_invariant, der_x_invariant (but with dummy id, since not yet known) - for i = 1:eqInfo.nx_info_invariant + # Fill info with x, der_x + for i in 1:length(eqInfo.x_info) xi_info = eqInfo.x_info[i] - x_unit = xi_info.unit - der_x_unit = x_unit == "" ? "1/s" : unitAsString(unit(uparse(x_unit)/u"s")) @assert(!haskey(info, xi_info.x_name)) @assert(!haskey(info, xi_info.der_x_name)) - if isnothing(xi_info.startOrInit) - xi_info.startOrInit = FloatType(0) + id = ValuesID(i > eqInfo.nx_info_invariant ? 1 : -1, xi_info.startIndex, size(xi_info.startOrInit)) + index = xi_info.startIndex + x_unit = xi_info.unit + der_x_unit = x_unit == "" ? "1/s" : unitAsString(unit(uparse(x_unit)/u"s")) + x_var = Var(_basetype=FloatType, unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + if !isnan(xi_info.nominal) + x_var[:nominal] = xi_info.nominal + end + if xi_info.unbounded + x_var[:unbounded] = true end - info[xi_info.x_name] = ResultInfo(RESULT_X , xi_info.startOrInit, x_unit ) - info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, xi_info.startOrInit, der_x_unit) + info[xi_info.x_name] = ResultInfo(RESULT_X , x_var, id) + info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(_basetype=FloatType, unit=der_x_unit), id) end # Fill info with w_invariant for (w_invariant_index, w_invariant_name) in enumerate(w_invariant_names) name = string(w_invariant_name) @assert(!haskey(info, name)) - info[name] = ResultInfo(RESULT_W_INVARIANT, missing, "", w_invariant_index) + wi_invariant = w_invariant_initial[w_invariant_index] + w_var = Var(_basetype=SignalTables.basetype(wi_invariant)) + info[name] = ResultInfo(RESULT_W_INVARIANT, w_var, ValuesID(w_invariant_index, size(wi_invariant))) end # Fill info with eliminated variables @@ -162,15 +154,15 @@ mutable struct Result{FloatType,TimeType} name = var_name(v) @assert(!haskey(info, name)) if ModiaBase.isZero(vProperty, v) - info[name] = ResultInfo(RESULT_CONSTANT, FloatType(0), "") + info[name] = ResultInfo(Var(_basetype=FloatType), FloatType(0)) elseif ModiaBase.isAlias(vProperty, v) aliasName = var_name( ModiaBase.alias(vProperty, v) ) @assert(haskey(info, aliasName)) - info[name] = ResultInfo(RESULT_ELIMINATED, aliasName) + info[name] = ResultInfo(Var(), aliasName, false) else # negated alias negatedAliasName = var_name( ModiaBase.negAlias(vProperty, v) ) @assert(haskey(info, negatedAliasName)) - info[name] = ResultInfo(RESULT_ELIMINATED, negatedAliasName, negate=true) + info[name] = ResultInfo(Var(), aliasName, true) end end @@ -179,12 +171,36 @@ mutable struct Result{FloatType,TimeType} end -function newResultSegment!(result::Result{FloatType,TimeType})::Nothing where {FloatType,TimeType} +""" + newResultSegment!(result, equationInfo) + +Start a new result segment. +""" +function newResultSegment!(result::Result{FloatType,TimeType}, equationInfo::EquationInfo, nsegments::Int)::Nothing where {FloatType,TimeType} + empty!(result.alias_segmented_names) + empty!(result.w_segmented_names) + empty!(result.w_segmented_temp) + + # Update id's for x_segmented and der_x_segmented + eqInfo = equationInfo + x_info = eqInfo.x_info + resultInfo = result.info + @assert(eqInfo.status == EquationInfo_After_All_States_Are_Known) + for i = eqInfo.nx_info_invariant+1:length(x_info) + xi_info = x_info[i] + resInfo = resultInfo[xi_info.x_name] + push!(resInfo.id, ValuesID(nsegments, resInfo.startIndex, size(resInfo.startOrInit))) + resInfo = resultInfo[xi_info.der_x_name] + push!(resInfo.id, ValuesID(nsegments, resInfo.startIndex, size(resInfo.startOrInit))) + end + + # Start new segment push!(result.t , TimeType[]) push!(result.x , Vector{FloatType}[]) push!(result.der_x , Vector{FloatType}[]) push!(result.w_invariant, Tuple[]) - push!(result.w_segmented , Vector{Any}[]) + push!(result.w_segmented, Vector{Any}[]) + return nothing end @@ -192,17 +208,23 @@ end dims_range(dims::Dims) = Tuple([1:i for i in dims]) dims_i( inlineValues::Bool, id::Vector{ValuesID}, k::Int, s::AbstractVector) = inlineValues ? id[k].dims : size( s[k][1][id[k].index]) ndims_i(inlineValues::Bool, id::Vector{ValuesID}, k::Int, s::AbstractVector) = inlineValues ? length(id[k].dims) : ndims(s[k][1][id[k].index]) - -signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::ResultInfo; log=false, name::AbstractString="") = - signalResultValues(t, s, resultInfo.id, kind == RESULT_X || kind == RESULT_DER_X, resultInfo.VariableType, log=log, name=name) -function signalResultValues(t::AbstractVector, s::AbstractVector, id::Vector{ValuesID}, inlineValues::Bool, VariableType=Float64; log=false, name::AbstractString="") - @assert(length(id) > 0) + +""" + signalResultValues(t, s, resultInfo::ResultInfo; log=false, name="") + +Return a Var() values vector from independent values t, dependent values s, and resultInfo. +""" +function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::ResultInfo; log=false, name::AbstractString="") + id = resultInfo.id + @assert(length(id) > 0) + inlineValues = resultInfo.kind == RESULT_X || resultInfo.kind == RESULT_DER_X + _basetype = resultInfo.signal[:_basetype] if length(id) == 1 && ndims_i(inlineValues,id,1,s) == 0 # Scalar signal that is defined in every segment index = id[1].index - sc = VariableType[ti[index] for sk in s for ti in sk] + sc = _basetype[ti[index] for sk in s for ti in sk] else # Find largest dims = dimsMax in all segments @@ -230,11 +252,11 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, id::Vector{Val dims = (dims1, dimsMax...) if hasMissing # Allocate target memory with missing values - sc = Array{Union{VariableType,Missing}, length(dims)}(missing, dims) + sc = Array{Union{_basetype,Missing}, length(dims)}(missing, dims) else # Allocate target memory with undef values @assert(length(dimsMax) > 0) - sc = Array{VariableType, length(dims)}(undef, dims) + sc = Array{_basetype, length(dims)}(undef, dims) end # Copy subset of s-values to target sc @@ -315,45 +337,4 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, id::Vector{Val println("typeof($name[id]) = ", typeof(sc)) end return sc -end - - -function signalResultValues(result::Result, name::AbstractString; unitless=true) - resInfo = result.info[name] - negate = false - - if resInfo.kind == RESULT_ELIMINATED - resInfo = result.info[resInfo.aliasName] - negate = result.info[resInfo.aliasNegate] - end - - if resInfo.kind == RESULT_T - sig = signal(result.t, result.t, resInfo) - elseif resInfo.kind == RESULT_X - sig = signal(result.t, result.x, resInfo) - elseif resInfo.kind == RESULT_DER_X - sig = signal(result.t, result.der_x, resInfo) - elseif resInfo.kind == RESULT_W_INVARIANT - sig = signal(result.t, result.w_invariant, resInfo) - elseif resInfo.kind == RESULT_W_SEGMENTED - sig = signal(result.t, result.w_segmented, resInfo) - elseif resInfo.kind == RESULT_CONSTANT - sig = ModiaResult.OneValueVector(resInf.value, sum(length(tk) for tk in result.t)) - else - error("Bug in Modia.signal: name=\"$name\" has ResultInfo=$resInfo, but ResultInfo.kind = $(resInfo.kind) is not known.") - end - - if negate - sig *= -1 - end - if resInfo.kind == RESULT_W_INVARIANT - # Result has already unit, if compiled with unitless=false - if unitless && !m.unitless - sig = stripUnit(sig) - end - elseif !unitless && resInfo.unit != "" - sig *= uparse(resInfo.unit) - end - - return sig end \ No newline at end of file diff --git a/src/ModiaResultInterface.jl b/src/SignalTablesInterface.jl similarity index 55% rename from src/ModiaResultInterface.jl rename to src/SignalTablesInterface.jl index 3f2e92f..fc51f86 100644 --- a/src/ModiaResultInterface.jl +++ b/src/SignalTablesInterface.jl @@ -1,90 +1,131 @@ # License for this file: MIT (expat) # Copyright 2022, DLR Institute of System Dynamics and Control -#------------------------------------------------------------------------------------------------ -# Provide the overloaded ModiaResult Abstract Interface for the results of SimulationModel -#------------------------------------------------------------------------------------------------ +#-------------------------------------------------------------------------------------------------- +# Provide the overloaded Abstract Signal Tables Interface for the results of SimulationModel +#-------------------------------------------------------------------------------------------------- -""" - hasSignal(instantiatedModel::Modia.SimulationModel, name::AbstractString) - -Return true if time-varying variable `name` (for example `name = "a.b.c"`) -is defined in the instantiateModel that can be accessed and can be used for plotting. -""" -ModiaResult.hasSignal(m::SimulationModel, name::AbstractString) = begin +@inline function checkMissingResult(m::SimulationModel, name::String)::Bool if isnothing(m) || ismissing(m) || ismissing(m.result) - return false + error("$name: No simulation results available.") end - haskey(m.result.info, name) #|| !ismissing(get_value(m.evaluatedParameters, name)) + return true end +SignalTables.isSignalTable(r::Result) = true +SignalTables.isSignalTable(m::SimulationModel) = true + """ - timeSignalName(instantiatedModel::Modia.SimulationModel) + independentSignalNames(instantiatedModel::Modia.SimulationModel|result::Modia.Result)::Vector{String} -Return the name of the independent variable of the result stored in instantiatedModel. +Return the name of the independent variable of the result stored in instantiatedModel or in result. """ -ModiaResult.timeSignalName(m::SimulationModel) = m.result.timeName +SignalTables.independentSignalNames(result::Result) = [result.timeName] +SignalTables.independentSignalNames(m::SimulationModel) = begin + if ismissing(m.result) + error("independentSignalName(..): No simulation results available in instantiated model of $(m.modelName)") + end + SignalTables.independentSignalNames(m.result) +end """ - names = signalNames(instantiatedModel::Modia.SimulationModel) + signalNames(instantiatedModel::Modia.SimulationModel|result::Modia.Result)::Vector{String} -Return the names of the time-varying variables of an +Returns a string vector of the time-varying variables of an [`@instantiateModel`](@ref) that are present in the result (e.g. can be accessed for plotting). """ -ModiaResult.signalNames(m::SimulationModel) = collect(keys(m.result.info)) - - -function getVariableType(result::Result, resInfo::ResultInfo)::DataType - if ismissing(resInfo.VariableType) - @assert(resInfo.kind == RESULT_W_INVARIANT) - return typeof( result.w_invariant[1][1][resInfo.id[1].index] ) - else - return resInfo.VariableType +SignalTables.signalNames(result::Result) = collect(keys(result.info)) +SignalTables.signalNames(m::SimulationModel) = begin + if ismissing(m.result) + error("signalNames(..): No simulation results available in instantiated model of $(m.modelName)") end + SignalTables.signalNames(m.result) end """ - info = SignalInfo(instantiatedModel::SimulationModel, name::AbstractString) + getSignal(instantiatedModel::Modia.SimulationModel|result::Modia.Result, name::String) -Return information about signal `name` of the result present in instantiatedModel. +Returns signal `name` of the result present in instantiatedModel +(that is a [`SignalTables.Var`](@ref) or a [`SignalTables.Par`](@ref)). +If `name` does not exist, an error is raised. """ -function ModiaResult.SignalInfo(m::SimulationModel, name::AbstractString) - resInfo = m.result.info[name] +SignalTables.getSignal(m::SimulationModel, name::String) = begin + checkMissingResult(m, name) + SignalTables.getSignal(m.result, name) +end +function SignalTables.getSignal(result::Result, name::String) + resInfo = result.info[name] + if haskey(resInfo.signal, :values) + return resInfo.signal + end + if resInfo.kind == RESULT_ELIMINATED - aliasResInfo = m.result.info[resInfo.aliasName] - VariableType = getVariableType(m.result, aliasResInfo) - return ModiaResult.SignalInfo(ModiaResult.Eliminated, VariableType, aliasResInfo.unit, aliasResInfo.value, resInfo.aliasName, resInfo.aliasNegate) + signal = resInfo.signal + aliasName = resInfo.aliasName + aliasNegate = resInfo.aliasNegate + aliasSignal = SignalTables.getSignal(result, aliasName) + signal = merge(aliasSignal, signal) + if aliasNegate + signal[:values] = -deepcopy(aliasSignal[:values]) + else + signal[:alias] = aliasName + signal[:values] = aliasSignal[:values] + end + return signal end - kind = resInfo.kind == RESULT_T ? ModiaResult.Independent : - (resInfo.kind == RESULT_CONSTANT ? ModiaResult.Constant : - ( (resInfo.kind == RESULT_X || resInfo.kind == RESULT_DER_X) && isInvariant(resInfo.id) || (resInfo.W_INVARIANT ? ModiaResult.Invariant : ModiaResult.Segmenteded))) + if resInfo.kind == RESULT_T + sigValues = signalResultValues(result.t, result.t, resInfo) + elseif resInfo.kind == RESULT_X + sigValues = signalResultValues(result.t, result.x, resInfo) + elseif resInfo.kind == RESULT_DER_X + sigValues = signalResultValues(result.t, result.der_x, resInfo) + elseif resInfo.kind == RESULT_W_INVARIANT + sigValues = signalResultValues(result.t, result.w_invariant, resInfo) + w_unit = unitAsParseableString(sigValues) + if w_unit != "" + resInfo.signal[:unit] = w_unit + sigValues = ustrip(sigValues) + end + elseif resInfo.kind == RESULT_W_SEGMENTED + sigValues = signalResultValues(result.t, result.w_segmented, resInfo) + elseif resInfo.kind == RESULT_CONSTANT + value = resInfo.value + t = getSignal(result, result.timeName) + if typeof(value) <: AbstractArray + sigValues = Array{eltype(value), ndims(values)}(undef, (length(t), size(value)...)) + for i = 1:length(sigValues) + for j = 1:length(value) + sigValues[i,j] = value[j] + end + end + else + sigValues = fill(value, length(t)) + end + else + error("Bug in getSignal: name=\"$name\" has ResultInfo=$resInfo, but ResultInfo.kind = $(resInfo.kind) is not known.") + end - VariableType = getVariableType(m.result, resInfo) - return ModiaResult.SignalInfo(kind, VariableType, resInfo.unit, resInfo.value, "", false) + resInfo.signal[:values] = sigValues + return resInfo.signal end """ - s = signalValues(instantiatedModel::Modia.SimulationModel, name; unitless=false) - -Return signal `name` of the result present in instantiatedModel. -If `unitless=false`, the signal is returned with its unit. + hasSignal(instantiatedModel::Modia.SimulationModel|result::Modia.Result, name::String) + +Returns `true` if signal `name` is present in the instantiatedModel result. """ -function ModiaResult.signalValues(m::SimulationModel, name; unitless=false) - if haskey(m.result.info, name) - return signalResultValues(m.result, name; unitless=unitless) - else - value = get_value(m.evaluatedParameters, name) - if ismissing(value) - error("signal(..): \"$name\" not in result and not a parameter of model $(m.modelName))") - end - return ModiaResult.OneValueVector(value, sum(length(tk) for tk in m.result.t)) +SignalTables.hasSignal(m::SimulationModel, name::String) = begin + if isnothing(m) || ismissing(m) || ismissing(m.result) + return false end + SignalTables.hasSignal(m.result, name) end +SignalTables.hasSignal(result::Result, name::String) = haskey(result.info, name) #|| !ismissing(get_value(m.evaluatedParameters, name)) function get_algorithmName_for_heading(m::SimulationModel)::String @@ -136,25 +177,23 @@ get_leaveName(pathName::String) = """ - ModiaResult.defaultHeading(instantiatedModel::Modia.SimulationModel) + SignalTables.getDefaultHeading(instantiatedModel::Modia.SimulationModel) -Return default heading of instantiatedModel result as a string -(can be used as default heading for a plot). +Return default heading of instantiatedModel as a string. """ -function ModiaResult.defaultHeading(m::SimulationModel) - FloatType = get_leaveName( string( typeof( m.x_start[1] ) ) ) - +function SignalTables.getDefaultHeading(m::SimulationModel{FloatType,TimeType}) where {FloatType,TimeType} + if isnothing(m) || ismissing(m) || ismissing(m.result) + return "" + end algorithmName = get_algorithmName_for_heading(m) if FloatType == "Float64" heading = m.modelName * " (" * algorithmName * ")" else - heading = m.modelName * " (" * algorithmName * ", " * FloatType * ")" - end - return heading + heading = m.modelName * " (" * algorithmName * ", " * string(FloatType) * ")" + end end - # For backwards compatibility """ @@ -170,7 +209,7 @@ end Therefore, the whole functionality of package [DataFrames](https://dataframes.juliadata.org/stable/) can be used, including storing the result on file in different formats. Furthermore, also plot can be used on dataFrame. - Parameters and zero-value variables are stored as ModiaResult.OneValueVector inside dataFrame + Parameters and zero-value variables are stored as SignalTables.OneValueVector inside dataFrame (are treated as vectors, but actually only the value and the number of time points is stored). If `onlyStates=true`, then only the states and the signals identified with `extraNames::Vector{String}` are stored in `dataFrame`. @@ -213,22 +252,22 @@ plot(result, "phi") # Get only states to be used as reference and compare result with reference reference = get_result(pendulum, onlyStates=true) (success, diff, diff_names, max_error, within_tolerance) = - ModiaResult.compareResults(result, reference, tolerance=0.01) + SignalTables.compareResults(result, reference, tolerance=0.01) println("Check results: success = $success") ``` """ function get_result(m::SimulationModel, name::AbstractString; unit=true) - #(xsig, xsigLegend, ysig, ysigLegend, yIsConstant) = ModiaResult.getPlotSignal(m, "time", name) + #(xsig, xsigLegend, ysig, ysigLegend, yIsConstant) = SignalTables.getPlotSignal(m, "time", name) #resIndex = m.variables[name] #ysig = ResultView(m.result, abs(resIndex), resIndex < 0) - #if ModiaResult.timeSignalName(m) != 1 + #if SignalTables.timeSignalName(m) != 1 if length(m.result.t) > 1 error("Error in Modia.get_result(\"$name\"), because function cannot be used for a segmenteded simulation with more as one segmented.") end - (tsig2, ysig2, ysigType) = ModiaResult.rawSignal(m, name) + (tsig2, ysig2, ysigType) = SignalTables.rawSignal(m, name) ysig = ysig2[1] ysig = unit ? ysig : stripUnit.(ysig) @@ -252,7 +291,7 @@ function setEvaluatedParametersInDataFrame!(obj::OrderedDict{Symbol,Any}, result if typeof(value) <: OrderedDict{Symbol,Any} setEvaluatedParametersInDataFrame!(value, result_info, dataFrame, name, nResult) elseif !haskey(result_info, name) - dataFrame[!,name] = ModiaResult.OneValueVector(value,nResult) + dataFrame[!,name] = SignalTables.OneValueVector(value,nResult) end end return nothing @@ -266,19 +305,19 @@ function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) dataFrame = DataFrames.DataFrame() - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, "time") + (timeSignal, signal, signalType) = SignalTables.rawSignal(m, "time") dataFrame[!,"time"] = timeSignal[1] if onlyStates || !ismissing(extraNames) if onlyStates for name in keys(m.equationInfo.x_dict) - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) + (timeSignal, signal, signalType) = SignalTables.rawSignal(m, name) dataFrame[!,name] = signal[1] end end if !ismissing(extraNames) for name in extraNames - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) + (timeSignal, signal, signalType) = SignalTables.rawSignal(m, name) dataFrame[!,name] = signal[1] end end @@ -286,7 +325,7 @@ function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) else for name in keys(m.result.info) if name != "time" - (timeSignal, signal, signalType) = ModiaResult.rawSignal(m, name) + (timeSignal, signal, signalType) = SignalTables.rawSignal(m, name) dataFrame[!,name] = signal[1] end end diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 6a5be02..997c782 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -3,34 +3,6 @@ import DataFrames import ForwardDiff import FiniteDiff -macro usingModiaPlot() - if haskey(ENV, "MODIA_PLOT") - ModiaPlotPackage = ENV["MODIA_PLOT"] - if !(ModiaPlotPackage in ModiaResult.AvailableModiaPlotPackages) - @warn "ENV[\"MODIA_PLOT\"] = \"$ModiaPlotPackage\" is not supported!. Using \"NoPlot\"." - @goto USE_NO_PLOT - elseif ModiaPlotPackage == "NoPlot" - @goto USE_NO_PLOT - elseif ModiaPlotPackage == "SilentNoPlot" - expr = :( import Modia.ModiaResult.SilentNoPlot: plot, showFigure, saveFigure, closeFigure, closeAllFigures ) - return esc( expr ) - else - ModiaPlotPackage = Symbol("ModiaPlot_" * ModiaPlotPackage) - expr = :(using $ModiaPlotPackage) - println("$expr") - return esc( :(using $ModiaPlotPackage) ) - end - - else - @warn "No plot package activated. Using \"NoPlot\"." - @goto USE_NO_PLOT - end - - @label USE_NO_PLOT - expr = :( import Modia.ModiaResult.NoPlot: plot, showFigure, saveFigure, closeFigure, closeAllFigures ) - println("$expr") - return esc( expr ) -end #--------------------------------------------------------------------- # Simulation @@ -222,7 +194,8 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me m.options = options m.time = options.startTime m.isInitial = true - m.nsegmented = 1 + m.nsegments = 1 + m.instantiateResult = true reinitEventHandler!(m.eventHandler, m.options.stopTime, m.options.logEvents) if ismissing(algorithm) && FloatType == Float64 diff --git a/test/TestFirstOrder.jl b/test/TestFirstOrder.jl index a688dae..2f3b585 100644 --- a/test/TestFirstOrder.jl +++ b/test/TestFirstOrder.jl @@ -15,7 +15,7 @@ FirstOrder = Model( firstOrder = @instantiateModel(FirstOrder, logCode=false) -simulate!(firstOrder, Tsit5(), stopTime = 10, log=false, requiredFinalStates = [-0.3617373025974107]) +simulate!(firstOrder, Tsit5(), stopTime = 10, log=true, requiredFinalStates = [-0.3617373025974107]) plot(firstOrder, ["u", "x", "der(x)", "y"]) From 653bd599452a51c4041379e855d577c1e33787ed Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 26 Jun 2022 12:03:40 +0200 Subject: [PATCH 36/63] Use at least DiffEqBase v6.91.7 (see https://github.com/SciML/DiffEqBase.jl/issues/784) --- Manifest.toml | 20 ++++++++++---------- Project.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index e52cc1c..3b707e0 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -201,9 +201,9 @@ version = "0.4.0" [[deps.DiffEqBase]] deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "528d97ef168b36e1a90d667e6611be24759aa1ba" +git-tree-sha1 = "1d06e792b1ed6da29bc5beabb7353c6b0e8e7b67" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.90.0" +version = "6.91.7" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] @@ -610,9 +610,9 @@ version = "6.18.0" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "7f4869861f8dac4990d6808b66b57e5a425cfd99" +git-tree-sha1 = "ca433b9e2f5ca3a0ce6702a032fce95a3b6e1e48" uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" -version = "0.11.13" +version = "0.11.14" [[deps.Parameters]] deps = ["OrderedCollections", "UnPack"] @@ -714,10 +714,10 @@ uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" version = "1.2.1" [[deps.RecursiveArrayTools]] -deps = ["Adapt", "ArrayInterfaceCore", "ArrayInterfaceStaticArrays", "ChainRulesCore", "DocStringExtensions", "FillArrays", "GPUArraysCore", "LinearAlgebra", "RecipesBase", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "de1d261ff688a68f296185085aaecf99bc039d80" +deps = ["Adapt", "ArrayInterfaceCore", "ArrayInterfaceStaticArraysCore", "ChainRulesCore", "DocStringExtensions", "FillArrays", "GPUArraysCore", "LinearAlgebra", "RecipesBase", "StaticArraysCore", "Statistics", "ZygoteRules"] +git-tree-sha1 = "7ddd4f1ac52f9cc1b784212785f86a75602a7e4b" uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" -version = "2.30.0" +version = "2.31.0" [[deps.RecursiveFactorization]] deps = ["LinearAlgebra", "LoopVectorization", "Polyester", "StrideArraysCore", "TriangularSolve"] @@ -775,10 +775,10 @@ uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" version = "0.6.33" [[deps.SciMLBase]] -deps = ["ArrayInterfaceCore", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "RecipesBase", "RecursiveArrayTools", "StaticArrays", "Statistics", "Tables", "TreeViews"] -git-tree-sha1 = "e74049cca1ff273cc62697dd3739f7d43e029d93" +deps = ["ArrayInterfaceCore", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "RecipesBase", "RecursiveArrayTools", "StaticArraysCore", "Statistics", "Tables", "TreeViews"] +git-tree-sha1 = "6a3f7d9b084b508e87d12135de950ac969187954" uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -version = "1.41.4" +version = "1.42.0" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" diff --git a/Project.toml b/Project.toml index f27f53c..4537a8c 100644 --- a/Project.toml +++ b/Project.toml @@ -21,7 +21,7 @@ Sundials = "4" TimerOutputs = "0.5" Unitful = "1" julia = "1.7" -DiffEqBase = "= 6.90.0" +DiffEqBase = "= 6.91.7" [deps] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" From 851ac3e32a311e80279e1685dcec6757f6f70069 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 26 Jun 2022 12:13:46 +0200 Subject: [PATCH 37/63] Require DiffEqBase >= v6.91.7 --- Manifest.toml | 4 ++-- Project.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 3b707e0..7462ac0 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -201,9 +201,9 @@ version = "0.4.0" [[deps.DiffEqBase]] deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "1d06e792b1ed6da29bc5beabb7353c6b0e8e7b67" +git-tree-sha1 = "ab123ea2e24d20140b284413bff63e80ea976626" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.91.7" +version = "6.92.0" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] diff --git a/Project.toml b/Project.toml index 4537a8c..5d75e84 100644 --- a/Project.toml +++ b/Project.toml @@ -21,7 +21,7 @@ Sundials = "4" TimerOutputs = "0.5" Unitful = "1" julia = "1.7" -DiffEqBase = "= 6.91.7" +DiffEqBase = "6.91.7" [deps] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" From b3a3b9e049911abe3064dbf0a5fd30d107bf36b8 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 29 Jun 2022 07:56:37 +0200 Subject: [PATCH 38/63] Bugs fixed --- src/CodeGeneration.jl | 157 ++++++++++++++++----------- src/JSONModel.jl | 2 +- src/Modia.jl | 53 +-------- src/ModiaLang.jl | 2 +- src/Result.jl | 45 ++++---- src/SignalTablesInterface.jl | 36 +++--- src/SimulateAndPlot.jl | 1 - src/Symbolic.jl | 4 +- test/TestFilterCircuit.jl | 3 +- test/TestLinearSystems.jl | 8 +- test/TestMultiReturningFunction10.jl | 2 +- test/TestPathPlanning.jl | 4 +- test/TestStateSelection.jl | 5 +- test/TestUnitAsString.jl | 4 +- 14 files changed, 156 insertions(+), 170 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 08aac17..e3b4c83 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -325,13 +325,11 @@ mutable struct SimulationModel{FloatType,TimeType} vProperty::Vector{Int} var_name::Function result::Union{Result,Missing} # Result data structure upto current time instant - instantiateResult::Bool # = true, if result shall be newly instantiated in addToResult!(..) - newResultSegment::Bool # = true, if new result segment shall be generated in addToResult!(..) parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor - + equationInfo::Modia.EquationInfo # Invariant part of equations are available + # Available after propagateEvaluateAndInstantiate!(..) called - equationInfo::Modia.EquationInfo instantiateFunctions::Vector{Tuple{Union{Expr,Symbol},OrderedDict{Symbol,Any},String}} # All definitions `_instantiateFunction = Par(functionName = XXX)` in the model to call # `XXX(instantiatedModel, submodel, submodelPath)` in the order occurring during evaluation @@ -418,7 +416,8 @@ mutable struct SimulationModel{FloatType,TimeType} hold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, - string(timeName), w_invariant_names, vEliminated, vProperty, var_name, result, instantiateResult, newResultSegment, parameters) + string(timeName), w_invariant_names, vEliminated, vProperty, var_name, result, + parameters, equationInfo) end #= @@ -652,6 +651,11 @@ and the function returns `nothing`. `name` can be a time-varying variable or a parameter. """ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit::Bool=true) where {FloatType,TimeType} + if isnothing(m) || ismissing(m.result) + @info "getLastValue(model,\"$name\"): No results yet available." + return nothing + end + result = m.result if haskey(result.info, name) # Time varying variable stored in m.result @@ -680,39 +684,45 @@ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit end elseif resInfo.kind == RESULT_X - locationID = resInfo.locationID[end] - segmented = locationID.segmented - ibeg = locationID.index - iend = ibeg + prod(locationID.size) - 1 - value = ibeg == iend ? result.x[segmented][end][ibeg] : result.x[segmented][end][ibeg:iend] + id = resInfo.id[end] + segment = id.segment + if segment < length(result.t) + return missing + end + ibeg = id.index + iend = ibeg + prod(id.size) - 1 + value = ibeg == iend ? result.x[segment][end][ibeg] : result.x[segment][end][ibeg:iend] if unit && resInfo.unit != "" value *= uparse(resInfo.unit) end elseif resInfo.kind == RESULT_DER_X - locationID = resInfo.locationID[end] - segmented = locationID.segmented - ibeg = locationID.index - iend = ibeg + prod(locationID.size) - 1 - value = ibeg == iend ? result.der_x[segmented][end][ibeg] : result.der_x[segmented][end][ibeg:iend] + id = resInfo.id[end] + segment = id.segment + if segment < length(result.t) + return missing + end + ibeg = id.index + iend = ibeg + prod(id.size) - 1 + value = ibeg == iend ? result.der_x[segment][end][ibeg] : result.der_x[segment][end][ibeg:iend] if unit && resInfo.unit != "" value *= uparse(resInfo.unit) end elseif resInfo.kind == RESULT_W_INVARIANT - locationID = resInfo.locationID[end] - @show name - @show resInfo - @show locationID - @show result.w_invariant - value = result.w_invariant[locationID.segmented][end][locationID.index] + id = resInfo.id[end] + value = result.w_invariant[end][end][id.index] if !unit value = stripUnit(value) end elseif resInfo.kind == RESULT_W_SEGMENTED - locationID = resInfo.locationID[end] - value = result.w_segmented[locationID.segmented][end][locationID.index] + id = resInfo.id[end] + segment = id.segment + if segment < length(result.t) + return missing + end + value = result.w_segmented[segment][end][id.index] if unit && resInfo.unit != "" && eltype(value) <: AbstractFloat value *= uparse(resInfo.unit) end @@ -873,8 +883,8 @@ initial( m::SimulationModel) = m.eventHandler.initial """ isFirstInitialOfAllSegments(instantiatedModel) -Return true, if **initialization phase** of simulation of the **first segmented** -of a segmenteded simulation. +Return true, if **initialization phase** of simulation of the **first segment** +of a segmented simulation. """ isFirstInitialOfAllSegments(m::SimulationModel) = m.eventHandler.firstInitialOfAllSegments @@ -891,8 +901,8 @@ terminal( m::SimulationModel) = m.eventHandler.terminal """ isTerminalOfAllSegmenteds(instantiatedModel) -Return true, if **terminal phase** of simulation of the **last segmented** -of a segmenteded simulation. +Return true, if **terminal phase** of simulation of the **last segment** +of a segmented simulation. """ isTerminalOfAllSegmenteds(m::SimulationModel) = m.eventHandler.terminalOfAllSegments @@ -1041,7 +1051,9 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti eh = m.eventHandler m.instantiateFunctions = Tuple{Any,String}[] m.nsegments = 1 - + m.result = Result{FloatType,TimeType}(m.equationInfo, m.timeName, m.w_invariant_names, m.vEliminated, m.vProperty, m.var_name) + result = m.result + if length(m.options.merge) > 0 m.parameters = mergeModels(m.parameters, m.options.merge) end @@ -1049,6 +1061,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti if isnothing(evaluatedParameters) return false end + m.evaluatedParameters = evaluatedParameters m.nextPrevious = deepcopy(m.previous) m.nextPre = deepcopy(m.pre) @@ -1065,6 +1078,16 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti m.der_x_segmented = zeros(FloatType, nxSegmented) m.der_x = zeros(FloatType,nx) + # update equationInfo + for i = equationInfo.nx_info_invariant+1:length(equationInfo.x_info) + xi_info = equationInfo.x_info[i] + resInfo = result.info[xi_info.x_name] + id = ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) + push!(resInfo.id, id) + resInfo = result.info[xi_info.der_x_name] + push!(resInfo.id, ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit))) + end + # Log parameters if m.options.logParameters parameters = m.parameters @@ -1126,10 +1149,10 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where eh = m.eventHandler removeSegmentedStates!(m.equationInfo) m.nsegments += 1 - m.newResultSegment = true m.options.startTime = m.time reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) - + newResultSegment!(m.result) + # Evaluate instantiate functions for fc in m.instantiatedFunctions logInstantiatedFunctionCalls = false @@ -1139,6 +1162,15 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where # Get initial state vector m.x_start = initialStateVector!(m.equationInfo, m.result, FloatType) + # update equationInfo + for i = m.equationInfo.nx_info_invariant+1:length(m.equationInfo.x_info) + xi_info = x_info[i] + resInfo = m.result.info[xi_info.x_name] + push!(resInfo.id, ValuesID(nsegments, xi_info.startIndex, size(xi_info.startOrInit))) + resInfo = m.result.info[xi_info.der_x_name] + push!(resInfo.id, ValuesID(nsegments, xi_info.startIndex, size(xi_info.startOrInit))) + end + # Resize states and results nx = length(m.x_start) nxSegmented = nx - m.equationInfo.nxInvariant @@ -1590,14 +1622,7 @@ end Add result of current time instant (`time, x, der_x, w_invariant, w_segmented`) to `instantiatedModel`. """ function addToResult!(m::SimulationModel{FloatType,TimeType}, x, time, w_invariant...)::Nothing where {FloatType,TimeType} - if m.instantiateResult - m.instantiateResult = false - m.result = Result{FloatType,TimeType}(m.equationInfo, m.timeName, m.w_invariant_names, w_invariant, m.vEliminated, m.vProperty, m.var_name) - elseif m.newResultSegment - m.newResultSegment = false - @assert(length(w_invariant) == m.result.n_w_invariant) - newResultSegment!(m.result) - end + @assert(length(w_invariant) == m.result.n_w_invariant) copyDerivatives!(m.der_x, m.der_x_invariant, m.der_x_segmented) result::Result = m.result push!(result.t[ end], time) @@ -1620,30 +1645,33 @@ Reserve storage location for a new x_segmented and der_x_segmented variable. The - to copy internal state derivative values to instantiatedModel.der_x_segmented[startIndex:startIndex+prod(dims(startOrInit))-1] Value startOrInit is the start/init value used during re-initialization of the new segmented with initFullRestart!(..). -""" -function new_x_segmented_variable!(eqInfo::EquationInfo, result::Result, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; - nominal::Float64 = NaN, unbounded::Bool = false)::Int +""" +function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; + nominal::Float64 = NaN, unbounded::Bool = false)::Int where {FloatType,TimeType} + eqInfo = m.equationInfo + result = m.result @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) new_result_info = true if haskey(result.info, x_name) - # State was already defined in one of the previous segmenteds + # State was already defined in one of the previous segments new_result_info = false - x_info = result.info[x_name] + x_info = result.info[x_name] + xi_info = eqInfo.x_info[ eqInfo.x_dict[x_name] ] @assert(x_info.kind == RESULT_X) - #@assert(x_info.type == typeof(startOrInit)) - #@assert(x_info.unit == x_unit) - #@assert(x_info.ndims == ndims(startOrInit)) - #@assert(!x_info.invariant) - @assert(eqInfo.x_dict, x_name) + @assert(basetype(startOrInit) == FloatType) + if typeof(startOrInit) <: Number + @assert(xi_info.scalar) + elseif typeof(startOrInit) <: AbstractVector + @assert(!xi_info.scalar) + else + error("new_x_segmented_variable(.. $x_name, $der_x_name, startOrInit,...): typeof(startOrInit) is neither a Number nor an AbstractVector)") + end + @assert(xi_info.unit == x_unit) @assert(haskey(result.info, der_x_name)) - der_x_info = result.info[der_x_name] - #@assert(der_x_info.kind == RESULT_DER_X) - #@assert(der_x_info.type == typeof(startOrInit)) - #@assert(der_x_info.unit == der_x_unit) - #@assert(der_x_info.ndims == ndims(startOrInit)) - #@assert(!der_x_info.invariant) - @assert(eqInfo.der_x_dict, der_x_name) + @assert(eqInfo.der_x_dict, der_x_name) + der_x_info = result.info[der_x_name] + @assert(der_x_info.kind == RESULT_DER_X) end x_segmented_startIndex = eqInfo.nxSegmented+1 @@ -1655,23 +1683,24 @@ function new_x_segmented_variable!(eqInfo::EquationInfo, result::Result, x_name: eqInfo.x_dict[x_name] = x_infoIndex eqInfo.der_x_dict[der_x_name] = x_infoIndex eqInfo.nxSegmented += length(startOrInit) - + if new_result_info # result.info can be only partially instantiated, because x_startIndex is only known # after function initialStateVector!(...) was called. - t_unit = result.info[result.timeName].unit - der_x_unit = x_unit == "" ? unitAsString(unit(1/uparse(t_unit))) : unitAsString(unit(uparse(x_unit)/uparse(t_unit))) - result.info[x_name] = ResultInfo(RESULT_X , startOrInit, x_unit , false) - result.info[der_x_name] = ResultInfo(RESULT_DER_X, startOrInit, der_x_unit, false) - end + t_unit = get(result.info[result.timeName].signal, :unit, "") + der_x_unit = x_unit == "" ? SignalTables.unitAsParseableString(unit(1/uparse(t_unit))) : SignalTables.unitAsParseableString(unit(uparse(x_unit)/uparse(t_unit))) + x_var = Var(_basetype=FloatType, unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + + result.info[x_name] = ResultInfo(RESULT_X , x_var) + result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(_basetype=FloatType, unit=der_x_unit)) + end return x_segmented_startIndex end -new_x_segmented_variable!(m::SimulationModel, args...; kwargs...) = new_x_segmented_variable!(m.equationInfo, m.result, args...; kwargs...) """ index = new_w_segmented_variable!(partiallyInstantiatedModel::SimulationModel, name::String, - w_segmented_default, unit::String="")::Int + w_segmented_default, unit::String="")::Int Reserve storage location for a new w_segmented variable. The returned `index` is used to store the w_segmented value at communication points in the result data structure. @@ -1683,7 +1712,7 @@ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented w_size = size(w_segmented_default) if haskey(result.info, name) - # Variable was already defined in one of the previous segmenteds + # Variable was already defined in one of the previous segments v_info = result.info[name] @assert(!haskey(result.w_segmented_names, name)) @assert(v_info.kind == RESULT_W_SEGMENTED) diff --git a/src/JSONModel.jl b/src/JSONModel.jl index d483718..e76a177 100644 --- a/src/JSONModel.jl +++ b/src/JSONModel.jl @@ -31,7 +31,7 @@ function encodeModel(model, expressionsAsStrings=true) Base.remove_linenums!(model) model = removeBlock(model) if typeof(model) <: Quantity - return Dict(:_value => ustrip.(model), :_unit=>Modia.unitAsString(unit(model))) + return Dict(:_value => ustrip.(model), :_unit=>SignalTables.unitAsParseableString(unit(model))) elseif expressionsAsStrings && typeof(model) == Expr return Dict(:_Expr=>string(model)) elseif typeof(model) == Expr diff --git a/src/Modia.jl b/src/Modia.jl index ba61505..df77e0e 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-06-26" +const Date = "2022-06-29" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -39,7 +39,6 @@ using Reexport @reexport using SignalTables # export SignalTables symbols @reexport using Unitful # export Unitful symbols @reexport using DifferentialEquations # export DifferentialEquations symbols - import SignalTables: AvailablePlotPackages """ @@ -151,56 +150,6 @@ The function is defined as: `stripUnit(v) = ustrip.(upreferred.(v))`. """ stripUnit(v) = ustrip.(upreferred.(v)) - -""" - str = unitAsString( unitOfQuantity::Unitful.FreeUnits ) - -Return a string representation of the unit of a quantity that can be used in a unit string macro -(see also Unitful [issue 412](https://github.com/PainterQubits/Unitful.jl/issues/412)). - -# Example -``` -v1 = 2.0u"m/s" -v1_unit = unitAsString( unit(v1) ) # = "m*s^-1" -v2_withoutUnit = 2.0 -code = :( \$v2_withoutUnit@u_str(\$v1_unit) ) # = 2.0u"m*s^-1" -v2 = eval(code) -@show v1 -@show v1_unit -@show v2 -``` - -# Notes -Transforms unit to string representation that is parseable again -(see also Unitful [issue 412](https://github.com/PainterQubits/Unitful.jl/issues/412)). -This implementation is a hack and only works in common cases. -Implementation is performed in the following way: - -1. Transform to string and display exponents on units not as Unicode superscripts (= default on macOS). -2. Replace " " by "*", since Unitful removes "*" when converting to string. -""" -unitAsString(unitOfQuantity::Unitful.FreeUnits) = replace(repr(unitOfQuantity,context = Pair(:fancy_exponent,false)), " " => "*") - -""" - quantityType = quantity(numberType, numberUnit::Unitful.FreeUnits) - -Return the quantity type given the numberType and the numberUnit. - -# Example -```julia -mutable struct Data{FloatType <: AbstractFloat} - velocity::quantity(FloatType, u"m/s") -end - -v = Data{Float64}(2.0u"mm/s") -@show v # v = -``` -""" -quantity(numberType, numberUnit::Unitful.FreeUnits) = Quantity{numberType, dimension(numberUnit), typeof(numberUnit)} - -quantityTypes(::Type{Unitful.Quantity{T,D,U}}) where {T,D,U} = (T,D,U) - - """ str = modelPathAsString(modelPath::Union{Expr,Symbol,Nothing}) diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 9710af5..2aa4795 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -590,7 +590,7 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod @assert all([un[i] == un[1] for i in 2:length(un)]) "The unit of all elements of state vector must be equal: $var::$(value)" un = un[1] end - return unitAsString(un) + return SignalTables.unitAsParseableString(un) end function var_startInitFixed(v_original) diff --git a/src/Result.jl b/src/Result.jl index c8f48f5..4b8527b 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -30,9 +30,9 @@ Kind of result variable. Return a new id that defines where the values of a variable are stored. """ struct ValuesID - segment::Int # Index of simulation segment (= -1, if index holds for every segment) - index::Int # Index or start index with respect to simulation segment - dims::Dims # Dimensions with respect to simulation segment + segment::Int # Index of simulation segment (= -1, if index holds for every segment) + index::Int # Index or start index with respect to simulation segment + dims::Union{Dims,Nothing} # Dimensions with respect to simulation segment; = nothing, if not yet defined (for RESULt_W_INVARIANT, before value is inquired) ValuesID(index, dims) = new( -1, index, dims) ValuesID(segment, index, dims) = new(segment, index, dims) @@ -72,13 +72,15 @@ struct ResultInfo aliasNegate::Bool # = true, if info[aliasName] signal must be negated id::Vector{ValuesID} # Location of the variable values with respect to ResultKind and Result value::Any # Value of constant variable (without unit) - - ResultInfo(kind::ResultKind, signal, id::ValuesID) = new(kind , signal, "" , false , ValuesID[id]) - ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[], value) - ResultInfo(signal::SignalTables.SymbolDictType, aliasName::String, aliasNegate::Int) = new(RESULT_ELIMINATED, signal, aliasName, aliasNegate) + + ResultInfo(kind::ResultKind, signal) = new(kind , signal, "" , false , ValuesID[]) + ResultInfo(kind::ResultKind, signal, id::ValuesID) = new(kind , signal, "" , false , ValuesID[id]) + ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[], value) + ResultInfo(signal::SignalTables.SymbolDictType, aliasName::String, aliasNegate::Bool) = new(RESULT_ELIMINATED, signal, aliasName, aliasNegate) end + """ result = Result{FloatType,TimeType}(timeNameAsString, equationInfo, w_invariant_names, w_invariant_initial, vEliminated, vProperty, var_name) @@ -96,14 +98,13 @@ mutable struct Result{FloatType,TimeType} # length(w_segmented_temp) = length(w_segmented_names) t::Vector{Vector{TimeType}} # t[sk][ti] is time instant ti in segment sk - # A variable v[sk][ti][j] is variable with index j at time instant ti in segmented sk + # A variable v[sk][ti][j] is variable with index j at time instant ti in segment sk x::Vector{Vector{Vector{FloatType}}} # x[sk][ti][j] - invariant and segmented states der_x::Vector{Vector{Vector{FloatType}}} # der_x[sk][ti][j] - invariant and segmented state derivatives w_invariant::Vector{Vector{Tuple}} # w_invariant[sk][ti][j] - invariant algebraic variables w_segmented::Vector{Vector{Vector{Any}}} # w_segmented[sk][ti][j] - segmented algebraic variables - function Result{FloatType,TimeType}(eqInfo::EquationInfo, timeNameAsString::String, w_invariant_names, w_invariant_initial, vEliminated, vProperty, var_name) where {FloatType,TimeType} - @assert(length(w_invariant_names) == length(w_invariant_initial)) + function Result{FloatType,TimeType}(eqInfo::EquationInfo, timeNameAsString::String, w_invariant_names, vEliminated, vProperty, var_name) where {FloatType,TimeType} info = OrderedDict{String, ResultInfo}() n_w_invariant = length(w_invariant_names) alias_segmented_names = OrderedSet{String}() @@ -128,7 +129,7 @@ mutable struct Result{FloatType,TimeType} id = ValuesID(i > eqInfo.nx_info_invariant ? 1 : -1, xi_info.startIndex, size(xi_info.startOrInit)) index = xi_info.startIndex x_unit = xi_info.unit - der_x_unit = x_unit == "" ? "1/s" : unitAsString(unit(uparse(x_unit)/u"s")) + der_x_unit = x_unit == "" ? "1/s" : unitAsParseableString(uparse(x_unit)/u"s") x_var = Var(_basetype=FloatType, unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) if !isnan(xi_info.nominal) x_var[:nominal] = xi_info.nominal @@ -143,10 +144,8 @@ mutable struct Result{FloatType,TimeType} # Fill info with w_invariant for (w_invariant_index, w_invariant_name) in enumerate(w_invariant_names) name = string(w_invariant_name) - @assert(!haskey(info, name)) - wi_invariant = w_invariant_initial[w_invariant_index] - w_var = Var(_basetype=SignalTables.basetype(wi_invariant)) - info[name] = ResultInfo(RESULT_W_INVARIANT, w_var, ValuesID(w_invariant_index, size(wi_invariant))) + @assert(!haskey(info, name)) + info[name] = ResultInfo(RESULT_W_INVARIANT, Var(), ValuesID(w_invariant_index, nothing)) end # Fill info with eliminated variables @@ -162,7 +161,7 @@ mutable struct Result{FloatType,TimeType} else # negated alias negatedAliasName = var_name( ModiaBase.negAlias(vProperty, v) ) @assert(haskey(info, negatedAliasName)) - info[name] = ResultInfo(Var(), aliasName, true) + info[name] = ResultInfo(Var(), negatedAliasName, true) end end @@ -206,8 +205,6 @@ end dims_range(dims::Dims) = Tuple([1:i for i in dims]) -dims_i( inlineValues::Bool, id::Vector{ValuesID}, k::Int, s::AbstractVector) = inlineValues ? id[k].dims : size( s[k][1][id[k].index]) -ndims_i(inlineValues::Bool, id::Vector{ValuesID}, k::Int, s::AbstractVector) = inlineValues ? length(id[k].dims) : ndims(s[k][1][id[k].index]) """ @@ -220,20 +217,20 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re @assert(length(id) > 0) inlineValues = resultInfo.kind == RESULT_X || resultInfo.kind == RESULT_DER_X _basetype = resultInfo.signal[:_basetype] - - if length(id) == 1 && ndims_i(inlineValues,id,1,s) == 0 + ndims_s = length(id[1].dims) + if length(id) == 1 && ndims_s == 0 # Scalar signal that is defined in every segment index = id[1].index - sc = _basetype[ti[index] for sk in s for ti in sk] + sc = _basetype[ustrip.(ti[index]) for sk in s for ti in sk] else # Find largest dims = dimsMax in all segments - dimsMax::Dims{ndims_i(inlineValues,id,1,s)} = dims_i(inlineValues,id,1,s) + dimsMax::Dims{ndims_s} = id[1].dims hasMissing::Bool = !(length(id) == 1 || length(id) == length(t)) if length(id) > 1 dMax::Vector{Int} = [dimsMax...] for i = 2:length(id) - dimi = dims_i(inlineValues,id,i,s) + dimi::Dims{ndims_s} = id[i].dims @assert(length(dMax) == length(dimi)) if dimi != dMax hasMissing = true @@ -324,7 +321,7 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re end end for s_ti in s[k] - setindex!(sc, s_ti[index], (j,dimr...)...) + setindex!(sc, uskip.(s_ti[index]), (j,dimr...)...) j += 1 end end diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index fc51f86..15c6f9a 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -78,32 +78,42 @@ function SignalTables.getSignal(result::Result, name::String) end if resInfo.kind == RESULT_T - sigValues = signalResultValues(result.t, result.t, resInfo) + sigValues = signalResultValues(result.t, result.t, resInfo; name=name) elseif resInfo.kind == RESULT_X - sigValues = signalResultValues(result.t, result.x, resInfo) + sigValues = signalResultValues(result.t, result.x, resInfo; name=name) elseif resInfo.kind == RESULT_DER_X - sigValues = signalResultValues(result.t, result.der_x, resInfo) + sigValues = signalResultValues(result.t, result.der_x, resInfo; name=name) elseif resInfo.kind == RESULT_W_INVARIANT - sigValues = signalResultValues(result.t, result.w_invariant, resInfo) - w_unit = unitAsParseableString(sigValues) - if w_unit != "" - resInfo.signal[:unit] = w_unit - sigValues = ustrip(sigValues) - end + index = resInfo.id[1].index + w_value = result.w_invariant[1][1][index] + w_unit = SignalTables.unitAsParseableString(w_value) + + # w_invariant has potentially a unit defined - remove it + if w_unit != "" + resInfo.signal[:unit] = w_unit + w_value = ustrip.(w_value) + end + + # w_invariant is defined in all segments and has no size information defined - add size information + resInfo.id[1] = ValuesID(index, size(w_value)) + + resInfo.signal[:_basetype] = basetype(w_value) + sigValues = signalResultValues(result.t, result.w_invariant, resInfo; name=name) elseif resInfo.kind == RESULT_W_SEGMENTED - sigValues = signalResultValues(result.t, result.w_segmented, resInfo) + sigValues = signalResultValues(result.t, result.w_segmented, resInfo; name=name) elseif resInfo.kind == RESULT_CONSTANT value = resInfo.value - t = getSignal(result, result.timeName) + t = getSignal(result, result.timeName)[:values] + len_t = sum(length(tk) for tk in t) if typeof(value) <: AbstractArray - sigValues = Array{eltype(value), ndims(values)}(undef, (length(t), size(value)...)) + sigValues = Array{eltype(value), ndims(values)}(undef, (len_t, size(value)...)) for i = 1:length(sigValues) for j = 1:length(value) sigValues[i,j] = value[j] end end else - sigValues = fill(value, length(t)) + sigValues = fill(value, len_t) end else error("Bug in getSignal: name=\"$name\" has ResultInfo=$resInfo, but ResultInfo.kind = $(resInfo.kind) is not known.") diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 997c782..e2bb0e0 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -195,7 +195,6 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me m.time = options.startTime m.isInitial = true m.nsegments = 1 - m.instantiateResult = true reinitEventHandler!(m.eventHandler, m.options.stopTime, m.options.logEvents) if ismissing(algorithm) && FloatType == Float64 diff --git a/src/Symbolic.jl b/src/Symbolic.jl index a563a49..72db3d8 100644 --- a/src/Symbolic.jl +++ b/src/Symbolic.jl @@ -20,7 +20,7 @@ function addCastAndTypeCheckBasicValueType(ex, value, FloatType) # typeof(FloatType) is neither Measurements nor MonteCarloMeasurements T = baseType(FloatType) if isQuantity(typeof(value)) - ustr = unitAsString(unit(value)) + ustr = unitAsParseableString(unit(value)) :( Modia.quantity($T, @u_str($ustr))($ex)::Modia.quantity($T, @u_str($ustr)) ) else :( $T($ex)::$T ) @@ -59,7 +59,7 @@ function addCastAndTypeCheck(ex,value,FloatType) if FloatType <: Measurements.Measurement if isMeasurements(valueType) if isQuantity(valueType) - ustr = unitAsString(unit(value)) + ustr = unitAsParseableString(unit(value)) :( Modia.quantity(Modia.Measurements.Measurement{$T}, @u_str($ustr))($ex)::Modia.quantity(Modia.Measurements.Measurement{$T}, @u_str($ustr)) ) else :( Modia.Measurements.Measurement{$T}($ex)::Modia.Measurements.Measurement{$T} ) diff --git a/test/TestFilterCircuit.jl b/test/TestFilterCircuit.jl index fdf4172..0163b35 100644 --- a/test/TestFilterCircuit.jl +++ b/test/TestFilterCircuit.jl @@ -24,7 +24,8 @@ filterCircuit = @instantiateModel(FilterCircuit) simulate!(filterCircuit, Tsit5(), stopTime = 10, merge = Map(R = Map(R = 5u"Ω"), C = Map(v = 3.0u"V")), logParameters = true, logStates = true, requiredFinalStates = [7.424843902110655]) -Modia.showResultInfo(filterCircuit) +showInfo(filterCircuit) + # Test access functions @testset "Test variable access functions (TestFilterCircuit.jl)" begin currentNames = signalNames(filterCircuit) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 454d6c3..7164997 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -205,7 +205,7 @@ SSTest = Model( ssTest = @instantiateModel(SSTest, logCode=true) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, requiredFinalStates = [1.987867388853733]) -Modia.showResultInfo(ssTest) +showInfo(ssTest) plot(ssTest, ("ss.x", "ss.u","ss.w", "y"), figure=1) simulate!(ssTest, stopTime=1.0, log=false, logStates=true, @@ -219,7 +219,7 @@ simulate!(ssTest, stopTime=1.0, log=false, logStates=true, 0.9 1.0], x_init=[0.3,0.4])), # two states requiredFinalStates = [1.98786636233743, 1.9892145443000466]) -Modia.showResultInfo(ssTest) +showInfo(ssTest) plot(ssTest, ("ss.x", "ss.u", "y", "ss.w"), figure=2) @@ -247,7 +247,7 @@ SSTest2 = Model( ) ssTest2 = @instantiateModel(SSTest2, logCode=false) simulate!(ssTest2, stopTime=1.0, log=true, logStates=true) -showResultInfo(ssTest2) +showInfo(ssTest2) plot(ssTest2, [("submodel.ss.x", "submodel.x1", "submodel.x2", "submodel.x3", "submodel.x4", "ss.x" ), ("submodel.ss.u", "ss.u", "y1", "y2", "submodel.ss.w"), @@ -264,7 +264,7 @@ simulate!(ssTest2, stopTime=1.0, log=false, logStates=true, C=[0.5 0.5 0.5;], x_init=[0.35,0.45,0.55])) ) -showResultInfo(ssTest2) +showInfo(ssTest2) println("\n... Check functions for parameters and signals") showParameters( ssTest2) diff --git a/test/TestMultiReturningFunction10.jl b/test/TestMultiReturningFunction10.jl index 6c1d249..6db0440 100644 --- a/test/TestMultiReturningFunction10.jl +++ b/test/TestMultiReturningFunction10.jl @@ -98,7 +98,7 @@ Pendulum = MyModelWithBuild(_buildOption = "MyBuildOption", pendulum = @instantiateModel(Pendulum , unitless=true, log=false, logDetails=false, logCode=true, logStateSelection=false) simulate!(pendulum, stopTime = 2.0, log=true) -showResultInfo(pendulum) +showInfo(pendulum) plot(pendulum, [("phi1", "w1"), "der(w1)", "qdd"]) diff --git a/test/TestPathPlanning.jl b/test/TestPathPlanning.jl index f68a21a..0f0fb10 100644 --- a/test/TestPathPlanning.jl +++ b/test/TestPathPlanning.jl @@ -15,7 +15,7 @@ const ptp_path = PTP_path(["angle1", "angle2", "angle3"], angles = zeros(3) getPosition!(ptp_path, 0.5, angles) # angles = [0.12, 2.24, 3.24] path = getPath(ptp_path) -showResultInfo(path) +showInfo(path) plot(path, [("angle1", "angle2", "angle3"), ("der(angle1)", "der(angle2)", "der(angle3)"), @@ -38,7 +38,7 @@ const ptp_path2 = PTP_path{Measurement{Float64}}( angles = zeros(Measurement{Float64}, 3) getPosition!(ptp_path2, nom(0.5), angles) # angles = [0.12, 2.24, 3.24] path2 = getPath(ptp_path2) -showResultInfo(path2) +showInfo(path2) plot(path2, [("angle1", "angle2", "angle3"), ("der(angle1)", "der(angle2)", "der(angle3)"), diff --git a/test/TestStateSelection.jl b/test/TestStateSelection.jl index 9f7c17b..9a585b5 100644 --- a/test/TestStateSelection.jl +++ b/test/TestStateSelection.jl @@ -5,6 +5,8 @@ using Modia.Test function checkStateSelection(model, x_names, linearEquations=[]) # Check names of the states + @show model.equationInfo + for (i, state_i) in enumerate(model.equationInfo.x_info) @test state_i.x_name == x_names[i] end @@ -30,7 +32,7 @@ end firstOrder = @instantiateModel(FirstOrder) checkStateSelection(firstOrder, ["x"]) end - + @testset "... Test TwoCoupledInertias" begin TwoCoupledInertias = Model( @@ -162,7 +164,6 @@ end #checkStateSelection(slidingMass, ["x6"], [(["x5"], [1], 1, 1)]) end =# - end diff --git a/test/TestUnitAsString.jl b/test/TestUnitAsString.jl index 5d91353..9a473ad 100644 --- a/test/TestUnitAsString.jl +++ b/test/TestUnitAsString.jl @@ -8,7 +8,7 @@ import Modia.MonteCarloMeasurements.StaticParticles v1 = 2.0u"m/s" unit_v1 = unit(v1) -v1_unit = Modia.unitAsString( unit_v1 ) # = "m*s^-1" +v1_unit = Modia.unitAsParseableString( unit_v1 ) # = "m*s^-1" v2_withoutUnit = 2.0 code = :( $v2_withoutUnit*@u_str($v1_unit) ) # = 2.0u"m*s^-1" v2 = eval(code) @@ -27,7 +27,7 @@ data = Data{Float64}(2.0u"mm/s") v3 = data.velocity #@show v3 # v3 = 0.002 m s^-1 -@test Modia.unitAsString( unit(v3) ) == "m*s^-1" +@test Modia.unitAsParseableString( unit(v3) ) == "m*s^-1" v = 2.0 From 25f3024e0383eac2835131aa0f25099f25e17fac Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 29 Jun 2022 10:24:14 +0200 Subject: [PATCH 39/63] Fixed bugs --- docs/src/index.md | 2 + src/CodeGeneration.jl | 73 +++++++++++++++++++++---------------- src/EquationAndStateInfo.jl | 18 +++++---- src/PathPlanning.jl | 70 ++++++++++------------------------- src/Result.jl | 13 +++---- test/TestLinearSystems.jl | 10 ++--- test/TestUnitAsString.jl | 4 +- test/include_all.jl | 5 ++- 8 files changed, 89 insertions(+), 106 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index d0034e0..4b70c9a 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -79,6 +79,8 @@ functionalities of these packages. Such variables `v` need to be declared with `v = Var(hideResult=true)`, in order that this error does not appear (and these variables are then not stored in the result). +- getPath(path, ...) does no longer return a dictionary but a SignalTables.SignalTable. + - Internal constructor `SimulationModel(..)`: Unused argument x_startValues removed. diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index e3b4c83..607ec40 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1067,27 +1067,27 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti m.nextPre = deepcopy(m.pre) m.nextHold = deepcopy(m.hold) m.x_start = initialStateVector!(m) - nx = length(m.x_start) - nxSegmented = nx-equationInfo.nxInvariant + + # update equationInfo + for xi_info in equationInfo.x_info + resInfo = result.info[xi_info.x_name] + resInfo.signal[:start] = xi_info.startOrInit + id = ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) + push!(resInfo.id, id) + resInfo = result.info[xi_info.der_x_name] + push!(resInfo.id, id) + end # Provide storage for x and der_x utility vectors + nx = length(m.x_start) + nxSegmented = nx-equationInfo.nxInvariant m.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] m.x_init = zeros(FloatType,nx) m.x_segmented = zeros(FloatType, nxSegmented) m.der_x_invariant = zeros(FloatType,equationInfo.nxInvariant) m.der_x_segmented = zeros(FloatType, nxSegmented) m.der_x = zeros(FloatType,nx) - - # update equationInfo - for i = equationInfo.nx_info_invariant+1:length(equationInfo.x_info) - xi_info = equationInfo.x_info[i] - resInfo = result.info[xi_info.x_name] - id = ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) - push!(resInfo.id, id) - resInfo = result.info[xi_info.der_x_name] - push!(resInfo.id, ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit))) - end - + # Log parameters if m.options.logParameters parameters = m.parameters @@ -1166,9 +1166,10 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where for i = m.equationInfo.nx_info_invariant+1:length(m.equationInfo.x_info) xi_info = x_info[i] resInfo = m.result.info[xi_info.x_name] - push!(resInfo.id, ValuesID(nsegments, xi_info.startIndex, size(xi_info.startOrInit))) + id = ValuesID(nsegments, xi_info.startIndex, size(xi_info.startOrInit)) + push!(resInfo.id, ) resInfo = m.result.info[xi_info.der_x_name] - push!(resInfo.id, ValuesID(nsegments, xi_info.startIndex, size(xi_info.startOrInit))) + push!(resInfo.id, id) end # Resize states and results @@ -1675,8 +1676,15 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam end x_segmented_startIndex = eqInfo.nxSegmented+1 + if isnothing(startOrInit) + @info "State $x_name has no start or init value defined. Using start value = 0.0." + fixed = false + startOrInit = FloatType(0) + else + fixed = true + end xi_info = StateElementInfo(x_name, Symbol(x_name), der_x_name, Symbol(der_x_name), - XD, x_unit, startOrInit, true, nominal, unbounded, + XD, x_unit, startOrInit, fixed, nominal, unbounded, x_segmented_startIndex = x_segmented_startIndex) push!(eqInfo.x_info, xi_info) x_infoIndex = length(eqInfo.x_info) @@ -1705,34 +1713,37 @@ end Reserve storage location for a new w_segmented variable. The returned `index` is used to store the w_segmented value at communication points in the result data structure. Value w_segmented_default is stored as default value and defines type and (fixed) size of the variable -in this segmented. +in this segment. """ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented_default, unit::String="")::Int result = m.result w_size = size(w_segmented_default) - + push!(result.w_segmented_names, name) + push!(result.w_segmented_temp, deepcopy(w_segmented_default)) + w_index = length(result.w_segmented_temp) + if haskey(result.info, name) # Variable was already defined in one of the previous segments v_info = result.info[name] @assert(!haskey(result.w_segmented_names, name)) @assert(v_info.kind == RESULT_W_SEGMENTED) + w_unit = get(v_info, :unit, "") + if w_unit != unit + error("Variable $name changed unit from \"$w_unit\" to \"$unit\".") + end #@assert(v_info.type == typeof(w_segmented_default)) - #@assert(v_info.unit == unit) - #@assert(v_info.ndims == ndims(w_segmented_default)) - #@assert(!v_info.invariant) - push!(result.w_segmented_names, name) - push!(result.w_segmented_temp, deepcopy(w_segmented_default)) - w_segmented_index = length(result_w_segmented_temp) - push!(v_info.id, ValuesID(m.nsegments, w_segmented_index, size(w_segmented_default))) + push!(v_info.id, ValuesID(m.nsegments, w_index, w_size)) else # Variable is defined the first time in the segmented simulation - push!(result.w_segmented_names, name) - push!(result.w_segmented_temp, deepcopy(w_segmented_default)) - w_segmented_index = length(result.w_segmented_temp) - #result.info[name] = ResultInfo(RESULT_W_SEGMENTED, w_segmented_default, unit, signalKind, m.nsegments, w_segmented_index) + if unit == "" + signal = Var(_basetype = basetype(w_segmented_default)) + else + signal = Var(_basetype = basetype(w_segmented_default), unit=unit) + end + result.info[name] = ResultInfo(RESULT_W_SEGMENTED, signal, ValuesID(m.nsegments, w_index, w_size)) end - println("new_w_segmented_variable: w_segmented_temp = ", result.w_segmented_temp) - return w_segmented_index + #println("new_w_segmented_variable: w_segmented_temp = ", result.w_segmented_temp) + return w_index end diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index bc62916..cf02825 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -762,6 +762,15 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex = xi_info.startIndex + xi_info.length end + # If startOrInit is not defined, use a default value of zero. + for xi_info in eqInfo.x_info + if isnothing(xi_info.startOrInit) + @info "State $(xi_info.x_name) has no start or init value defined. Using start value = 0.0." + xi_info.startOrInit = FloatType(0) + xi_info.scalar = true + end + end + # Set startIndex for invariant states where the size was not fixed before code generation for i = nx_info_fixedLength+1:eqInfo.nx_info_invariant xi_info = x_info[i] @@ -786,13 +795,8 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa startIndex = 1 for xe_info in eqInfo.x_info if xe_info.scalar - if isnothing(xe_info.startOrInit) - x_name = xe_info.x_name - @warn "State $x_name has no start or init value defined. Using start value = 0.0." - else - @assert(length(xe_info.startOrInit) == 1) - x_start[startIndex] = FloatType(ustrip(xe_info.startOrInit)) - end + @assert(length(xe_info.startOrInit) == 1) + x_start[startIndex] = FloatType(ustrip(xe_info.startOrInit)) startIndex += 1 else xe_start = Vector{FloatType}(ustrip(xe_info.startOrInit)) diff --git a/src/PathPlanning.jl b/src/PathPlanning.jl index 84508d2..69f67ce 100644 --- a/src/PathPlanning.jl +++ b/src/PathPlanning.jl @@ -356,15 +356,16 @@ end """ getPath(path; - names=path.names, tend=1.1*path.Tend, ntime=101) + names=path.names, tend=1.1*path.Tend, ntime=101, onlyPositions=false) -Given a `path::PTP_path`, return a dictionary with the time series +Given a `path::PTP_path`, return a SignalTables.SignalTable with the time series of the path over `time` up to `tend` for all `ntime` time points. """ function getPath(path::PTP_path{FloatType}; names=path.names, ntime=101, tend = 1.1*path.Tend, onlyPositions=false) where {FloatType} tend = convertTimeVariable(FloatType, tend) - time = range(convert(FloatType,0)u"s",(tend)u"s",length=ntime) + tvec = range(0.0, tend, length=ntime) + @show tvec indices = indexin(names, path.names) names2 = deepcopy(names) for i in eachindex(indices) @@ -376,40 +377,39 @@ function getPath(path::PTP_path{FloatType}; names=path.names, end np = length(indices) - q = zeros(FloatType,length(time), np) + q = zeros(FloatType,length(tvec), np) qt = zeros(FloatType,length(path.names)) - series = OrderedDict{AbstractString,Any}() - series["time"] = time + series = SignalTable("time" => Var(values=tvec, unit="s", independent=true)) if onlyPositions - for i in eachindex(time) - getPosition!(path, time[i], qt) + for i in eachindex(tvec) + getPosition!(path, tvec[i], qt) q[i,:] = qt[indices] end for i in eachindex(names2) - series[names2[i]] = q[:,i] + series[names2[i]] = Var(values = q[:,i]) end else der_names2 = "der(" .* names2 .* ")" der2_names2 = "der2(" .* names2 .* ")" - qd = zeros(FloatType,length(time), np) - qdd = zeros(FloatType,length(time), np) + qd = zeros(FloatType,length(tvec), np) + qdd = zeros(FloatType,length(tvec), np) qtd = zeros(FloatType,length(path.names)) qtdd = zeros(FloatType,length(path.names)) - for i in eachindex(time) - getPosition!(path, stripUnit(time[i]), qt, qtd, qtdd) + for i in eachindex(tvec) + getPosition!(path, stripUnit(tvec[i]), qt, qtd, qtdd) q[i,:] = qt[indices] qd[i,:] = qtd[indices] qdd[i,:] = qtdd[indices] end for i in eachindex(names2) - series[names2[i]] = q[:,i] - series[der_names2[i]] = qd[:,i] - series[der2_names2[i]] = qdd[:,i] + series[names2[i]] = Var(values = q[:,i]) + series[der_names2[i]] = Var(values = qd[:,i]) + series[der2_names2[i]] = Var(values = qdd[:,i]) end end @@ -458,45 +458,13 @@ function plotPath(path::PTP_path{FloatType}, plot::Function; names=path.names, h end end - np = length(indices) - q = zeros(FloatType, length(time), np) - qt = zeros(FloatType, length(path.names)) - - series = Dict{AbstractString,Any}() - series["time"] = time - + pathSignalTable = getPath(path; names=names, tend=tend, ntime=ntime, onlyPositions=onlyPositions) if onlyPositions - for i in eachindex(time) - getPosition!(path, time[i], qt) - q[i,:] = qt[indices] - end - - for i in eachindex(names2) - series[names2[i]] = q[:,i] - end - - plot(series, Tuple(names2), heading=heading, figure=figure) + plot(pathSignalTable, Tuple(names2), heading=heading, figure=figure) else der_names2 = "der(" .* names2 .* ")" der2_names2 = "der2(" .* names2 .* ")" - qd = zeros(FloatType, length(time), np) - qdd = zeros(FloatType, length(time), np) - qtd = zeros(FloatType, length(path.names)) - qtdd = zeros(FloatType, length(path.names)) - for i in eachindex(time) - getPosition!(path, time[i], qt, qtd, qtdd) - q[i,:] = qt[indices] - qd[i,:] = qtd[indices] - qdd[i,:] = qtdd[indices] - end - - for i in eachindex(names2) - series[names2[i]] = q[:,i] - series[der_names2[i]] = qd[:,i] - series[der2_names2[i]] = qdd[:,i] - end - - plot(series, [Tuple(names2), Tuple(der_names2), Tuple(der2_names2)], + plot(pathSignalTable, [Tuple(names2), Tuple(der_names2), Tuple(der2_names2)], heading=heading, figure=figure) end diff --git a/src/Result.jl b/src/Result.jl index 4b8527b..a748b3b 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -116,19 +116,16 @@ mutable struct Result{FloatType,TimeType} w_invariant = fill(Tuple[], 1) w_segmented = fill(Vector{Any}[], 1) - # Fill info with time timeResultInfo = ResultInfo(RESULT_T, Var(_basetype=TimeType, unit="s", independent=true), ValuesID(1,())) info[timeNameAsString] = timeResultInfo - # Fill info with x, der_x + # Fill info with x, der_x (note: id is not yet known, because init/start value might be changed in evaluatedParameters(..), which is called after Result(...) for i in 1:length(eqInfo.x_info) xi_info = eqInfo.x_info[i] @assert(!haskey(info, xi_info.x_name)) @assert(!haskey(info, xi_info.der_x_name)) - id = ValuesID(i > eqInfo.nx_info_invariant ? 1 : -1, xi_info.startIndex, size(xi_info.startOrInit)) - index = xi_info.startIndex - x_unit = xi_info.unit + x_unit = xi_info.unit der_x_unit = x_unit == "" ? "1/s" : unitAsParseableString(uparse(x_unit)/u"s") x_var = Var(_basetype=FloatType, unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) if !isnan(xi_info.nominal) @@ -137,8 +134,8 @@ mutable struct Result{FloatType,TimeType} if xi_info.unbounded x_var[:unbounded] = true end - info[xi_info.x_name] = ResultInfo(RESULT_X , x_var, id) - info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(_basetype=FloatType, unit=der_x_unit), id) + info[xi_info.x_name] = ResultInfo(RESULT_X , x_var) + info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(_basetype=FloatType, unit=der_x_unit)) end # Fill info with w_invariant @@ -321,7 +318,7 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re end end for s_ti in s[k] - setindex!(sc, uskip.(s_ti[index]), (j,dimr...)...) + setindex!(sc, ustrip.(s_ti[index]), (j,dimr...)...) j += 1 end end diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 7164997..a3e0962 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -160,11 +160,11 @@ function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationMode end lsBuild::LinearStateSpaceBuild{FloatType} = partiallyInstantiatedModel.buildDict[path] ls = LinearStateSpaceStruct{FloatType}(; path, model...) - ls.x_startIndex = Modia.new_x_segment_variable!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) + ls.x_startIndex = Modia.new_x_segmented_variable!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) if length(ls.W) > 0 # w = W*x_init ls.w = ls.W*ls.x_init - ls.w_index = Modia.new_w_segment_variable!(partiallyInstantiatedModel, path*".w", ls.w) + ls.w_index = Modia.new_w_segmented_variable!(partiallyInstantiatedModel, path*".w", ls.w) end lsBuild.ls = ls return nothing @@ -173,11 +173,11 @@ end function openLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = instantiatedModel.buildDict[path].ls - Modia.get_Vector_x_segment_value!(instantiatedModel, ls.x_startIndex, ls.x) + Modia.get_Vector_x_segmented_value!(instantiatedModel, ls.x_startIndex, ls.x) if Modia.storeResults(instantiatedModel) && length(ls.W) > 0 # w = W*x mul!(ls.w, ls.W, ls.x) - Modia.add_w_segment_value!(instantiatedModel, ls.w_index, ls.w) + Modia.add_w_segmented_value!(instantiatedModel, ls.w_index, ls.w) end return ls end @@ -191,7 +191,7 @@ function computeStateDerivatives!(instantiatedModel, ls, u)::Bool # der_x = A*x + B*u mul!(ls.der_x, ls.A, ls.x) mul!(ls.der_x, ls.B, u, 1.0, 1.0) - Modia.add_der_x_segment_value!(instantiatedModel, ls.x_startIndex, ls.der_x) + Modia.add_der_x_segmented_value!(instantiatedModel, ls.x_startIndex, ls.der_x) return true end diff --git a/test/TestUnitAsString.jl b/test/TestUnitAsString.jl index 9a473ad..a3ea281 100644 --- a/test/TestUnitAsString.jl +++ b/test/TestUnitAsString.jl @@ -8,7 +8,7 @@ import Modia.MonteCarloMeasurements.StaticParticles v1 = 2.0u"m/s" unit_v1 = unit(v1) -v1_unit = Modia.unitAsParseableString( unit_v1 ) # = "m*s^-1" +v1_unit = unitAsParseableString( unit_v1 ) # = "m*s^-1" v2_withoutUnit = 2.0 code = :( $v2_withoutUnit*@u_str($v1_unit) ) # = 2.0u"m*s^-1" v2 = eval(code) @@ -27,7 +27,7 @@ data = Data{Float64}(2.0u"mm/s") v3 = data.velocity #@show v3 # v3 = 0.002 m s^-1 -@test Modia.unitAsParseableString( unit(v3) ) == "m*s^-1" +@test unitAsParseableString( unit(v3) ) == "m*s^-1" v = 2.0 diff --git a/test/include_all.jl b/test/include_all.jl index 2da667c..e0f8faa 100644 --- a/test/include_all.jl +++ b/test/include_all.jl @@ -4,11 +4,12 @@ import Modia.Test Test.@testset "Test basic functionality" begin include("TestVariables.jl") include("TestFirstOrder.jl") - include("TestFirstOrder2.jl") - include("TestSource.jl") +# include("TestFirstOrder2.jl") +# include("TestSource.jl") include("TestLinearEquations.jl") include("TestStateSelection.jl") include("TestFilterCircuit.jl") + include("TestFilterCircuit2.jl") include("TestArrays.jl") include("TestLinearSystems.jl") From 08064b6c8a46c6bf5e3dc710b251bfa0c3ab6e08 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 29 Jun 2022 12:58:36 +0200 Subject: [PATCH 40/63] store _basetype in ResultInfo, not in Signal --- src/CodeGeneration.jl | 13 +++++++------ src/Result.jl | 26 ++++++++++++++------------ src/SignalTablesInterface.jl | 12 +++++++++++- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 607ec40..ecde00a 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1073,6 +1073,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti resInfo = result.info[xi_info.x_name] resInfo.signal[:start] = xi_info.startOrInit id = ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) + x_type = push!(resInfo.id, id) resInfo = result.info[xi_info.der_x_name] push!(resInfo.id, id) @@ -1697,10 +1698,10 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam # after function initialStateVector!(...) was called. t_unit = get(result.info[result.timeName].signal, :unit, "") der_x_unit = x_unit == "" ? SignalTables.unitAsParseableString(unit(1/uparse(t_unit))) : SignalTables.unitAsParseableString(unit(uparse(x_unit)/uparse(t_unit))) - x_var = Var(_basetype=FloatType, unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + x_var = Var(unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) - result.info[x_name] = ResultInfo(RESULT_X , x_var) - result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(_basetype=FloatType, unit=der_x_unit)) + result.info[x_name] = ResultInfo(RESULT_X , x_var, FloatType) + result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(unit=der_x_unit), FloatType) end return x_segmented_startIndex end @@ -1736,11 +1737,11 @@ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented else # Variable is defined the first time in the segmented simulation if unit == "" - signal = Var(_basetype = basetype(w_segmented_default)) + signal = Var() else - signal = Var(_basetype = basetype(w_segmented_default), unit=unit) + signal = Var(unit=unit) end - result.info[name] = ResultInfo(RESULT_W_SEGMENTED, signal, ValuesID(m.nsegments, w_index, w_size)) + result.info[name] = ResultInfo(RESULT_W_SEGMENTED, signal, ValuesID(m.nsegments, w_index, w_size), basetype(w_segmented_default)) end #println("new_w_segmented_variable: w_segmented_temp = ", result.w_segmented_temp) return w_index diff --git a/src/Result.jl b/src/Result.jl index a748b3b..8c36f22 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -51,13 +51,14 @@ dims_i( id::Vector{ValuesID}, i::Int, kind::ResultKind, v::AbstractVector) = has """ - info = ResultInfo(kind, signal, id) # t, x, der_x, w_invariant, w_segmented + info = ResultInfo(kind, signal) # x, der_x (id is initially not known) + info = ResultInfo(kind, signal, id) # t, w_invariant, w_segmented info = ResultInfo(signal, value) # constant info = ResultInfo(signal, aliasName, aliasNegate) # alias and negative alias Return info how to access a result variable. """ -struct ResultInfo +mutable struct ResultInfo kind::ResultKind # Kind of result variable in simulation segment sk at time instant ti with index = index_i(..): # = RESULT_ELIMINATED : Variable is eliminated. Alias info is stored in result.info # = RESULT_CONSTANT : Variable is constant all the time. Value is stored in result.info @@ -71,11 +72,12 @@ struct ResultInfo aliasName::String # Name of non-eliminated variable aliasNegate::Bool # = true, if info[aliasName] signal must be negated id::Vector{ValuesID} # Location of the variable values with respect to ResultKind and Result + _basetype # If known, basetype(signal.values/.values); if not known: Nothing value::Any # Value of constant variable (without unit) - ResultInfo(kind::ResultKind, signal) = new(kind , signal, "" , false , ValuesID[]) - ResultInfo(kind::ResultKind, signal, id::ValuesID) = new(kind , signal, "" , false , ValuesID[id]) - ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[], value) + ResultInfo(kind::ResultKind, signal, _basetype) = new(kind , signal, "" , false , ValuesID[] , _basetype) + ResultInfo(kind::ResultKind, signal, id::ValuesID, _basetype) = new(kind , signal, "" , false , ValuesID[id], _basetype) + ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[] , basetype(value), value) ResultInfo(signal::SignalTables.SymbolDictType, aliasName::String, aliasNegate::Bool) = new(RESULT_ELIMINATED, signal, aliasName, aliasNegate) end @@ -117,7 +119,7 @@ mutable struct Result{FloatType,TimeType} w_segmented = fill(Vector{Any}[], 1) # Fill info with time - timeResultInfo = ResultInfo(RESULT_T, Var(_basetype=TimeType, unit="s", independent=true), ValuesID(1,())) + timeResultInfo = ResultInfo(RESULT_T, Var(unit="s", independent=true), ValuesID(1,()), TimeType) info[timeNameAsString] = timeResultInfo # Fill info with x, der_x (note: id is not yet known, because init/start value might be changed in evaluatedParameters(..), which is called after Result(...) @@ -127,22 +129,22 @@ mutable struct Result{FloatType,TimeType} @assert(!haskey(info, xi_info.der_x_name)) x_unit = xi_info.unit der_x_unit = x_unit == "" ? "1/s" : unitAsParseableString(uparse(x_unit)/u"s") - x_var = Var(_basetype=FloatType, unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + x_var = Var(unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) if !isnan(xi_info.nominal) x_var[:nominal] = xi_info.nominal end if xi_info.unbounded x_var[:unbounded] = true end - info[xi_info.x_name] = ResultInfo(RESULT_X , x_var) - info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(_basetype=FloatType, unit=der_x_unit)) + info[xi_info.x_name] = ResultInfo(RESULT_X , x_var, FloatType) + info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(unit=der_x_unit), FloatType) end # Fill info with w_invariant for (w_invariant_index, w_invariant_name) in enumerate(w_invariant_names) name = string(w_invariant_name) @assert(!haskey(info, name)) - info[name] = ResultInfo(RESULT_W_INVARIANT, Var(), ValuesID(w_invariant_index, nothing)) + info[name] = ResultInfo(RESULT_W_INVARIANT, Var(), ValuesID(w_invariant_index, nothing), Nothing) end # Fill info with eliminated variables @@ -150,7 +152,7 @@ mutable struct Result{FloatType,TimeType} name = var_name(v) @assert(!haskey(info, name)) if ModiaBase.isZero(vProperty, v) - info[name] = ResultInfo(Var(_basetype=FloatType), FloatType(0)) + info[name] = ResultInfo(Var(), FloatType(0)) elseif ModiaBase.isAlias(vProperty, v) aliasName = var_name( ModiaBase.alias(vProperty, v) ) @assert(haskey(info, aliasName)) @@ -213,7 +215,7 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re id = resultInfo.id @assert(length(id) > 0) inlineValues = resultInfo.kind == RESULT_X || resultInfo.kind == RESULT_DER_X - _basetype = resultInfo.signal[:_basetype] + _basetype = resultInfo._basetype ndims_s = length(id[1].dims) if length(id) == 1 && ndims_s == 0 # Scalar signal that is defined in every segment diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index 15c6f9a..80831ad 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -97,7 +97,7 @@ function SignalTables.getSignal(result::Result, name::String) # w_invariant is defined in all segments and has no size information defined - add size information resInfo.id[1] = ValuesID(index, size(w_value)) - resInfo.signal[:_basetype] = basetype(w_value) + resInfo._basetype = basetype(w_value) sigValues = signalResultValues(result.t, result.w_invariant, resInfo; name=name) elseif resInfo.kind == RESULT_W_SEGMENTED sigValues = signalResultValues(result.t, result.w_segmented, resInfo; name=name) @@ -137,6 +137,16 @@ SignalTables.hasSignal(m::SimulationModel, name::String) = begin end SignalTables.hasSignal(result::Result, name::String) = haskey(result.info, name) #|| !ismissing(get_value(m.evaluatedParameters, name)) +#= + +""" + getSignalInfo(instantiatedModel::Modia.SimulationModel|result::Modia.Result, name::String) +""" +function getSignalInfo(instantiatedModel::Modia.SimulationModel|result::Modia.Result, name::String) +end +function getSignalInfo(instantiatedModel::Modia.SimulationModel|result::Modia.Result, name::String) +end +=# function get_algorithmName_for_heading(m::SimulationModel)::String if ismissing(m.algorithmName) From abd3f4ca053775e288e0fd1eff7b9b2ab3b2a372 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 29 Jun 2022 15:46:10 +0200 Subject: [PATCH 41/63] Evaluated parameters are now part of the result (and can be used in plots) --- docs/src/index.md | 18 ++-- src/SignalTablesInterface.jl | 162 ++++++++++++++++++++++++++++++++--- test/TestArrays.jl | 2 +- test/TestFirstOrder.jl | 2 +- test/TestFirstOrder2.jl | 3 - 5 files changed, 164 insertions(+), 23 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 4b70c9a..5bf35a6 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -42,11 +42,19 @@ functionalities of these packages. get parameter/init/start values by name (e.g. `getEvaluatedParameter(instantiatedModel, "a.b.c")`) or show all parameters. For details see the [function docu](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html). -- New functions to add hidden states and extra results from within functions that are not visible in the generated code: - `Modia.newHiddenState!, Modia.newExtraResult!, Modia.addHiddenState!, Modia.addExtraResult!, Modia.storeResults`. +- New functions to add states and algebraic variables from within functions that are not visible in the generated code: + `Modia.new_x_segmented_variable!, Modia.new_w_segmented_variable!, Modia.add_w_segmented_value!`. + These functions are called after simulate!(..) is called, but before initialization is performed. + For details see example `Modia/test/TestLinearSystems.jl`. - simulate!(..): Maximum number of iterations is switched off (DifferentialEquations.jl option set to: maxiters = Int(typemax(Int32)) ≈ 2e9). +- An instance of a SimulationModel is now a signal table according to [SignalTables.jl](https://github.com/ModiaSim/SignalTables.jl). + This means that all functions defined for a signal table (see [function overview](https://modiasim.github.io/SignalTables.jl/stable/Functions/OverviewOfFunctions.html)) + can be applied on a SimulationModel. Hereby, all Var(..) and Par(..) Modia variables are seen as signals of the signal table + (so both time varying variables, as well as parameters). One benefit is, that its now possible to directly perform standard array operations + on results, e.g. `diff = getValues(simulationModel, "a.b.c") - getValues(simulationModel, "b.d.e")`. + - Docu improved (e.g. links to utility functions documentation added) @@ -64,11 +72,7 @@ functionalities of these packages. - Bug fix 1 can lead for some models to warnings and the selected variable is no longer plotted (-> the model needs to be changed). - Bug fix 2 can lead for some models to a different result (without notice). - -- Parameters are no longer seen as part of the result (since parameters can be complex internal datastructures, e.g. for Modia3D). - Therefore, they are no longer available in result access functions (`printResultInfo, signalNames, rawSignal, getPlotSignal, plot, ...`). - Instead, they can be accessed via new functions `hasParameter, parameter, evaluatedParameter, showParameter, showEvaluatedParameter`. - + - The result data structure is now constructed with `deepcopy(..)` of every involved result variable. Previously, for some result variables just the variable reference was stored. The effect is that if previously a complex internal data structure was incorporated into the result data structure, diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index 80831ad..dbf3588 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -30,21 +30,70 @@ SignalTables.independentSignalNames(m::SimulationModel) = begin end + +function getParameterNames!(parameters, names::Vector{String}, path::String)::Nothing + for (key,value) in parameters + name = path == "" ? string(key) : path*"."*string(key) + if typeof(value) <: AbstractDict + getParameterNames!(value, names, name) + else + push!(names, name) + end + end + return nothing +end + +function getParameterNames(parameters)::Vector{String} + names = String[] + getParameterNames!(parameters, names, "") + return names +end + + """ - signalNames(instantiatedModel::Modia.SimulationModel|result::Modia.Result)::Vector{String} + signalNames(instantiatedModel::Modia.SimulationModel; var=true, par=true)::Vector{String} -Returns a string vector of the time-varying variables of an -[`@instantiateModel`](@ref) that are present in the result (e.g. can be accessed for plotting). +Returns a string vector of the variables of an +[`@instantiateModel`](@ref) that are present in the result or are (evaluated) parameters. +- If var=true, Var(..) variables are included. +- If par=true, Par(..) variables are included. """ -SignalTables.signalNames(result::Result) = collect(keys(result.info)) -SignalTables.signalNames(m::SimulationModel) = begin +function SignalTables.signalNames(m::SimulationModel; val=true, par=true)::Vector{String} if ismissing(m.result) error("signalNames(..): No simulation results available in instantiated model of $(m.modelName)") end - SignalTables.signalNames(m.result) + names1 = collect(keys(m.result.info)) + if var && !par + return names1 + end + names2 = getParameterNames(m.evaluatedParameters) + if var && par + return union(names1,names2) + elseif par + return setdiff(names2,names1) + else + return String[] + end end +""" + signalNames(result::Modia.Result)::Vector{String} + +Returns a string vector of the variables that are present in the result. +""" +SignalTables.signalNames(result::Result) = collect(keys(result.info)) + + +""" + getIndependentSignalsSize(instantiatedModel::Modia.SimulationModel|result::Modia.Result)::Dims + +Returns the lengths of the independent signal of the result as (len,). +""" +SignalTables.getIndependentSignalsSize(m::SimulationModel) = SignalTables.getIndependentSignalsSize(m.result) +SignalTables.getIndependentSignalsSize(result::Result) = (sum(length(sk) for sk in result.t), ) + + """ getSignal(instantiatedModel::Modia.SimulationModel|result::Modia.Result, name::String) @@ -54,8 +103,27 @@ If `name` does not exist, an error is raised. """ SignalTables.getSignal(m::SimulationModel, name::String) = begin checkMissingResult(m, name) - SignalTables.getSignal(m.result, name) + result = m.result + + if haskey(result.info, name) + # name is a result variable (time-varying variable stored in m.result) + signal = getSignal(result, name) + else + # name might be a parameter + sigValue = get_value(m.evaluatedParameters, name) + if ismissing(sigValue) + error("getSignal(.., $name): name is not known") + end + sigUnit = unitAsParseableString(sigValue) + if sigUnit == "" + signal = Par(value = sigValue) + else + signal = Par(value = sigValue, unit=sigUnit) + end + end + return signal end + function SignalTables.getSignal(result::Result, name::String) resInfo = result.info[name] if haskey(resInfo.signal, :values) @@ -125,17 +193,88 @@ end """ - hasSignal(instantiatedModel::Modia.SimulationModel|result::Modia.Result, name::String) + hasSignal(instantiatedModel::Modia.SimulationModel, name::String) -Returns `true` if signal `name` is present in the instantiatedModel result. +Returns `true` if signal `name` is present in the instantiatedModel result or in the evaluated parameters. """ SignalTables.hasSignal(m::SimulationModel, name::String) = begin if isnothing(m) || ismissing(m) || ismissing(m.result) return false end - SignalTables.hasSignal(m.result, name) + return haskey(m.result.info, name) || !ismissing(get_value(m.evaluatedParameters, name)) +end + + +""" + hasSignal(result::Modia.Result, name::String) + +Returns `true` if signal `name` is present in result. +""" +SignalTables.hasSignal(result::Result, name::String) = begin + if isnothing(result) || ismissing(result) + return false + end + return haskey(result.info, name) end -SignalTables.hasSignal(result::Result, name::String) = haskey(result.info, name) #|| !ismissing(get_value(m.evaluatedParameters, name)) + + +""" + getSignalInfo(instantiatedModel::Modia.SimulationModel, name::String) + +Returns signal info of variables stored in the result and of parameters. +""" +function SignalTables.getSignalInfo(m::SimulationModel, name::String) + result = m.result + if haskey(result.info, name) + # name is a result variable (time-varying variable stored in m.result) + signalInfo = getSignalInfo(m.result, name) + else + # name might be a parameter + sigValue = get_value(m.evaluatedParameters, name) + if ismissing(sigValue) + error("getSignalInfo(.., $name): name is not known") + end + sigUnit = unitAsParseableString(sigValue) + if sigUnit == "" + signalInfo = Par(_basetype = basetype(sigValue)) + else + signalInfo = Par(_basetype = basetype( ustrip.(sigValue) ), unit=sigUnit) + end + _size = nothing + size_available = false + try + _size = size(sigValue) + size_available = true + catch + size_available = false + end + if size_available + signalInfo[:_size] = _size + end + end + return signalInfo +end + + +#= + +""" + getSignalInfo(result::Modia.result, name::String) + +Returns signal info of variables stored in result. +""" +function SignalTables.getSignalInfo(result::Result, name::String) + resInfo = result.info[name] + if haskey(resInfo.signal, :values) + signalInfo = copy(resInfo.signal) + delete!(signalInfo, :values) + signalValues = resInfo.signal[:values] + signalInfo[:_basetype] = basetype(signalValues) + signalInfo[:_size] = size(signalValues) + return signalInfo + end +end +=# #= @@ -148,6 +287,7 @@ function getSignalInfo(instantiatedModel::Modia.SimulationModel|result::Modia.Re end =# + function get_algorithmName_for_heading(m::SimulationModel)::String if ismissing(m.algorithmName) algorithmName = "???" diff --git a/test/TestArrays.jl b/test/TestArrays.jl index fba2ff4..a085fa9 100644 --- a/test/TestArrays.jl +++ b/test/TestArrays.jl @@ -15,7 +15,7 @@ LinearODE = Model( linearODE = @instantiateModel(LinearODE, logCode=true) simulate!(linearODE, stopTime = 2, log=false, logStates=false, requiredFinalStates=[0.13533533463680386, 0.036632273646086545]) -plot(linearODE, ["x", "der(x)"], figure=1, heading="LinearODE with length(x)=2") +plot(linearODE, ["x", "der(x)", "A"], figure=1, heading="LinearODE with length(x)=2") simulate!(linearODE, stopTime = 2, log=false, logStates=false, requiredFinalStates=[0.14886882881582736, 0.038462894626776434, 0.00768439894426358], merge = Map(A = [-1.0 0.0 0.0; diff --git a/test/TestFirstOrder.jl b/test/TestFirstOrder.jl index 2f3b585..1db6858 100644 --- a/test/TestFirstOrder.jl +++ b/test/TestFirstOrder.jl @@ -17,6 +17,6 @@ firstOrder = @instantiateModel(FirstOrder, logCode=false) simulate!(firstOrder, Tsit5(), stopTime = 10, log=true, requiredFinalStates = [-0.3617373025974107]) -plot(firstOrder, ["u", "x", "der(x)", "y"]) +plot(firstOrder, ["u", "x", "der(x)", "y", "T"]) end \ No newline at end of file diff --git a/test/TestFirstOrder2.jl b/test/TestFirstOrder2.jl index 56f9a2e..56a59e1 100644 --- a/test/TestFirstOrder2.jl +++ b/test/TestFirstOrder2.jl @@ -4,9 +4,6 @@ using Modia @usingModiaPlot using Modia.Test -# using RuntimeGeneratedFunctions -# RuntimeGeneratedFunctions.init(@__MODULE__) - inputSignal(t) = sin(t) FirstOrder1 = Model( From 720136e522fdfa82514045725f40be7cd187d2ec Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 29 Jun 2022 16:13:04 +0200 Subject: [PATCH 42/63] Support get_result(instantiatedModel, name), but no longer get_result(instantiatedModel) --- src/SignalTablesInterface.jl | 4 ++++ test/TestFirstOrder2.jl | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index dbf3588..512fbef 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -459,6 +459,9 @@ end function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) + error("get_result(instantiatedModel) is no longer supported") + + #= if length(m.result.t) > 1 error("Error in Modia.get_result(...), because function cannot be used for a segmenteded simulation with more as one segmented.") end @@ -493,4 +496,5 @@ function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) setEvaluatedParametersInDataFrame!(m.evaluatedParameters, m.result.info, dataFrame, "", length(timeSignal[1])) end return dataFrame + =# end \ No newline at end of file diff --git a/test/TestFirstOrder2.jl b/test/TestFirstOrder2.jl index 56a59e1..1094add 100644 --- a/test/TestFirstOrder2.jl +++ b/test/TestFirstOrder2.jl @@ -22,7 +22,8 @@ simulate!(firstOrder, Tsit5(), stopTime = 10, merge = Map(T = 0.4, x = 0.9), log=false, logParameters=true, logStates=true, requiredFinalStates = [-0.17964872595554535]) -# Test get_result(instantiatedModel) +# Test get_result(instantiatedModel) no longer supported +#= println() result1 = get_result(firstOrder) @show(result1[1:10,:]) @@ -36,6 +37,7 @@ result2 = get_result(firstOrder, onlyStates=true, extraNames=["y"]) println() result3 = get_result(firstOrder, extraNames=["y"]) @show(result3[1:10,:]) +=# # Linearize println("\n... Linearize at stopTime = 0 and 10:") @@ -51,7 +53,7 @@ xNames = get_xNames(firstOrder) @test isapprox(A_0, A_10) -plot(result1, [("u", "x"), "der(x)", "y"]) +plot(firstOrder, [("u", "x"), "der(x)", "y"]) FirstOrder3 = Model( From 4bdf9381802a4347175296a3348e35cff781f279 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Wed, 29 Jun 2022 17:28:00 +0200 Subject: [PATCH 43/63] Minor bug fix --- src/SignalTablesInterface.jl | 6 +++--- test/TestFilterCircuit.jl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index 512fbef..5aaf7b2 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -58,7 +58,7 @@ Returns a string vector of the variables of an - If var=true, Var(..) variables are included. - If par=true, Par(..) variables are included. """ -function SignalTables.signalNames(m::SimulationModel; val=true, par=true)::Vector{String} +function SignalTables.signalNames(m::SimulationModel; var=true, par=true)::Vector{String} if ismissing(m.result) error("signalNames(..): No simulation results available in instantiated model of $(m.modelName)") end @@ -101,7 +101,7 @@ Returns signal `name` of the result present in instantiatedModel (that is a [`SignalTables.Var`](@ref) or a [`SignalTables.Par`](@ref)). If `name` does not exist, an error is raised. """ -SignalTables.getSignal(m::SimulationModel, name::String) = begin +function SignalTables.getSignal(m::SimulationModel, name::String) checkMissingResult(m, name) result = m.result @@ -118,7 +118,7 @@ SignalTables.getSignal(m::SimulationModel, name::String) = begin if sigUnit == "" signal = Par(value = sigValue) else - signal = Par(value = sigValue, unit=sigUnit) + signal = Par(value = ustrip.(sigValue), unit=sigUnit) end end return signal diff --git a/test/TestFilterCircuit.jl b/test/TestFilterCircuit.jl index 0163b35..d5b6d70 100644 --- a/test/TestFilterCircuit.jl +++ b/test/TestFilterCircuit.jl @@ -28,7 +28,7 @@ showInfo(filterCircuit) # Test access functions @testset "Test variable access functions (TestFilterCircuit.jl)" begin - currentNames = signalNames(filterCircuit) + currentNames = signalNames(filterCircuit, par=false) requiredNames = String["C.i", "C.n.i", "C.n.v", "C.p.i", "C.p.v", "C.v", "R.i", "R.n.i", "R.n.v", "R.p.i", "R.p.v", "R.v", "V.i", "V.n.i", "V.n.v", "V.p.i", "V.p.v", "V.v", "C.der(v)", "ground.p.i", "ground.p.v", "time"] @test sort!(currentNames) == sort!(requiredNames) From ec7121b86191c72af43e066c6994160823fe16a1 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Thu, 30 Jun 2022 07:40:28 +0200 Subject: [PATCH 44/63] Bugs fixed --- src/CodeGeneration.jl | 57 ++++++++++++++++++++---------------- src/Result.jl | 6 ++-- src/SignalTablesInterface.jl | 2 ++ src/SimulateAndPlot.jl | 2 +- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index ecde00a..68e204b 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -974,6 +974,12 @@ setNextEvent!(m::SimulationModel{FloatType,TimeType}, nextEventTime) where {Floa setNextEvent!(m.eventHandler, convert(TimeType,nextEventTime)) +function setFullRestartEvent!(m::SimulationModel) + m.eventHandler.restart = FullRestart + return nothing +end + + """ tCurrent = getTime(instantiatedModel) @@ -1049,7 +1055,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti m.equationInfo = deepcopy(m.initialEquationInfo) equationInfo = m.equationInfo eh = m.eventHandler - m.instantiateFunctions = Tuple{Any,String}[] + m.instantiateFunctions = Tuple{Union{Expr,Symbol}, OrderedDict{Symbol,Any}, String}[] m.nsegments = 1 m.result = Result{FloatType,TimeType}(m.equationInfo, m.timeName, m.w_invariant_names, m.vEliminated, m.vProperty, m.var_name) result = m.result @@ -1152,22 +1158,23 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where m.nsegments += 1 m.options.startTime = m.time reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) - newResultSegment!(m.result) + newResultSegment!(m.result, m.equationInfo, m.nsegments) # Evaluate instantiate functions - for fc in m.instantiatedFunctions + for fc in m.instantiateFunctions logInstantiatedFunctionCalls = false Core.eval(m.modelModule, :($(fc[1])($m, $(fc[2]), $(fc[3]), log=$logInstantiatedFunctionCalls))) end # Get initial state vector - m.x_start = initialStateVector!(m.equationInfo, m.result, FloatType) + m.x_start = initialStateVector!(m.equationInfo, FloatType) # update equationInfo - for i = m.equationInfo.nx_info_invariant+1:length(m.equationInfo.x_info) + x_info = m.equationInfo.x_info + for i = m.equationInfo.nx_info_invariant+1:length(x_info) xi_info = x_info[i] resInfo = m.result.info[xi_info.x_name] - id = ValuesID(nsegments, xi_info.startIndex, size(xi_info.startOrInit)) + id = ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) push!(resInfo.id, ) resInfo = m.result.info[xi_info.der_x_name] push!(resInfo.id, id) @@ -1461,6 +1468,9 @@ function affectEvent!(integrator, stateEvent::Bool, eventIndex::Int)::Nothing eh.nTimeEvents += 1 end +if eh.nStateEvents > 20 + error("too many state events") +end # Event iteration eventIteration!(m, integrator.u, time) @@ -1473,8 +1483,8 @@ function affectEvent!(integrator, stateEvent::Bool, eventIndex::Int)::Nothing else printstyled(" restart = ", eh.restart, "\n", color=:red) end - end - + end + # Compute outputs and store them after the event occurred if m.addEventPointsDueToDEBug push!(integrator.sol.t, deepcopy(integrator.t)) @@ -1482,7 +1492,7 @@ function affectEvent!(integrator, stateEvent::Bool, eventIndex::Int)::Nothing end outputs!(integrator.u, time, integrator) - if eh.restart == Terminate + if eh.restart == Terminate || eh.restart == FullRestart DifferentialEquations.terminate!(integrator) return nothing end @@ -1657,21 +1667,19 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam if haskey(result.info, x_name) # State was already defined in one of the previous segments new_result_info = false - x_info = result.info[x_name] - xi_info = eqInfo.x_info[ eqInfo.x_dict[x_name] ] + x_info = result.info[x_name] @assert(x_info.kind == RESULT_X) @assert(basetype(startOrInit) == FloatType) - if typeof(startOrInit) <: Number - @assert(xi_info.scalar) - elseif typeof(startOrInit) <: AbstractVector - @assert(!xi_info.scalar) - else - error("new_x_segmented_variable(.. $x_name, $der_x_name, startOrInit,...): typeof(startOrInit) is neither a Number nor an AbstractVector)") - end - @assert(xi_info.unit == x_unit) - - @assert(haskey(result.info, der_x_name)) - @assert(eqInfo.der_x_dict, der_x_name) + @assert(length( x_info.id[end].dims ) == ndims(startOrInit)) # Number of dimensions cannot change + #if typeof(startOrInit) <: Number + # @assert(xi_info.scalar) + #elseif typeof(startOrInit) <: AbstractVector + # @assert(!xi_info.scalar) + #else + # error("new_x_segmented_variable(.. $x_name, $der_x_name, startOrInit,...): typeof(startOrInit) is neither a Number nor an AbstractVector)") + #end + @assert(x_info.signal[:unit] == x_unit) + @assert(haskey(result.info, der_x_name)) der_x_info = result.info[der_x_name] @assert(der_x_info.kind == RESULT_DER_X) end @@ -1726,9 +1734,8 @@ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented if haskey(result.info, name) # Variable was already defined in one of the previous segments v_info = result.info[name] - @assert(!haskey(result.w_segmented_names, name)) @assert(v_info.kind == RESULT_W_SEGMENTED) - w_unit = get(v_info, :unit, "") + w_unit = get(v_info.signal, :unit, "") if w_unit != unit error("Variable $name changed unit from \"$w_unit\" to \"$unit\".") end @@ -1825,7 +1832,7 @@ end Copy scalar or array segmented state derivative value `der_x_segmented_value` into `instantiatedModel` starting at index `startIndex` (returned from `new_x_segmented_variable!(..)`). """ -@inline function add_der_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segmented::FloatType)::Nothing where {FloatType,TimeType} +@inline function add_der_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segmented_value::FloatType)::Nothing where {FloatType,TimeType} m.der_x_segmented[startIndex] = der_x_segmented_value return nothing end diff --git a/src/Result.jl b/src/Result.jl index 8c36f22..78190d2 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -170,7 +170,7 @@ end """ - newResultSegment!(result, equationInfo) + newResultSegment!(result, equationInfo, nsegments) Start a new result segment. """ @@ -180,6 +180,7 @@ function newResultSegment!(result::Result{FloatType,TimeType}, equationInfo::Equ empty!(result.w_segmented_temp) # Update id's for x_segmented and der_x_segmented + #= eqInfo = equationInfo x_info = eqInfo.x_info resultInfo = result.info @@ -191,7 +192,8 @@ function newResultSegment!(result::Result{FloatType,TimeType}, equationInfo::Equ resInfo = resultInfo[xi_info.der_x_name] push!(resInfo.id, ValuesID(nsegments, resInfo.startIndex, size(resInfo.startOrInit))) end - + =# + # Start new segment push!(result.t , TimeType[]) push!(result.x , Vector{FloatType}[]) diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index 5aaf7b2..7b44b35 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -126,6 +126,8 @@ end function SignalTables.getSignal(result::Result, name::String) resInfo = result.info[name] + @show name + @show resInfo if haskey(resInfo.signal, :values) return resInfo.signal end diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index e2bb0e0..68ceeaf 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -255,7 +255,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me end # Re-initialize model for FullRestart - + initFullRestart!(m) end # --------------------------------------------------------- End of core simulation loop ------------------------------ disable_timer!(m.timer) From 6e08460eb727ae4cd7a73c330c8fa8129923c666 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 1 Jul 2022 09:18:28 +0200 Subject: [PATCH 45/63] Fix bugs --- src/CodeGeneration.jl | 2 +- src/Modia.jl | 2 +- src/Result.jl | 128 ++++++++++++++++------------------- src/SignalTablesInterface.jl | 15 ++-- 4 files changed, 67 insertions(+), 80 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 68e204b..b4c0ba1 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1175,7 +1175,7 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where xi_info = x_info[i] resInfo = m.result.info[xi_info.x_name] id = ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) - push!(resInfo.id, ) + push!(resInfo.id, id) resInfo = m.result.info[xi_info.der_x_name] push!(resInfo.id, id) end diff --git a/src/Modia.jl b/src/Modia.jl index df77e0e..6e1da5b 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-06-29" +const Date = "2022-07-01" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/src/Result.jl b/src/Result.jl index 78190d2..2a23a6f 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -75,10 +75,10 @@ mutable struct ResultInfo _basetype # If known, basetype(signal.values/.values); if not known: Nothing value::Any # Value of constant variable (without unit) - ResultInfo(kind::ResultKind, signal, _basetype) = new(kind , signal, "" , false , ValuesID[] , _basetype) - ResultInfo(kind::ResultKind, signal, id::ValuesID, _basetype) = new(kind , signal, "" , false , ValuesID[id], _basetype) + ResultInfo(kind::ResultKind, signal, _basetype) = new(kind , signal, "" , false , ValuesID[] , _basetype, nothing) + ResultInfo(kind::ResultKind, signal, id::ValuesID, _basetype) = new(kind , signal, "" , false , ValuesID[id], _basetype, nothing) ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[] , basetype(value), value) - ResultInfo(signal::SignalTables.SymbolDictType, aliasName::String, aliasNegate::Bool) = new(RESULT_ELIMINATED, signal, aliasName, aliasNegate) + ResultInfo(signal::SignalTables.SymbolDictType, aliasName::String, aliasNegate::Bool) = new(RESULT_ELIMINATED, signal, aliasName, aliasNegate, ValuesID[], Nothing, nothing) end @@ -98,6 +98,7 @@ mutable struct Result{FloatType,TimeType} w_segmented_names::OrderedSet{String} # Names of w_segmented results in current segment w_segmented_temp::Vector{Any} # Memory to store temporarily references to w_segmented results in current segment # length(w_segmented_temp) = length(w_segmented_names) + firstIndexOfSegment::Vector{Int} # firstIndexOfSegment[sk] is the first index of the "expanded" time vector of segment sk t::Vector{Vector{TimeType}} # t[sk][ti] is time instant ti in segment sk # A variable v[sk][ti][j] is variable with index j at time instant ti in segment sk @@ -111,7 +112,7 @@ mutable struct Result{FloatType,TimeType} n_w_invariant = length(w_invariant_names) alias_segmented_names = OrderedSet{String}() w_segmented_names = OrderedSet{String}() - w_segmented_temp = Any[] + w_segmented_temp = Any[] t = fill(TimeType[],1) x = fill(Vector{FloatType}[], 1) der_x = fill(Vector{FloatType}[], 1) @@ -119,6 +120,7 @@ mutable struct Result{FloatType,TimeType} w_segmented = fill(Vector{Any}[], 1) # Fill info with time + firstIndexOfSegment = Int[1] timeResultInfo = ResultInfo(RESULT_T, Var(unit="s", independent=true), ValuesID(1,()), TimeType) info[timeNameAsString] = timeResultInfo @@ -164,7 +166,8 @@ mutable struct Result{FloatType,TimeType} end end - new(info, timeNameAsString, timeResultInfo, n_w_invariant, alias_segmented_names, w_segmented_names, w_segmented_temp, t, x, der_x, w_invariant, w_segmented) + new(info, timeNameAsString, timeResultInfo, n_w_invariant, alias_segmented_names, w_segmented_names, w_segmented_temp, + firstIndexOfSegment, t, x, der_x, w_invariant, w_segmented) end end @@ -172,29 +175,16 @@ end """ newResultSegment!(result, equationInfo, nsegments) -Start a new result segment. +Start a new result segment (nsegments > 1) """ function newResultSegment!(result::Result{FloatType,TimeType}, equationInfo::EquationInfo, nsegments::Int)::Nothing where {FloatType,TimeType} + @assert(nsegments > 1) empty!(result.alias_segmented_names) empty!(result.w_segmented_names) empty!(result.w_segmented_temp) - # Update id's for x_segmented and der_x_segmented - #= - eqInfo = equationInfo - x_info = eqInfo.x_info - resultInfo = result.info - @assert(eqInfo.status == EquationInfo_After_All_States_Are_Known) - for i = eqInfo.nx_info_invariant+1:length(x_info) - xi_info = x_info[i] - resInfo = resultInfo[xi_info.x_name] - push!(resInfo.id, ValuesID(nsegments, resInfo.startIndex, size(resInfo.startOrInit))) - resInfo = resultInfo[xi_info.der_x_name] - push!(resInfo.id, ValuesID(nsegments, resInfo.startIndex, size(resInfo.startOrInit))) - end - =# - # Start new segment + push!(result.firstIndexOfSegment, result.firstIndexOfSegment[end] + length(result.t[end])) push!(result.t , TimeType[]) push!(result.x , Vector{FloatType}[]) push!(result.der_x , Vector{FloatType}[]) @@ -213,13 +203,13 @@ dims_range(dims::Dims) = Tuple([1:i for i in dims]) Return a Var() values vector from independent values t, dependent values s, and resultInfo. """ -function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::ResultInfo; log=false, name::AbstractString="") +function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::ResultInfo, result::Result; log=false, name::AbstractString="") id = resultInfo.id @assert(length(id) > 0) inlineValues = resultInfo.kind == RESULT_X || resultInfo.kind == RESULT_DER_X _basetype = resultInfo._basetype ndims_s = length(id[1].dims) - if length(id) == 1 && ndims_s == 0 + if id[1].segment == -1 && ndims_s == 0 # Scalar signal that is defined in every segment index = id[1].index sc = _basetype[ustrip.(ti[index]) for sk in s for ti in sk] @@ -227,7 +217,8 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re else # Find largest dims = dimsMax in all segments dimsMax::Dims{ndims_s} = id[1].dims - hasMissing::Bool = !(length(id) == 1 || length(id) == length(t)) + invariant::Bool = id[1].segment==-1 # = true, if variable is defined at all time instants and variable index does not change + hasMissing::Bool = !(invariant || length(id) == length(t)) # = true, if at least one variable value is not defined at all time instants if length(id) > 1 dMax::Vector{Int} = [dimsMax...] for i = 2:length(id) @@ -257,73 +248,70 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re sc = Array{_basetype, length(dims)}(undef, dims) end - # Copy subset of s-values to target sc - invariant = length(id) == 1 - segmentOld = 1 + # Copy subset of s-values to target sc j = 1 + firstIndexOfSegment = result.firstIndexOfSegment if length(dimsMax) == 0 # Target is a scalar signal - if invariant - index = id[1].index - end - for k = 1:length(s) - if !invariant - index = id[k].index - segment = id[k].segment - if segmentOld < segment-1 - j = sum(length(t[i]) for i = segmentOld:segment-1) + 1 - segmentOld = segment - end - end - for s_ti in s[k] + @assert(id[1].segment != -1) + for id_k in resultInfo.id + index = id_k.index + segment = id_k.segment + j = firstIndexOfSegment[segment] + for s_ti in s[segment] sc[j] = s_ti[index] j += 1 end end else # Target is not a scalar signal setindex!(A,x,(2,2:4)...) - if inlineValues + j = 1 + if inlineValues if invariant dims = id[1].dims dimr = dims_range(dims) ibeg = id[1].index iend = ibeg + prod(dims) - 1 - end - for k = 1:length(s) - if !invariant - dims = id[k].dims - dimr = dims_range(dims) - ibeg = id[k].index - iend = ibeg + prod(dims) - 1 - segment = id[k].segment - if segmentOld < segment-1 - j = sum(length(t[i]) for i = segmentOld:segment-1) + 1 - segmentOld = segment + for sk in s + for s_ti in sk + setindex!(sc, reshape(view(s_ti,ibeg:iend),dims), (j,dimr...)...) + j += 1 + end + end + else + for id_k in resultInfo.id + dims = id_k.dims + dimr = dims_range(dims) + ibeg = id_k.index + iend = ibeg + prod(dims) - 1 + segment = id_k.segment + j = firstIndexOfSegment[segment] + for s_ti in s[segment] + setindex!(sc, reshape(view(s_ti,ibeg:iend),dims), (j,dimr...)...) + j += 1 end - end - for s_ti in s[k] - setindex!(sc, reshape(view(s_ti,ibeg:iend),dims), (j,dimr...)...) - j += 1 end end else if invariant index = id[1].index - dimr = dims_range( size(s[1][1][index]) ) - end - for k = 1:length(s) - if !invariant - index = id[k].index - dimr = dims_range( size(s[k][1][index]) ) - segment = id[k].segment - if segmentOld < segment-1 - j = sum(length(t[i]) for i = segmentOld:segment-1) + 1 - segmentOld = segment - end + dimr = dims_range(id_k.dims) + for sk in s + for s_ti in sk + setindex!(sc, ustrip.(s_ti[index]), (j,dimr...)...) + j += 1 + end end - for s_ti in s[k] - setindex!(sc, ustrip.(s_ti[index]), (j,dimr...)...) - j += 1 + else + for id_k in resultInfo.id + index = id_k.index + dimr = dims_range(id_k.dims) + segment = id_k.segment + j = firstIndexOfSegment[segment] + for s_ti in s[segment] + setindex!(sc, ustrip.(s_ti[index]), (j,dimr...)...) + j += 1 + end end end end diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index 7b44b35..f5cae48 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -126,8 +126,7 @@ end function SignalTables.getSignal(result::Result, name::String) resInfo = result.info[name] - @show name - @show resInfo + if haskey(resInfo.signal, :values) return resInfo.signal end @@ -148,11 +147,11 @@ function SignalTables.getSignal(result::Result, name::String) end if resInfo.kind == RESULT_T - sigValues = signalResultValues(result.t, result.t, resInfo; name=name) - elseif resInfo.kind == RESULT_X - sigValues = signalResultValues(result.t, result.x, resInfo; name=name) + sigValues = signalResultValues(result.t, result.t, resInfo, result; name=name) + elseif resInfo.kind == RESULT_X + sigValues = signalResultValues(result.t, result.x, resInfo, result; name=name) elseif resInfo.kind == RESULT_DER_X - sigValues = signalResultValues(result.t, result.der_x, resInfo; name=name) + sigValues = signalResultValues(result.t, result.der_x, resInfo, result; name=name) elseif resInfo.kind == RESULT_W_INVARIANT index = resInfo.id[1].index w_value = result.w_invariant[1][1][index] @@ -168,9 +167,9 @@ function SignalTables.getSignal(result::Result, name::String) resInfo.id[1] = ValuesID(index, size(w_value)) resInfo._basetype = basetype(w_value) - sigValues = signalResultValues(result.t, result.w_invariant, resInfo; name=name) + sigValues = signalResultValues(result.t, result.w_invariant, resInfo, result; name=name) elseif resInfo.kind == RESULT_W_SEGMENTED - sigValues = signalResultValues(result.t, result.w_segmented, resInfo; name=name) + sigValues = signalResultValues(result.t, result.w_segmented, resInfo, result; name=name) elseif resInfo.kind == RESULT_CONSTANT value = resInfo.value t = getSignal(result, result.timeName)[:values] From 9b585c591be33d2947a6d816fc833a51571b77e1 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 1 Jul 2022 11:29:05 +0200 Subject: [PATCH 46/63] Bugs fixed --- src/Result.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Result.jl b/src/Result.jl index 2a23a6f..bbd5c48 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -295,7 +295,7 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re else if invariant index = id[1].index - dimr = dims_range(id_k.dims) + dimr = dims_range(id[1].dims) for sk in s for s_ti in sk setindex!(sc, ustrip.(s_ti[index]), (j,dimr...)...) From 658e10343c174c3569015d7aedcb7c57292c801e Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 1 Jul 2022 11:47:54 +0200 Subject: [PATCH 47/63] Bugs fixed --- src/CodeGeneration.jl | 7 ++----- src/EquationAndStateInfo.jl | 10 ++++++++++ src/Result.jl | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index b4c0ba1..46de851 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1078,8 +1078,8 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti for xi_info in equationInfo.x_info resInfo = result.info[xi_info.x_name] resInfo.signal[:start] = xi_info.startOrInit - id = ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) - x_type = + id = xi_info.x_segmented_startIndex == -1 ? ValuesID( -1, xi_info.startIndex, size(xi_info.startOrInit)) : + ValuesID(m.nsegments, xi_info.startIndex, size(xi_info.startOrInit)) push!(resInfo.id, id) resInfo = result.info[xi_info.der_x_name] push!(resInfo.id, id) @@ -1468,9 +1468,6 @@ function affectEvent!(integrator, stateEvent::Bool, eventIndex::Int)::Nothing eh.nTimeEvents += 1 end -if eh.nStateEvents > 20 - error("too many state events") -end # Event iteration eventIteration!(m, integrator.u, time) diff --git a/src/EquationAndStateInfo.jl b/src/EquationAndStateInfo.jl index cf02825..472b90f 100644 --- a/src/EquationAndStateInfo.jl +++ b/src/EquationAndStateInfo.jl @@ -808,6 +808,16 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa @assert(eqInfo.nx == startIndex - 1) eqInfo.status = EquationInfo_After_All_States_Are_Known + + # Final check + for (i, xi_info) = enumerate(eqInfo.x_info) + @assert(xi_info.startIndex > 0) + if i <= eqInfo.nx_info_invariant + @assert(xi_info.x_segmented_startIndex == -1) + else + @assert(xi_info.x_segmented_startIndex > 0) + end + end return x_start end diff --git a/src/Result.jl b/src/Result.jl index bbd5c48..e8f60c5 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -260,7 +260,7 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re j = firstIndexOfSegment[segment] for s_ti in s[segment] sc[j] = s_ti[index] - j += 1 + j += 1inclu end end else From 053404a69fd3d9b9fa4b9f2fe0954283e0c54994 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 1 Jul 2022 11:58:33 +0200 Subject: [PATCH 48/63] Bug fixed --- src/Result.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Result.jl b/src/Result.jl index e8f60c5..bbd5c48 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -260,7 +260,7 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re j = firstIndexOfSegment[segment] for s_ti in s[segment] sc[j] = s_ti[index] - j += 1inclu + j += 1 end end else From 929e6a5bb29b87b19b3539947a0821ebc475ebb1 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 1 Jul 2022 12:42:53 +0200 Subject: [PATCH 49/63] Bugs fixed --- src/SimulateAndPlot.jl | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 68ceeaf..f16f977 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -194,7 +194,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me m.options = options m.time = options.startTime m.isInitial = true - m.nsegments = 1 + m.nsegments = 1 reinitEventHandler!(m.eventHandler, m.options.stopTime, m.options.logEvents) if ismissing(algorithm) && FloatType == Float64 @@ -381,7 +381,19 @@ function simulateSegment!(m::SimulationModel{FloatType,TimeType}, algorithm=miss interval = 1.0 tspan2 = [m.options.startTime] elseif abs(m.options.interval) < abs(m.options.stopTime-m.options.startTime) - tspan2 = m.options.startTime:m.options.interval:m.options.stopTime + if m.nsegments == 1 + tspan2 = m.options.startTime:interval:m.options.stopTime + else + i = ceil( (m.options.startTime - m.options.startTimeFirstSegment)/interval ) + tnext = m.options.startTimeFirstSegment + i*interval + tspan2 = tnext:interval:m.options.stopTime + if tspan2[1] > m.options.startTime + tspan2 = [m.options.startTime, tspan2...] + end + end + if tspan2[end] < m.options.stopTime + tspan2 = [tspan2..., m.options.stopTime] + end else tspan2 = [m.options.startTime, m.options.stopTime] end From 382113dbf09298646bfc8408dfa629ee03248839 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Fri, 1 Jul 2022 14:35:47 +0200 Subject: [PATCH 50/63] Minor bug fix --- src/Result.jl | 7 +++++++ src/SimulateAndPlot.jl | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Result.jl b/src/Result.jl index bbd5c48..4c8953c 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -82,6 +82,13 @@ mutable struct ResultInfo end +""" + nResults(result::Result) + +Returns the number of result points (= number of values of time vector). +""" +nResults(result::Result) = result.firstIndexOfSegment[end] + length(result.t[end]) - 1 + """ result = Result{FloatType,TimeType}(timeNameAsString, equationInfo, w_invariant_names, w_invariant_initial, vEliminated, vProperty, var_name) diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index f16f977..653ac89 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -278,7 +278,7 @@ function simulate!(m::SimulationModel{FloatType,TimeType}, algorithm=missing; me println(" linearSystemSizes = ", Int[length(leq.b) for leq in m.linearEquations]) println(" useRecursiveFactorization = ", useRecursiveFactorization) println(" odeModeLinearSystems = ", Bool[leq.odeMode for leq in m.linearEquations]) - println(" nResults = ", length(m.result.t[end])) + println(" nResults = ", nResults(m.result)) println(" nGetDerivatives = ", m.nGetDerivatives, " (total number of getDerivatives! calls)") println(" nf = ", m.nf, " (number of getDerivatives! calls from integrator)") # solution.destats.nf println(" nZeroCrossings = ", eh.nZeroCrossings, " (number of getDerivatives! calls for zero crossing detection)") From 928444ff360e824e09ad341c81ef8604caff8482 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sat, 2 Jul 2022 06:39:14 +0200 Subject: [PATCH 51/63] New function get_x_startIndex_from_x_segmented_startIndex (needed by Modia3D) --- src/CodeGeneration.jl | 34 ++++++++++++++++++++++++---------- src/Modia.jl | 2 +- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 46de851..3a408e5 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1644,16 +1644,20 @@ end """ - startIndex = new_x_segmented_variable!(instantiatedModel::SimulationModel, - x_name::String, der_x_name::String, startOrInit, x_unit::String=""; - nominal::Float64 = NaN, unbounded::Bool = false)::Int - -Reserve storage location for a new x_segmented and der_x_segmented variable. The returned startIndex is used - -- to copy state values from instantiatedModel.x_segmented[startIndex:startIndex+prod(dims(startOrInit))-1] into the internal states -- to copy internal state derivative values to instantiatedModel.der_x_segmented[startIndex:startIndex+prod(dims(startOrInit))-1] - -Value startOrInit is the start/init value used during re-initialization of the new segmented with initFullRestart!(..). + index = new_x_segmented_variable!( + instantiatedModel::SimulationModel, + x_name::String, der_x_name::String, startOrInit, x_unit::String=""; + nominal::Float64 = NaN, unbounded::Bool = false)::Int + +Reserves storage location for a new x_segmented and der_x_segmented variable and returns +the index (= x_segmented_startIndex) to access this storage location, in particular + +- to copy state values from instantiatedModel.x_segmented[index:index+prod(dims(startOrInit))-1] + into this storage location +- to copy state derivative values of this storage location to + instantiatedModel.der_x_segmented[index:index+prod(dims(startOrInit))-1] + +Value startOrInit is the start/init value used during re-initialization of the new segment with initFullRestart!(..). """ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; nominal::Float64 = NaN, unbounded::Bool = false)::Int where {FloatType,TimeType} @@ -1712,6 +1716,16 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam end +""" + x_startIndex = get_x_startIndex_from_x_segmented_startIndex(instantiatedModel::SimulationModel, x_segmented_startIndex) + +Return the startindex of an x_segmented state with respect to the x-vector, +given the startIndex with respect to the x_segmented vector +(x_segmented_startIndex is the return value of new_x_segmented_variable!(..)). +""" +get_x_startIndex_from_x_segmented_startIndex(m::SimulationModel, x_segmented_startIndex::Int) = m.equationInfo.nxInvariant + x_segmented_startIndex + + """ index = new_w_segmented_variable!(partiallyInstantiatedModel::SimulationModel, name::String, w_segmented_default, unit::String="")::Int diff --git a/src/Modia.jl b/src/Modia.jl index 6e1da5b..2434802 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-07-01" +const Date = "2022-07-02" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") From bc25470f1231d6614524ebe08d2c91ec1b95e4c9 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sat, 2 Jul 2022 07:08:14 +0200 Subject: [PATCH 52/63] Fixes a bug and requires DiffEqBase of at least version 6.92.2 to get rid of the potential StackOverflowError (https://github.com/SciML/DiffEqBase.jl/issues/784) --- Manifest.toml | 88 +++++++++++++++++++++++++-------------------------- Project.toml | 5 ++- src/Result.jl | 16 +++++----- 3 files changed, 54 insertions(+), 55 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 7462ac0..3c73c42 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -20,21 +20,21 @@ version = "0.2.0" [[deps.ArrayInterface]] deps = ["ArrayInterfaceCore", "Compat", "IfElse", "LinearAlgebra", "Static"] -git-tree-sha1 = "1d062b8ab719670c16024105ace35e6d32988d4f" +git-tree-sha1 = "6ccb71b40b04ad69152f1f83d5925de13911417e" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "6.0.18" +version = "6.0.19" [[deps.ArrayInterfaceCore]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "5e732808bcf7bbf730e810a9eaafc52705b38bb5" +git-tree-sha1 = "7d255eb1d2e409335835dc8624c35d97453011eb" uuid = "30b0a656-2188-435a-8636-2ec0e6a096e2" -version = "0.1.13" +version = "0.1.14" [[deps.ArrayInterfaceGPUArrays]] deps = ["Adapt", "ArrayInterfaceCore", "GPUArraysCore", "LinearAlgebra"] -git-tree-sha1 = "02ec61006f49c43607a34cbd036b3d68485d38aa" +git-tree-sha1 = "febba7add2873aecc0b6620b55969e73ec875bce" uuid = "6ba088a2-8465-4c0a-af30-387133b534db" -version = "0.2.0" +version = "0.2.1" [[deps.ArrayInterfaceOffsetArrays]] deps = ["ArrayInterface", "OffsetArrays", "Static"] @@ -103,9 +103,9 @@ version = "0.5.1" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "9489214b993cd42d17f44c36e359bf6a7c919abf" +git-tree-sha1 = "2dd813e5f2f7eec2d1268c57cf2373d3ee91fcea" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.15.0" +version = "1.15.1" [[deps.ChangesOfVariables]] deps = ["ChainRulesCore", "LinearAlgebra", "Test"] @@ -142,9 +142,9 @@ uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" [[deps.ConstructionBase]] deps = ["LinearAlgebra"] -git-tree-sha1 = "f74e9d5388b8620b4cee35d4c5a618dd4dc547f4" +git-tree-sha1 = "c096d0e321368ac23eb1be1ea405814f8b32adb3" uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" -version = "1.3.0" +version = "1.3.1" [[deps.CpuId]] deps = ["Markdown"] @@ -201,9 +201,9 @@ version = "0.4.0" [[deps.DiffEqBase]] deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "ab123ea2e24d20140b284413bff63e80ea976626" +git-tree-sha1 = "9862c61c6049b0ad5a6b433e31d2c6c8ff373056" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.92.0" +version = "6.92.2" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] @@ -211,12 +211,6 @@ git-tree-sha1 = "cfef2afe8d73ed2d036b0e4b14a3f9b53045c534" uuid = "459566f4-90b8-5000-8ac3-15dfb0a30def" version = "2.23.1" -[[deps.DiffEqJump]] -deps = ["ArrayInterfaceCore", "DataStructures", "DiffEqBase", "DocStringExtensions", "FunctionWrappers", "Graphs", "LinearAlgebra", "Markdown", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "StaticArrays", "TreeViews", "UnPack"] -git-tree-sha1 = "760a048fc34902bfd1b1e4ac4b67162da1f74972" -uuid = "c894b116-72e5-5b58-be3c-e6d8d4ac2b12" -version = "8.6.2" - [[deps.DiffEqNoiseProcess]] deps = ["DiffEqBase", "Distributions", "GPUArraysCore", "LinearAlgebra", "Markdown", "Optim", "PoissonRandom", "QuadGK", "Random", "Random123", "RandomNumbers", "RecipesBase", "RecursiveArrayTools", "ResettableStacks", "SciMLBase", "StaticArrays", "Statistics"] git-tree-sha1 = "6f3fe6ebe1b6e6e3a9b72739ada313aa17c9bb66" @@ -236,10 +230,10 @@ uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" version = "1.11.0" [[deps.DifferentialEquations]] -deps = ["BoundaryValueDiffEq", "DelayDiffEq", "DiffEqBase", "DiffEqCallbacks", "DiffEqJump", "DiffEqNoiseProcess", "LinearAlgebra", "LinearSolve", "OrdinaryDiffEq", "Random", "RecursiveArrayTools", "Reexport", "SteadyStateDiffEq", "StochasticDiffEq", "Sundials"] -git-tree-sha1 = "3f3db9365fedd5fdbecebc3cce86dfdfe5c43c50" +deps = ["BoundaryValueDiffEq", "DelayDiffEq", "DiffEqBase", "DiffEqCallbacks", "DiffEqNoiseProcess", "JumpProcesses", "LinearAlgebra", "LinearSolve", "OrdinaryDiffEq", "Random", "RecursiveArrayTools", "Reexport", "SteadyStateDiffEq", "StochasticDiffEq", "Sundials"] +git-tree-sha1 = "0ccc4356a8f268d5eee641f0944074560c45267a" uuid = "0c46a032-eb83-5123-abaf-570d42b7fbaa" -version = "7.1.0" +version = "7.2.0" [[deps.Distances]] deps = ["LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI"] @@ -253,9 +247,9 @@ uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" [[deps.Distributions]] deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] -git-tree-sha1 = "0ec161f87bf4ab164ff96dfacf4be8ffff2375fd" +git-tree-sha1 = "d530092b57aef8b96b27694e51c575b09c7f0b2e" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.62" +version = "0.25.64" [[deps.DocStringExtensions]] deps = ["LibGit2"] @@ -411,6 +405,12 @@ git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" version = "0.21.3" +[[deps.JumpProcesses]] +deps = ["ArrayInterfaceCore", "DataStructures", "DiffEqBase", "DocStringExtensions", "FunctionWrappers", "Graphs", "LinearAlgebra", "Markdown", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "StaticArrays", "TreeViews", "UnPack"] +git-tree-sha1 = "4aa139750616fee7216ddcb30652357c60c3683e" +uuid = "ccbc3e58-028d-4f4c-8cd5-9ae44345cda5" +version = "9.0.1" + [[deps.KLU]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse_jll"] git-tree-sha1 = "cae5e3dfd89b209e01bcd65b3a25e74462c67ee0" @@ -472,9 +472,9 @@ uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [[deps.LinearSolve]] deps = ["ArrayInterfaceCore", "DocStringExtensions", "GPUArraysCore", "IterativeSolvers", "KLU", "Krylov", "KrylovKit", "LinearAlgebra", "RecursiveFactorization", "Reexport", "SciMLBase", "Setfield", "SparseArrays", "SuiteSparse", "UnPack"] -git-tree-sha1 = "b3e7461184bd748e5dee98f9b11766be39634fae" +git-tree-sha1 = "c08c4177cc7edbf42a92f08a04bf848dde73f0b9" uuid = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" -version = "1.19.0" +version = "1.20.0" [[deps.LogExpFunctions]] deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] @@ -573,9 +573,9 @@ version = "0.3.20" [[deps.OffsetArrays]] deps = ["Adapt"] -git-tree-sha1 = "ec2e30596282d722f018ae784b7f44f3b88065e4" +git-tree-sha1 = "1ea784113a6aa054c5ebd95945fa5e52c2f378e7" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.12.6" +version = "1.12.7" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] @@ -604,9 +604,9 @@ version = "1.4.1" [[deps.OrdinaryDiffEq]] deps = ["Adapt", "ArrayInterface", "ArrayInterfaceGPUArrays", "ArrayInterfaceStaticArrays", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "e92f136d8961446ea0cf1f46bc6335654d49fa8c" +git-tree-sha1 = "062f233b13f04aa942bd3ca831791280f57874a3" uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -version = "6.18.0" +version = "6.18.1" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] @@ -776,9 +776,9 @@ version = "0.6.33" [[deps.SciMLBase]] deps = ["ArrayInterfaceCore", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "RecipesBase", "RecursiveArrayTools", "StaticArraysCore", "Statistics", "Tables", "TreeViews"] -git-tree-sha1 = "6a3f7d9b084b508e87d12135de950ac969187954" +git-tree-sha1 = "3243a883fa422a0a5cfe2d3b6ea6287fc396018f" uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -version = "1.42.0" +version = "1.42.2" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" @@ -832,9 +832,9 @@ version = "2.1.6" [[deps.Static]] deps = ["IfElse"] -git-tree-sha1 = "11f1b69a28b6e4ca1cc18342bfab7adb7ff3a090" +git-tree-sha1 = "46638763d3a25ad7818a15d441e0c3446a10742d" uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -version = "0.7.3" +version = "0.7.5" [[deps.StaticArrays]] deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] @@ -843,9 +843,9 @@ uuid = "90137ffa-7385-5640-81b9-e52037218182" version = "1.5.0" [[deps.StaticArraysCore]] -git-tree-sha1 = "6edcea211d224fa551ec8a85debdc6d732f155dc" +git-tree-sha1 = "66fe9eb253f910fe8cf161953880cfdaef01cdf0" uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" -version = "1.0.0" +version = "1.0.1" [[deps.Statistics]] deps = ["LinearAlgebra", "SparseArrays"] @@ -859,9 +859,9 @@ version = "1.4.0" [[deps.StatsBase]] deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "642f08bf9ff9e39ccc7b710b2eb9a24971b52b1a" +git-tree-sha1 = "48598584bacbebf7d30e20880438ed1d24b7c7d6" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.33.17" +version = "0.33.18" [[deps.StatsFuns]] deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] @@ -876,16 +876,16 @@ uuid = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f" version = "1.8.0" [[deps.StochasticDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqJump", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "fea4cc29ff7d392ceb29bb64a717e6ed128bb5ff" +deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "JumpProcesses", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] +git-tree-sha1 = "fbefdd80ccbabf9d7c402dbaf845afde5f4cf33d" uuid = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" -version = "6.49.1" +version = "6.50.0" [[deps.StrideArraysCore]] deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "SIMDTypes", "Static", "ThreadingUtilities"] -git-tree-sha1 = "367989c5c0c856fdf7e7f6577b384e63104fb854" +git-tree-sha1 = "ac730bd978bf35f9fe45daa0bd1f51e493e97eb4" uuid = "7792a7ef-975c-4747-a70f-980b88e8d1da" -version = "0.3.14" +version = "0.3.15" [[deps.SuiteSparse]] deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] @@ -975,9 +975,9 @@ version = "1.11.0" [[deps.VectorizationBase]] deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static"] -git-tree-sha1 = "0453988844dd8ded9d63b3cdfe9e4e26b062c396" +git-tree-sha1 = "9d87c8c1d27dc20ba8be6bdca85d36556c371172" uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" -version = "0.21.37" +version = "0.21.38" [[deps.VertexSafeGraphs]] deps = ["Graphs"] diff --git a/Project.toml b/Project.toml index 5d75e84..6050db5 100644 --- a/Project.toml +++ b/Project.toml @@ -4,6 +4,7 @@ uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e" version = "0.9.0-dev" [compat] +DiffEqBase = "6.92.2" DataFrames = "1" DifferentialEquations = "7" FiniteDiff = "2" @@ -21,9 +22,9 @@ Sundials = "4" TimerOutputs = "0.5" Unitful = "1" julia = "1.7" -DiffEqBase = "6.91.7" [deps] +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" @@ -45,7 +46,5 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" - [extras] CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" diff --git a/src/Result.jl b/src/Result.jl index 4c8953c..50e1730 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -82,14 +82,6 @@ mutable struct ResultInfo end -""" - nResults(result::Result) - -Returns the number of result points (= number of values of time vector). -""" -nResults(result::Result) = result.firstIndexOfSegment[end] + length(result.t[end]) - 1 - - """ result = Result{FloatType,TimeType}(timeNameAsString, equationInfo, w_invariant_names, w_invariant_initial, vEliminated, vProperty, var_name) @@ -179,6 +171,14 @@ mutable struct Result{FloatType,TimeType} end +""" + nResults(result::Result) + +Returns the number of result points (= number of values of time vector). +""" +nResults(result::Result) = result.firstIndexOfSegment[end] + length(result.t[end]) - 1 + + """ newResultSegment!(result, equationInfo, nsegments) From 746ddca643b4d4b87799979f6fe9155785d84a1c Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sat, 2 Jul 2022 07:51:18 +0200 Subject: [PATCH 53/63] Fix some typos in comments --- src/CodeGeneration.jl | 4 ++-- src/SignalTablesInterface.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 3a408e5..8565349 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -344,7 +344,7 @@ mutable struct SimulationModel{FloatType,TimeType} # equationInfo.x_info[equationInfo.nx_info_fixedLength+i:equationInfo.nx_info_invariant] x_start::Vector{FloatType} # States x before first event iteration (before initialization) x_init::Vector{FloatType} # States x after initialization (and before integrator is started) - x_segmented::Vector{FloatType} # A copy of the current segment states + x_segmented::Vector{FloatType} # A copy of the current segmented states der_x_invariant::Vector{FloatType} # Derivatives of states x or x_init that correspond to invariant states # This vector is filled with derivatives of invariants states with appendVariable!(m.der_x_invariant, ...) calls, @@ -936,7 +936,7 @@ isFirstEventIterationDirectlyAfterInitial(m::SimulationModel) = m.eventHandler.f """ isFullRestart(instantiatedModel) -Return true, if **FullRestart event** of a segmenteded simulation. +Return true, if **FullRestart event** of a segmented simulation. """ isFullRestart(m::SimulationModel) = m.eventHandler.fullRestart diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index f5cae48..fe78b8e 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -425,7 +425,7 @@ function get_result(m::SimulationModel, name::AbstractString; unit=true) #if SignalTables.timeSignalName(m) != 1 if length(m.result.t) > 1 - error("Error in Modia.get_result(\"$name\"), because function cannot be used for a segmenteded simulation with more as one segmented.") + error("Error in Modia.get_result(\"$name\"), because function cannot be used for a segmented simulation with more as one segmented.") end (tsig2, ysig2, ysigType) = SignalTables.rawSignal(m, name) @@ -464,7 +464,7 @@ function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) #= if length(m.result.t) > 1 - error("Error in Modia.get_result(...), because function cannot be used for a segmenteded simulation with more as one segmented.") + error("Error in Modia.get_result(...), because function cannot be used for a segmented simulation with more as one segmented.") end dataFrame = DataFrames.DataFrame() From 6f0a29d1151fdbc417b26d8d9b250561dc8b3aec Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sat, 2 Jul 2022 08:36:14 +0200 Subject: [PATCH 54/63] Changed back to DiffEqBase 6.90.0, due to https://github.com/SciML/DiffEqBase.jl/issues/791 --- Manifest.toml | 4 ++-- Project.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 3c73c42..8dd2b07 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -201,9 +201,9 @@ version = "0.4.0" [[deps.DiffEqBase]] deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "9862c61c6049b0ad5a6b433e31d2c6c8ff373056" +git-tree-sha1 = "528d97ef168b36e1a90d667e6611be24759aa1ba" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.92.2" +version = "6.90.0" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] diff --git a/Project.toml b/Project.toml index 6050db5..2420d88 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,7 @@ uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e" version = "0.9.0-dev" [compat] -DiffEqBase = "6.92.2" +DiffEqBase = "= 6.90.0" DataFrames = "1" DifferentialEquations = "7" FiniteDiff = "2" From 61f645c9680c48004eb4220141862e227ccab584 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sat, 2 Jul 2022 09:05:27 +0200 Subject: [PATCH 55/63] Fixes bug + remove ModiaPlot_PyPlot from docs --- docs/make.jl | 2 +- src/Result.jl | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 5ad8e24..1e6fd3a 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,4 +1,4 @@ -using Documenter, Modia, Modia.ModiaResult, ModiaPlot_PyPlot +using Documenter, Modia, SignalTables, SignalTablesInterface_PyPlot makedocs( #modules = [Modia], diff --git a/src/Result.jl b/src/Result.jl index 50e1730..9b47bde 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -251,7 +251,6 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re sc = Array{Union{_basetype,Missing}, length(dims)}(missing, dims) else # Allocate target memory with undef values - @assert(length(dimsMax) > 0) sc = Array{_basetype, length(dims)}(undef, dims) end From ff89d0884addcff86386be319fea063ce76e33e2 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 3 Jul 2022 07:25:02 +0200 Subject: [PATCH 56/63] Require DiffEqBase version 6.92.2 (see https://github.com/SciML/DiffEqBase.jl/issues/791) --- Manifest.toml | 4 ++-- Project.toml | 2 +- src/CodeGeneration.jl | 3 +++ src/Modia.jl | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 8dd2b07..3c73c42 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -201,9 +201,9 @@ version = "0.4.0" [[deps.DiffEqBase]] deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "528d97ef168b36e1a90d667e6611be24759aa1ba" +git-tree-sha1 = "9862c61c6049b0ad5a6b433e31d2c6c8ff373056" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.90.0" +version = "6.92.2" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] diff --git a/Project.toml b/Project.toml index 2420d88..6050db5 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,7 @@ uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e" version = "0.9.0-dev" [compat] -DiffEqBase = "= 6.90.0" +DiffEqBase = "6.92.2" DataFrames = "1" DifferentialEquations = "7" FiniteDiff = "2" diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 8565349..7de9c2a 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -484,6 +484,9 @@ SimulationModel{MonteCarloMeasurements.StaticParticles{T,N}}(args...; kwargs...) timeType(m::SimulationModel{FloatType,TimeType}) where {FloatType,TimeType} = TimeType +# The following rule is important that simulation is efficient. +# See, https://github.com/SciML/DiffEqBase.jl/issues/791 +DiffEqBase.anyeltypedual(::SimulationModel) = Any positive(m::SimulationModel, args...; kwargs...) = Modia.positive!(m.eventHandler, args...; kwargs...) negative(m::SimulationModel, args...; kwargs...) = Modia.negative!(m.eventHandler, args...; kwargs...) diff --git a/src/Modia.jl b/src/Modia.jl index 2434802..fdf0aed 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-07-02" +const Date = "2022-07-03" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") From 7dc36f80c3e573cdf325f3a538880501c743bb72 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Sun, 3 Jul 2022 10:00:40 +0200 Subject: [PATCH 57/63] Remove hideResult variables from signal table names --- src/CodeGeneration.jl | 11 +++++++---- src/ModiaLang.jl | 4 ++-- src/SignalTablesInterface.jl | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 7de9c2a..341e1d6 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -321,9 +321,10 @@ mutable struct SimulationModel{FloatType,TimeType} timeName::String w_invariant_names::Vector{String} + hideResult_names::Vector{String} # Names of hidden variables vEliminated::Vector{Int} vProperty::Vector{Int} - var_name::Function + var_name::Function result::Union{Result,Missing} # Result data structure upto current time instant parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor @@ -354,7 +355,7 @@ mutable struct SimulationModel{FloatType,TimeType} function SimulationModel{FloatType,TimeType}(modelModule, modelName, buildDict, getDerivatives!, equationInfo, previousVars, preVars, holdVars, - parameterDefinition, timeName, w_invariant_names; + parameterDefinition, timeName, w_invariant_names, hideResult_names; unitless::Bool=true, nz::Int = 0, nAfter::Int = 0, @@ -416,7 +417,7 @@ mutable struct SimulationModel{FloatType,TimeType} hold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, - string(timeName), w_invariant_names, vEliminated, vProperty, var_name, result, + string(timeName), w_invariant_names, hideResult_names, vEliminated, vProperty, var_name, result, parameters, equationInfo) end @@ -486,7 +487,9 @@ timeType(m::SimulationModel{FloatType,TimeType}) where {FloatType,TimeType} = Ti # The following rule is important that simulation is efficient. # See, https://github.com/SciML/DiffEqBase.jl/issues/791 -DiffEqBase.anyeltypedual(::SimulationModel) = Any +if Base.isdefined(DiffEqBase, :anyeltypedual) + DiffEqBase.anyeltypedual(::SimulationModel) = Any +end positive(m::SimulationModel, args...; kwargs...) = Modia.positive!(m.eventHandler, args...; kwargs...) negative(m::SimulationModel, args...; kwargs...) = Modia.negative!(m.eventHandler, args...; kwargs...) diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 2aa4795..a7bdd74 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -764,9 +764,9 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod # @show mappedParameters # println("Build SimulationModel") - + hideResult_names = [string(h) for h in hideResults] model = @timeit to "build SimulationModel" SimulationModel{FloatType,TimeType}(modelModule, name, buildDict, getDerivatives, equationInfo, previousVars, preVars, holdVars, - mappedParameters, timeName, w_invariant_names; + mappedParameters, timeName, w_invariant_names, hideResult_names; vSolvedWithInitValuesAndUnit, vEliminated, vProperty, var_name = (v)->string(unknownsWithEliminated[v]), nz=nCrossingFunctions, nAfter=nAfter, unitless=unitless) diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index fe78b8e..4ab285c 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -66,7 +66,7 @@ function SignalTables.signalNames(m::SimulationModel; var=true, par=true)::Vecto if var && !par return names1 end - names2 = getParameterNames(m.evaluatedParameters) + names2 = setdiff(getParameterNames(m.evaluatedParameters), m.hideResult_names) # parameters without hideResult_names if var && par return union(names1,names2) elseif par From d2cafcd85cae7f677c536c101b930953dfb661f9 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Mon, 4 Jul 2022 08:25:49 +0200 Subject: [PATCH 58/63] Adpated to latest SignalTables version + SignalTables functions used in TestFirstOrder2.jl (especially, writing signals to file) --- Manifest.toml | 8 +++---- Project.toml | 40 +++++++++++++++---------------- docs/src/Functions.md | 5 +++- src/CodeGeneration.jl | 25 +++++++++++++------- src/EventHandler.jl | 14 +++++------ src/Modia.jl | 12 ++-------- src/Result.jl | 30 ++++++++++++++--------- src/SignalTablesInterface.jl | 46 ++++++++++++++++++++++++++---------- test/TestFilterCircuit.jl | 2 +- test/TestFirstOrder2.jl | 38 ++++++++++++++++------------- 10 files changed, 127 insertions(+), 93 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 3c73c42..9117641 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -201,9 +201,9 @@ version = "0.4.0" [[deps.DiffEqBase]] deps = ["ArrayInterfaceCore", "ChainRulesCore", "DataStructures", "Distributions", "DocStringExtensions", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "Logging", "MuladdMacro", "NonlinearSolve", "Parameters", "Printf", "RecursiveArrayTools", "Reexport", "Requires", "SciMLBase", "Setfield", "SparseArrays", "StaticArrays", "Statistics", "ZygoteRules"] -git-tree-sha1 = "9862c61c6049b0ad5a6b433e31d2c6c8ff373056" +git-tree-sha1 = "f7a479aac5f3917b8472ac5f1b77d6f296fe58f1" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.92.2" +version = "6.92.3" [[deps.DiffEqCallbacks]] deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "LinearAlgebra", "NLsolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArrays"] @@ -533,9 +533,9 @@ version = "0.11.0" [[deps.MonteCarloMeasurements]] deps = ["Distributed", "Distributions", "LinearAlgebra", "MacroTools", "Random", "RecipesBase", "Requires", "SLEEFPirates", "StaticArrays", "Statistics", "StatsBase", "Test"] -git-tree-sha1 = "03619e255664666b352a5e5f6b45e8b00d439870" +git-tree-sha1 = "a7e89fde6ff10000e1a8f4d697b978d3908e913a" uuid = "0987c9cc-fe09-11e8-30f0-b96dd679fdca" -version = "1.0.8" +version = "1.0.9" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" diff --git a/Project.toml b/Project.toml index 6050db5..470d5ba 100644 --- a/Project.toml +++ b/Project.toml @@ -3,26 +3,6 @@ name = "Modia" uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e" version = "0.9.0-dev" -[compat] -DiffEqBase = "6.92.2" -DataFrames = "1" -DifferentialEquations = "7" -FiniteDiff = "2" -ForwardDiff = "0.10" -JSON = "0.21" -Measurements = "2" -ModiaBase = "0.11" -MonteCarloMeasurements = "1" -OrderedCollections = "1" -RecursiveFactorization = "0.2" -Reexport = "1" -SignalTables = "0.2" -StaticArrays = "1" -Sundials = "4" -TimerOutputs = "0.5" -Unitful = "1" -julia = "1.7" - [deps] DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" @@ -46,5 +26,25 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +[compat] +DiffEqBase = "6.82.0" +DataFrames = "1" +DifferentialEquations = "7" +FiniteDiff = "2" +ForwardDiff = "0.10" +JSON = "0.21" +Measurements = "2" +ModiaBase = "0.11" +MonteCarloMeasurements = "1" +OrderedCollections = "1" +RecursiveFactorization = "0.2" +Reexport = "1" +SignalTables = "0.2, 0.3" +StaticArrays = "1" +Sundials = "4" +TimerOutputs = "0.5" +Unitful = "1" +julia = "1.7" + [extras] CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" diff --git a/docs/src/Functions.md b/docs/src/Functions.md index a614d93..64baf6c 100644 --- a/docs/src/Functions.md +++ b/docs/src/Functions.md @@ -60,7 +60,10 @@ showEvaluatedParameters CurrentModule = Modia ``` -The simulation result of a model `instantiatedModel` supports the functions of +The simulation result of a model `instantiatedModel` are provided as *signal table* +(see [SignalTables.jl]()). +Therefore, all functions[SignalTables.jl functions] can be used. +These functions [ModiaResult](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html) and exports them, so the functions can be accessed without prefixing them with `Modia`. diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 341e1d6..77ad073 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -184,9 +184,9 @@ mutable struct SimulationOptions{FloatType,TimeType} rawStopTime = get(kwargs, :stopTime, startTime) stopTime = convertTimeVariable(TimeType, rawStopTime) interval = convertTimeVariable(TimeType, get(kwargs, :interval , (stopTime - startTime)/500.0) ) - dtmax = get(kwargs, :dtmax, 100*getValue(interval)) + dtmax = get(kwargs, :dtmax, 100*getValueOnly(interval)) if ismissing(dtmax) || isnothing(dtmax) - dtmax = 100*getValue(interval) + dtmax = 100*getValueOnly(interval) end dtmax = convert(Float64, dtmax) desiredResultTimeUnit = unit(rawStopTime) @@ -1676,7 +1676,7 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam new_result_info = false x_info = result.info[x_name] @assert(x_info.kind == RESULT_X) - @assert(basetype(startOrInit) == FloatType) + @assert(eltypeOrType(startOrInit) == FloatType) @assert(length( x_info.id[end].dims ) == ndims(startOrInit)) # Number of dimensions cannot change #if typeof(startOrInit) <: Number # @assert(xi_info.scalar) @@ -1713,10 +1713,17 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam # after function initialStateVector!(...) was called. t_unit = get(result.info[result.timeName].signal, :unit, "") der_x_unit = x_unit == "" ? SignalTables.unitAsParseableString(unit(1/uparse(t_unit))) : SignalTables.unitAsParseableString(unit(uparse(x_unit)/uparse(t_unit))) - x_var = Var(unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) - - result.info[x_name] = ResultInfo(RESULT_X , x_var, FloatType) - result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(unit=der_x_unit), FloatType) + if x_unit == "" + x_var = Var(start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + else + x_var = Var(unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + end + result.info[x_name] = ResultInfo(RESULT_X, x_var, FloatType) + if der_x_unit == "" + result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(), FloatType) + else + result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(unit=der_x_unit), FloatType) + end end return x_segmented_startIndex end @@ -1765,7 +1772,7 @@ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented else signal = Var(unit=unit) end - result.info[name] = ResultInfo(RESULT_W_SEGMENTED, signal, ValuesID(m.nsegments, w_index, w_size), basetype(w_segmented_default)) + result.info[name] = ResultInfo(RESULT_W_SEGMENTED, signal, ValuesID(m.nsegments, w_index, w_size), eltypeOrType(w_segmented_default)) end #println("new_w_segmented_variable: w_segmented_temp = ", result.w_segmented_temp) return w_index @@ -2012,7 +2019,7 @@ function generate_getDerivatives!(FloatType, TimeType, AST::Vector{Expr}, equati end # Generate code of the function - # temporarily removed: _m.time = $TimeType(Modia.getValue(_time)) + # temporarily removed: _m.time = $TimeType(Modia.getValueOnly(_time)) code = quote function $functionName(_x, _m::Modia.SimulationModel{$FloatType,$TimeType}, _time::$TimeType)::Nothing _FloatType = $FloatType diff --git a/src/EventHandler.jl b/src/EventHandler.jl index 031e564..b2c88d1 100644 --- a/src/EventHandler.jl +++ b/src/EventHandler.jl @@ -19,9 +19,9 @@ should be used. Only in special cases, the other flags are useful. using ForwardDiff -getValue(v) = v -getValue(v::ForwardDiff.Dual) = v.value -getValue(v::Measurements.Measurement) = Measurements.value(v) +getValueOnly(v) = v +getValueOnly(v::ForwardDiff.Dual) = v.value +getValueOnly(v::Measurements.Measurement) = Measurements.value(v) const nClock = 100 @@ -278,12 +278,12 @@ function after!(h::EventHandler{FloatType,TimeType}, nr::Int, t::Number, tAsStri end -#positive!(h, nr, crossing, crossingAsString, leq_mode; restart=Restart) = positive!(h, nr, getValue(crossing), crossingAsString, leq_mode; restart=restart) +#positive!(h, nr, crossing, crossingAsString, leq_mode; restart=Restart) = positive!(h, nr, getValueOnly(crossing), crossingAsString, leq_mode; restart=restart) function positive!(h::EventHandler{FloatType,TimeType}, nr::Int, crossing, crossingAsString::String, leq::Union{Nothing,Modia.LinearEquations{FloatType}}; restart::EventRestart=Restart)::Bool where {FloatType,TimeType} - crossing = getValue(crossing) + crossing = getValueOnly(crossing) if h.initial if !isnothing(leq) && leq.mode >= 0 @@ -330,7 +330,7 @@ end function negative!(h::EventHandler{FloatType,TimeType}, nr::Int, crossing, crossingAsString::String, leq::Union{Nothing,Modia.LinearEquations{FloatType}}; restart::EventRestart=Restart)::Bool where {FloatType,TimeType} - crossing = getValue(crossing) + crossing = getValueOnly(crossing) if h.initial if !isnothing(leq) && leq.mode >= 0 @@ -419,7 +419,7 @@ function edge!(h::EventHandler{FloatType,TimeType}, nr::Int, crossing, crossingA "iteration variables $(leq.vTear_names). This is not supported." end - crossing = getValue(crossing) + crossing = getValueOnly(crossing) if h.initial h.zPositive[nr] = crossing > convert(FloatType,0) diff --git a/src/Modia.jl b/src/Modia.jl index fdf0aed..0c52a50 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-07-03" +const Date = "2022-07-04" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -83,13 +83,10 @@ export instantiateModel, @instantiateModel, assert, stringifyDefinition export stripUnit export simulate!, linearize!, get_result -#export @usingModiaPlot, usePlotPackage, usePreviousPlotPackage, currentPlotPackage -export resultInfo, showResultInfo, rawSignal, getPlotSignal, defaultHeading -export signalNames, timeSignalName, hasSignal export hasParameter, getParameter, getEvaluatedParameter export showParameters, showEvaluatedParameters -export SimulationModel, measurementToString, get_lastValue, getLastValue +export SimulationModel, measurementToString, get_lastValue, getLastValue, getStateNames export positive, negative, previous, edge, after, reinit, pre export initial, terminal, isInitial, isTerminal, initLinearEquationsIteration! export get_xNames @@ -113,11 +110,6 @@ using ModiaBase.BLTandPantelidesUtilities using ModiaBase.BLTandPantelides using ModiaBase.Differentiate -#import SignalTables -#import SignalTables.: usePlotPackage, usePreviousPlotPackage, currentPlotPackage -#import SignalTables.: resultInfo, showResultInfo, getPlotSignal, getDefaultHeading -#import SignalTables.: signalNames, timeSignalName, hasSignal - import StaticArrays # Make StaticArrays available for the tests diff --git a/src/Result.jl b/src/Result.jl index 9b47bde..81af2f6 100644 --- a/src/Result.jl +++ b/src/Result.jl @@ -72,12 +72,12 @@ mutable struct ResultInfo aliasName::String # Name of non-eliminated variable aliasNegate::Bool # = true, if info[aliasName] signal must be negated id::Vector{ValuesID} # Location of the variable values with respect to ResultKind and Result - _basetype # If known, basetype(signal.values/.values); if not known: Nothing + _eltypeOrType # If known, eltypeOrType(signal.values/.values); if not known: Nothing value::Any # Value of constant variable (without unit) - ResultInfo(kind::ResultKind, signal, _basetype) = new(kind , signal, "" , false , ValuesID[] , _basetype, nothing) - ResultInfo(kind::ResultKind, signal, id::ValuesID, _basetype) = new(kind , signal, "" , false , ValuesID[id], _basetype, nothing) - ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[] , basetype(value), value) + ResultInfo(kind::ResultKind, signal, _eltypeOrType) = new(kind , signal, "" , false , ValuesID[] , _eltypeOrType, nothing) + ResultInfo(kind::ResultKind, signal, id::ValuesID, _eltypeOrType) = new(kind , signal, "" , false , ValuesID[id], _eltypeOrType, nothing) + ResultInfo(signal::SignalTables.SymbolDictType, value) = new(RESULT_CONSTANT , signal, "" , false , ValuesID[] , eltypeOrType(value), value) ResultInfo(signal::SignalTables.SymbolDictType, aliasName::String, aliasNegate::Bool) = new(RESULT_ELIMINATED, signal, aliasName, aliasNegate, ValuesID[], Nothing, nothing) end @@ -130,15 +130,23 @@ mutable struct Result{FloatType,TimeType} @assert(!haskey(info, xi_info.der_x_name)) x_unit = xi_info.unit der_x_unit = x_unit == "" ? "1/s" : unitAsParseableString(uparse(x_unit)/u"s") - x_var = Var(unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + if x_unit == "" + x_var = Var(start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + else + x_var = Var(unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + end if !isnan(xi_info.nominal) x_var[:nominal] = xi_info.nominal end if xi_info.unbounded x_var[:unbounded] = true end - info[xi_info.x_name] = ResultInfo(RESULT_X , x_var, FloatType) - info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(unit=der_x_unit), FloatType) + info[xi_info.x_name] = ResultInfo(RESULT_X, x_var, FloatType) + if der_x_unit == "" + info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(), FloatType) + else + info[xi_info.der_x_name] = ResultInfo(RESULT_DER_X, Var(unit=der_x_unit), FloatType) + end end # Fill info with w_invariant @@ -214,12 +222,12 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re id = resultInfo.id @assert(length(id) > 0) inlineValues = resultInfo.kind == RESULT_X || resultInfo.kind == RESULT_DER_X - _basetype = resultInfo._basetype + _eltypeOrType = resultInfo._eltypeOrType ndims_s = length(id[1].dims) if id[1].segment == -1 && ndims_s == 0 # Scalar signal that is defined in every segment index = id[1].index - sc = _basetype[ustrip.(ti[index]) for sk in s for ti in sk] + sc = _eltypeOrType[ustrip.(ti[index]) for sk in s for ti in sk] else # Find largest dims = dimsMax in all segments @@ -248,10 +256,10 @@ function signalResultValues(t::AbstractVector, s::AbstractVector, resultInfo::Re dims = (dims1, dimsMax...) if hasMissing # Allocate target memory with missing values - sc = Array{Union{_basetype,Missing}, length(dims)}(missing, dims) + sc = Array{Union{_eltypeOrType,Missing}, length(dims)}(missing, dims) else # Allocate target memory with undef values - sc = Array{_basetype, length(dims)}(undef, dims) + sc = Array{_eltypeOrType, length(dims)}(undef, dims) end # Copy subset of s-values to target sc diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index 4ab285c..6c23449 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -17,16 +17,16 @@ SignalTables.isSignalTable(m::SimulationModel) = true """ - independentSignalNames(instantiatedModel::Modia.SimulationModel|result::Modia.Result)::Vector{String} + getIndependentSignalNames(instantiatedModel::Modia.SimulationModel|result::Modia.Result)::Vector{String} Return the name of the independent variable of the result stored in instantiatedModel or in result. """ -SignalTables.independentSignalNames(result::Result) = [result.timeName] -SignalTables.independentSignalNames(m::SimulationModel) = begin +SignalTables.getIndependentSignalNames(result::Result) = [result.timeName] +SignalTables.getIndependentSignalNames(m::SimulationModel) = begin if ismissing(m.result) error("independentSignalName(..): No simulation results available in instantiated model of $(m.modelName)") end - SignalTables.independentSignalNames(m.result) + SignalTables.getIndependentSignalNames(m.result) end @@ -51,16 +51,16 @@ end """ - signalNames(instantiatedModel::Modia.SimulationModel; var=true, par=true)::Vector{String} + getSignalNames(instantiatedModel::Modia.SimulationModel; var=true, par=true)::Vector{String} Returns a string vector of the variables of an [`@instantiateModel`](@ref) that are present in the result or are (evaluated) parameters. - If var=true, Var(..) variables are included. - If par=true, Par(..) variables are included. """ -function SignalTables.signalNames(m::SimulationModel; var=true, par=true)::Vector{String} +function SignalTables.getSignalNames(m::SimulationModel; var=true, par=true)::Vector{String} if ismissing(m.result) - error("signalNames(..): No simulation results available in instantiated model of $(m.modelName)") + error("getSignalNames(..): No simulation results available in instantiated model of $(m.modelName)") end names1 = collect(keys(m.result.info)) if var && !par @@ -78,11 +78,31 @@ end """ - signalNames(result::Modia.Result)::Vector{String} + getStateNames(instantiatedModel::Modia.SimulationModel)::Vector{String} + +Returns a string vector of the states that are present in [`@instantiateModel`](@ref) +""" +function getStateNames(m::SimulationModel)::Vector{String} + if ismissing(m.result) + return collect(keys(m.equationInfo.x_dict)) + else + stateNames = String[] + for (key,resultInfo) in m.result.info + if resultInfo.kind == RESULT_X + push!(stateNames, key) + end + end + return stateNames + end +end + + +""" + getSignalNames(result::Modia.Result)::Vector{String} Returns a string vector of the variables that are present in the result. """ -SignalTables.signalNames(result::Result) = collect(keys(result.info)) +SignalTables.getSignalNames(result::Result) = collect(keys(result.info)) """ @@ -166,7 +186,7 @@ function SignalTables.getSignal(result::Result, name::String) # w_invariant is defined in all segments and has no size information defined - add size information resInfo.id[1] = ValuesID(index, size(w_value)) - resInfo._basetype = basetype(w_value) + resInfo._eltypeOrType = eltypeOrType(w_value) sigValues = signalResultValues(result.t, result.w_invariant, resInfo, result; name=name) elseif resInfo.kind == RESULT_W_SEGMENTED sigValues = signalResultValues(result.t, result.w_segmented, resInfo, result; name=name) @@ -237,9 +257,9 @@ function SignalTables.getSignalInfo(m::SimulationModel, name::String) end sigUnit = unitAsParseableString(sigValue) if sigUnit == "" - signalInfo = Par(_basetype = basetype(sigValue)) + signalInfo = Par(_eltypeOrType = eltypeOrType(sigValue)) else - signalInfo = Par(_basetype = basetype( ustrip.(sigValue) ), unit=sigUnit) + signalInfo = Par(_eltypeOrType = eltypeOrType( ustrip.(sigValue) ), unit=sigUnit) end _size = nothing size_available = false @@ -270,7 +290,7 @@ function SignalTables.getSignalInfo(result::Result, name::String) signalInfo = copy(resInfo.signal) delete!(signalInfo, :values) signalValues = resInfo.signal[:values] - signalInfo[:_basetype] = basetype(signalValues) + signalInfo[:_eltypeOrType] = eltypeOrType(signalValues) signalInfo[:_size] = size(signalValues) return signalInfo end diff --git a/test/TestFilterCircuit.jl b/test/TestFilterCircuit.jl index d5b6d70..e848bc1 100644 --- a/test/TestFilterCircuit.jl +++ b/test/TestFilterCircuit.jl @@ -28,7 +28,7 @@ showInfo(filterCircuit) # Test access functions @testset "Test variable access functions (TestFilterCircuit.jl)" begin - currentNames = signalNames(filterCircuit, par=false) + currentNames = getSignalNames(filterCircuit, par=false) requiredNames = String["C.i", "C.n.i", "C.n.v", "C.p.i", "C.p.v", "C.v", "R.i", "R.n.i", "R.n.v", "R.p.i", "R.p.v", "R.v", "V.i", "V.n.i", "V.n.v", "V.p.i", "V.p.v", "V.v", "C.der(v)", "ground.p.i", "ground.p.v", "time"] @test sort!(currentNames) == sort!(requiredNames) diff --git a/test/TestFirstOrder2.jl b/test/TestFirstOrder2.jl index 1094add..3a420d2 100644 --- a/test/TestFirstOrder2.jl +++ b/test/TestFirstOrder2.jl @@ -21,23 +21,27 @@ firstOrder = @instantiateModel(FirstOrder2, logCode=false) simulate!(firstOrder, Tsit5(), stopTime = 10, merge = Map(T = 0.4, x = 0.9), log=false, logParameters=true, logStates=true, requiredFinalStates = [-0.17964872595554535]) - -# Test get_result(instantiatedModel) no longer supported -#= -println() -result1 = get_result(firstOrder) -@show(result1[1:10,:]) -println() -@show(result1[1:10, ["time", "u", "y"]]) - -println() -result2 = get_result(firstOrder, onlyStates=true, extraNames=["y"]) -@show(result2[1:10,:]) - -println() -result3 = get_result(firstOrder, extraNames=["y"]) -@show(result3[1:10,:]) -=# +showInfo(firstOrder) + + +# Get result info +println("\n... Get values") +t = getValues(firstOrder, "time") +y = getValues(firstOrder, "y") +T = getValue( firstOrder, "T") +tWithUnit = getValuesWithUnit(firstOrder, "time") +@show t[1:10] +@show y[1:10] +@show T +@show tWithUnit[1:10] + +# Store result info on file +println("\n... Store result on file in JSON format") +writeSignalTable("TestFirstOrder2.json", firstOrder; indent=2, log=true) + +println("\n... Store states on file in JSON format") +stateNames = getStateNames(firstOrder) +writeSignalTable("TestFirstOrder2_states.json", firstOrder; signalNames=stateNames, indent=2, log=true) # Linearize println("\n... Linearize at stopTime = 0 and 10:") From 22ffbc24fc763873fde344e4f4576458422bd6a4 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Mon, 4 Jul 2022 08:44:15 +0200 Subject: [PATCH 59/63] Minor bug fixed --- src/CodeGeneration.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 77ad073..2a0612f 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1685,7 +1685,7 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam #else # error("new_x_segmented_variable(.. $x_name, $der_x_name, startOrInit,...): typeof(startOrInit) is neither a Number nor an AbstractVector)") #end - @assert(x_info.signal[:unit] == x_unit) + @assert(get(x_info.signal,:unit,"") == x_unit) @assert(haskey(result.info, der_x_name)) der_x_info = result.info[der_x_name] @assert(der_x_info.kind == RESULT_DER_X) From 84d0c315e33ec1c9a8befdecd49cab0490024631 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 5 Jul 2022 12:34:25 +0200 Subject: [PATCH 60/63] Docu adapted and improved. --- README.md | 18 ++++-- docs/src/Functions.md | 87 ++++++++++++----------------- docs/src/Internal.md | 44 ++++++++++++++- docs/src/index.md | 77 ++++++++++++++++--------- docs/src/tutorial/GettingStarted.md | 12 ++-- docs/src/tutorial/Modeling.md | 5 +- docs/src/tutorial/Simulation.md | 6 +- docs/src/tutorial/Tutorial.md | 18 +++--- examples/Tutorial.jl | 4 +- src/CodeGeneration.jl | 80 +++++++++++++------------- src/Modia.jl | 28 ++++++++-- src/SignalTablesInterface.jl | 87 +++++------------------------ src/SimulateAndPlot.jl | 8 +-- test/TestFirstOrder2.jl | 62 +++++++++++++++----- 14 files changed, 295 insertions(+), 241 deletions(-) diff --git a/README.md b/README.md index 2c55892..eb5fd49 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ The [Modia Tutorial](https://modiasim.github.io/Modia.jl/stable/tutorial/Getting The [Modia3D Tutorial](https://modiasim.github.io/Modia3D.jl/stable/tutorial/GettingStarted.html) provides an introduction to use 3D components in Modia. Modia is part of [ModiaSim](https://modiasim.github.io/docs/). -[Modia](https://github.com/ModiaSim/Modia.jl) is an environment in form of a Julia package to model and simulate physical systems (electrical, mechanical, thermo-dynamical, etc.) described by differential and algebraic equations. A user defines a model on a high level with model components (like a mechanical body, an electrical resistance, or a pipe) that are physically connected together. A model component is constructed by **`expression = expression` equations** or by Julia structs/functions, such as the pre-defined Modia 3D-mechanical components. The defined model is symbolically processed (for example, equations might be analytically differentiated) with algorithms from package [ModiaBase.jl](https://github.com/ModiaSim/ModiaBase.jl). From the transformed model a Julia function is generated that is used to simulate the model with integrators from [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl). +[Modia](https://github.com/ModiaSim/Modia.jl) is an environment in form of a Julia package to model and simulate physical systems (electrical, mechanical, thermo-dynamical, etc.) described by differential and algebraic equations. A user defines a model on a high level with model components (like a mechanical body, an electrical resistance, or a pipe) that are physically connected together. A model component is constructed by **`expression = expression` equations** or by Julia structs/functions, such as the pre-defined [Modia3D] (https://github.com/ModiaSim/Modia3D.jl) multibody components. The defined model is symbolically processed (for example, equations might be analytically differentiated) with algorithms from package [ModiaBase.jl](https://github.com/ModiaSim/ModiaBase.jl). From the transformed model a Julia function is generated that is used to simulate the model with integrators from [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl). The basic type of the floating point variables is usually `Float64`, but can be set to any -type `FloatType<:AbstractFloat` via `@instantiateModel(..., FloatType = xxx)`, for example +type `FloatType <: AbstractFloat` via `@instantiateModel(..., FloatType = xxx)`, for example it can be set to `Float32, DoubleFloat, Measurement{Float64}, StaticParticles{Float64,100}`. ## Installation @@ -24,16 +24,22 @@ Furthermore, one or more of the following packages should be installed in order to be able to generate plots: ```julia -julia> ]add ModiaPlot_PyPlot # if plotting with PyPlot desired - add ModiaPlot_GLMakie # if plotting with GLMakie desired - add ModiaPlot_WGLMakie # if plotting with WGLMakie desired - add ModiaPlot_CairoMakie # if plotting with CairoMakie desired +julia> ]add SignalTablesInterface_PyPlot # if plotting with PyPlot desired + + # currently under registration + add SignalTablesInterface_GLMakie # if plotting with GLMakie desired + add SignalTablesInterface_WGLMakie # if plotting with WGLMakie desired + add SignalTablesInterface_CairoMakie # if plotting with CairoMakie desired ``` +or call `t = getValues(instantiatedModel, "time"), y = getValues(instantiatedModel, "y")` to retrieve +the results in form of vectors and arrays and use any desired plot package for plotting, e.g., `plot(t,y)`. + Note, Modia reexports the following definitions - `using Unitful` - `using DifferentialEquations` +- `using SignalTables` - and exports functions `CVODE_BDF` and `IDA` of [Sundials.jl](https://github.com/SciML/Sundials.jl). As a result, it is usually sufficient to have `using Modia` in a model to utilize the relevant diff --git a/docs/src/Functions.md b/docs/src/Functions.md index 64baf6c..6bb88a5 100644 --- a/docs/src/Functions.md +++ b/docs/src/Functions.md @@ -54,71 +54,54 @@ showEvaluatedParameters ``` -## Results +## Results and Plotting ```@meta CurrentModule = Modia ``` -The simulation result of a model `instantiatedModel` are provided as *signal table* -(see [SignalTables.jl]()). -Therefore, all functions[SignalTables.jl functions] can be used. -These functions -[ModiaResult](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html) and -exports them, so the functions can be accessed without prefixing them with `Modia`. +The simulation result of a model `instantiatedModel` are provided as a *signal table*, +see [SignalTables.jl](https://github.com/ModiaSim/SignalTables.jl). -The following functions are provided to access **Modia results** -(use `ìnstantiatedModel` as argument `result`, e.g. `printResultInfo(instantiatedModel)`): +Therefore, all [signal table functions](https://modiasim.github.io/SignalTables.jl/stable/Functions/OverviewOfFunctions.html) +can be used on a simulated model, for example: -| Functions | Description | -|:---------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------| -| [`printResultInfo` ](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.printResultInfo) | Print info of the result on stdout. | -| [`resultInfo`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.resultInfo) | Return info about the result as [DataFrame](https://github.com/JuliaData/DataFrames.jl) table | -| [`rawSignal`](https://modiasim.github.io/ModiaResult.jl/stable/AbstractInterface.html#ModiaResult.rawSignal) | Return raw signal data given the signal name. | -| [`getPlotSignal`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.getPlotSignal) | Return signal data prepared for a plot package. | -| [`signalNames`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.signalNames) | Return all signal names. | -| [`timeSignalName`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.timeSignalName) | Return the name of the time signal. | -| [`hasOneTimeSignal`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.hasOneTimeSignal) | Return true if one time signal present. | -| [`hasSignal`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.hasSignal) | Return true if a signal name is known. | -| [`getLastValue`](@ref) | Return last available value of variable name | -| [`defaultHeading`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.defaultHeading`) | Return default heading of a result. | - - -## Plotting - -```@meta -CurrentModule = Modia ``` +using Modia -The simulation result of a model `instantiatedModel` supports the functions of -[ModiaResult](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html) and -exports them, so the functions can be accessed without prefixing them with `Modia`. - -The following functions are provided to **define/inquire the current plot package**: +FirstOrder = Model( + T = 0.2u"s", + x = Var(init=0.3), + equations = :[u = sin(time/u"s") + T * der(x) + x = u + y = 2*x] +) +simulate!(firstOrder, stopTime=10) +showInfo(firstOrder) # list info about the result +t = getValues(firstOrder, "time") +y = getValues(firstOrder, "y") # use any plot program: plot(t,y) + +# Write result on file +writeSignalTable("firstOrder.json", firstOrder, indent=2, log=true) +``` -| Functions | Description | -|:-------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------| -| [`@usingModiaPlot`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.@usingModiaPlot) | Expands into `using ModiaPlot_` | -| [`usePlotPackage`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.usePlotPackage) | Define the plot package to be used. | -| [`usePreviousPlotPackage`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.usePreviousPlotPackage) | Define the previously defined plot package to be used. | -| [`currentPlotPackage`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaResult.currentPlotPackage) | Return name defined with `usePlotPackage` | +See the generated [json-file](../resources/fileio/firstOrder.json). -The following functions are available after +For plotting, a plot package must be installed, e.g., -1. `ENV["MODIA_PLOT"] = XXX` (e.g. in startup.jl file) or - `usePlotPackage(XXX)` has been executed (XXX = "PyPlot", "GLMakie", "WGLMakie", "CairoMakie", "NoPlot" or "SilentNoPlot") and -2. `@usingModiaPlot` has been called, +```julia +julia> ]add SignalTablesInterface_PyPlot # if plotting with PyPlot desired + add SignalTablesInterface_GLMakie # if plotting with GLMakie desired + add SignalTablesInterface_WGLMakie # if plotting with WGLMakie desired + add SignalTablesInterface_CairoMakie # if plotting with CairoMakie desired +``` -to **plot with the currently defined plot package** -(use `ìnstantiatedModel` as argument `result`, e.g. `plot(instantiatedModel, ...)`): +In a model, the desired plot package is defined with: -| Functions | Description | -|:----------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------| -| [`plot`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.plot) | Plot simulation results in multiple diagrams/figures. | -| [`saveFigure`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.saveFigure) | Save figure in different formats on file. | -| [`closeFigure`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.closeFigure) | Close one figure | -| [`closeAllFigures`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.closeAllFigures) | Close all figures | -| [`showFigure`](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html#ModiaPlot_PyPlot.showFigure) | Show figure in window (only GLMakie, WGLMakie) | +```julia +using Modia +usePlotPackage("PyPlot") # or ENV["SignalTablesPlotPackage"] = "PyPlot" +``` A Modia variable `a.b.c` is identified by a String key `"a.b.c"`. The legends/labels of the plots are automatically constructed by the @@ -126,7 +109,7 @@ names and units of the variables. Example: ```julia using Modia -@usingModiaPlot +@usingPlotPackage # execute `using SignalTablesInterface_XXX` instantiatedModel = @instantiateModel(...) simulate!(instantiatedModel, ...) diff --git a/docs/src/Internal.md b/docs/src/Internal.md index 7cec678..dbdc7c4 100644 --- a/docs/src/Internal.md +++ b/docs/src/Internal.md @@ -17,14 +17,24 @@ SimulationModel generate_getDerivatives! init! outputs! +terminate! +derivatives! +DAEresidualsForODE! +affectEvent! +zeroCrossings! +affectStateEvent! +timeEventCondition! +affectTimeEvent! addToResult! getFloatType -baseType measurementToString ``` ## Inquiries in Model +The functions in this section can be called in the model code or in +functions that are called from the model code. + ```@docs isInitial isTerminal @@ -34,4 +44,36 @@ isFirstEventIterationDirectlyAfterInitial isAfterSimulationStart isZeroCrossing storeResults +getTime +``` + +## Variable definitions in functions + +The following functions can be used to define states and algebraic variables inside functions: + +```@docs +new_x_segmented_variable! +new_w_segmented_variable! +new_alias_segmented_variable! +new_z_segmented_variable! +get_x_startIndex_from_x_segmented_startIndex +get_scalar_x_segmented_value +get_SVector3_x_segmented_value +get_Vector_x_segmented_value! +add_der_x_segmented_value! +add_w_segmented_value! ``` + + + + + + + + + + + + + + diff --git a/docs/src/index.md b/docs/src/index.md index 5bf35a6..ed7c8d7 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,8 +1,8 @@ # Modia Documentation -[Modia](https://github.com/ModiaSim/Modia.jl) is an environment in form of a Julia package to model and simulate physical systems (electrical, mechanical, thermo-dynamical, etc.) described by differential and algebraic equations. A user defines a model on a high level with model components (like a mechanical body, an electrical resistance, or a pipe) that are physically connected together. A model component is constructed by **`expression = expression` equations** or by Julia structs/functions, such as the pre-defined Modia 3D-mechanical components. The defined model is symbolically processed (for example, equations might be analytically differentiated) with algorithms from package [ModiaBase.jl](https://github.com/ModiaSim/ModiaBase.jl). From the transformed model a Julia function is generated that is used to simulate the model with integrators from [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl). +[Modia](https://github.com/ModiaSim/Modia.jl) is an environment in form of a Julia package to model and simulate physical systems (electrical, mechanical, thermo-dynamical, etc.) described by differential and algebraic equations. A user defines a model on a high level with model components (like a mechanical body, an electrical resistance, or a pipe) that are physically connected together. A model component is constructed by **`expression = expression` equations** or by Julia structs/functions, such as the pre-defined [Modia3D] (https://github.com/ModiaSim/Modia3D.jl) multibody components. The defined model is symbolically processed (for example, equations might be analytically differentiated) with algorithms from package [ModiaBase.jl](https://github.com/ModiaSim/ModiaBase.jl). From the transformed model a Julia function is generated that is used to simulate the model with integrators from [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl). The basic type of the floating point variables is usually `Float64`, but can be set to any -type `FloatType<:AbstractFloat` via `@instantiateModel(..., FloatType = xxx)`, for example +type `FloatType <: AbstractFloat` via `@instantiateModel(..., FloatType = xxx)`, for example it can be set to `Float32, DoubleFloat, Measurement{Float64}, StaticParticles{Float64,100}`. @@ -18,16 +18,22 @@ Furthermore, one or more of the following packages should be installed in order to be able to generate plots: ```julia -julia> ]add ModiaPlot_PyPlot # if plotting with PyPlot desired - add ModiaPlot_GLMakie # if plotting with GLMakie desired - add ModiaPlot_WGLMakie # if plotting with WGLMakie desired - add ModiaPlot_CairoMakie # if plotting with CairoMakie desired +julia> ]add SignalTablesInterface_PyPlot # if plotting with PyPlot desired + + # currently under registration + add SignalTablesInterface_GLMakie # if plotting with GLMakie desired + add SignalTablesInterface_WGLMakie # if plotting with WGLMakie desired + add SignalTablesInterface_CairoMakie # if plotting with CairoMakie desired ``` +or call `t = getValues(instantiatedModel, "time"), y = getValues(instantiatedModel, "y")` to retrieve +the results in form of vectors and arrays and use any desired plot package for plotting, e.g., `plot(t,y)`. + Note, Modia reexports the following definitions - `using Unitful` - `using DifferentialEquations` +- `using SignalTables` - and exports functions `CVODE_BDF` and `IDA` of [Sundials.jl](https://github.com/SciML/Sundials.jl). As a result, it is usually sufficient to have `using Modia` in a model to utilize the relevant @@ -36,35 +42,50 @@ functionalities of these packages. ## Release Notes -### Version 0.9.0-dev +### Version 0.9.0 + +- This version is slightly **non-backwards** compatible to 0.8.x. Most important, the result handling has been changed. + Especially, package [ModiaResult.jl](https://github.com/ModiaSim/ModiaResult.jl) has been replaced by + package [SignalTables.jl](https://github.com/ModiaSim/SignalTables.jl). + Also the plot package interfaces SignalTablesInterface\_PyPlot, SignalTablesInterface\_GLMakie etc. have been replaced by packages + SignalTablesInterface\_PyPlot, SignalTablesInterface\_GLMakie etc.\ + In order that plotting works again with your models, you have to add one of the new plot package interfaces, e.g. + `]add SignalTablesInterface_PyPlot`. One benefit is, that the plot packages have now access to all attributes + associated with a variable. -- New functions `hasParameter, getParameter, getEvaluatedParameter, showParameter, showEvaluatedParameter` to +- An instantiated model (as returned from `@instantiateModel(..)`) is now a signal table according to [SignalTables.jl](https://github.com/ModiaSim/SignalTables.jl). + This means that all functions defined for a signal table (see [function overview](https://modiasim.github.io/SignalTables.jl/stable/Functions/OverviewOfFunctions.html)) + can be applied on a simulated model. Hereby, all Var(..) and Par(..) Modia variables are seen as signals of the signal table + (so both time varying variables, as well as parameters). See example `Modia/test/TestFirstOrder2.jl`.\ + For example, it is now possible to store simulation results (together with all parameter and start values) on file in JSON format + with `writeSignalTable(filename, instantiatedModel)` (or in HDF5 format via [JDL](https://github.com/JuliaIO/JLD.jl)). + You get an overview of a simulation result via `showInfo(instantiatedModel)`. + +- New functions [`hasParameter`](@ref), [`getParameter`](@ref), [`getEvaluatedParameter`](@ref), + [`showParameters`](@ref), [`showEvaluatedParameters`](@ref) to get parameter/init/start values by name (e.g. `getEvaluatedParameter(instantiatedModel, "a.b.c")`) or - show all parameters. For details see the [function docu](https://modiasim.github.io/ModiaResult.jl/stable/Functions.html). + show all parameters. -- New functions to add states and algebraic variables from within functions that are not visible in the generated code: - `Modia.new_x_segmented_variable!, Modia.new_w_segmented_variable!, Modia.add_w_segmented_value!`. - These functions are called after simulate!(..) is called, but before initialization is performed. - For details see example `Modia/test/TestLinearSystems.jl`. +- New functions to add states and algebraic variables from within functions that are not visible in the generated code + (see [Variable definitions in functions](@ref) and example `Modia/test/TestLinearSystems.jl`). + This feature is used in the next version of + Modia3D to allow (Modia3D) model changes after code generation and to get more light weight code. - simulate!(..): Maximum number of iterations is switched off (DifferentialEquations.jl option set to: maxiters = Int(typemax(Int32)) ≈ 2e9). -- An instance of a SimulationModel is now a signal table according to [SignalTables.jl](https://github.com/ModiaSim/SignalTables.jl). - This means that all functions defined for a signal table (see [function overview](https://modiasim.github.io/SignalTables.jl/stable/Functions/OverviewOfFunctions.html)) - can be applied on a SimulationModel. Hereby, all Var(..) and Par(..) Modia variables are seen as signals of the signal table - (so both time varying variables, as well as parameters). One benefit is, that its now possible to directly perform standard array operations - on results, e.g. `diff = getValues(simulationModel, "a.b.c") - getValues(simulationModel, "b.d.e")`. - -- Docu improved (e.g. links to utility functions documentation added) +- Docu improved. +- @usingModiaPlot is deprecated. Use instead @usingPlotPackage. -** Bug fixes + +**Bug fixes** 1. A hierarchical model name with a derivative operator, say `der(a.b.c)`, has now the correct name `a.b.der(c)` in the result. For example, the plot command needs to be changed to `plot(..., "a.b.der(c)")` instead of the previous command `plot(..., "der(a.b.c)")`. -2. The initial state vector was not always correctly filled with start/init values of the model (is now fixed). +2. The initial state vector was not always correctly filled with start/init values of the model (is now fixed). 3. `signalNames(instantiatedModel)` did sometimes not show the correct signal names available in the result (is now fixed). + `signalNames` is deprecated. Use instead [getSignalNames](https://modiasim.github.io/SignalTables.jl/stable/Functions/SignalTables.html#SignalTables.getSignalNames). **Non-backwards compatible changes** @@ -72,7 +93,7 @@ functionalities of these packages. - Bug fix 1 can lead for some models to warnings and the selected variable is no longer plotted (-> the model needs to be changed). - Bug fix 2 can lead for some models to a different result (without notice). - + - The result data structure is now constructed with `deepcopy(..)` of every involved result variable. Previously, for some result variables just the variable reference was stored. The effect is that if previously a complex internal data structure was incorporated into the result data structure, @@ -83,9 +104,15 @@ functionalities of these packages. Such variables `v` need to be declared with `v = Var(hideResult=true)`, in order that this error does not appear (and these variables are then not stored in the result). -- getPath(path, ...) does no longer return a dictionary but a SignalTables.SignalTable. +- Function `rawSignal(instantiatedModel, name)` is no longer supported. + Use [getValues](https://modiasim.github.io/SignalTables.jl/stable/Functions/SignalTables.html#SignalTables.getValues) + or [getSignal](https://modiasim.github.io/SignalTables.jl/stable/Functions/SignalTables.html#SignalTables.getSignal) instead. + +- Function `getPlotSignal(instantiatedModel, name)` is no longer supported. + Use [getFlattenedSignal](https://modiasim.github.io/SignalTables.jl/stable/Functions/SignalTables.html#SignalTables.getFlattenedSignal) instead. + +- Function `getPath(path, ...)` does no longer return a dictionary but a [SignalTable](https://modiasim.github.io/SignalTables.jl/stable/Functions/SignalTables.html#SignalTables.SignalTable). -- Internal constructor `SimulationModel(..)`: Unused argument x_startValues removed. ### Version 0.8.3 diff --git a/docs/src/tutorial/GettingStarted.md b/docs/src/tutorial/GettingStarted.md index d960b29..7ea1565 100644 --- a/docs/src/tutorial/GettingStarted.md +++ b/docs/src/tutorial/GettingStarted.md @@ -10,10 +10,7 @@ can be defined, simulated and plotted with the following commands: ```julia using Modia # reexports exported symbols from - # DifferentialEquations and from Unitful -@usingModiaPlot # Use plot package defined with - # ENV["MODIA_PLOT"] or usePlotPackage(..) - + # DifferentialEquations, Unitful, SignalTables # Define model SimpleModel = Model( @@ -32,6 +29,9 @@ simulate!(simpleModel, stopTime = 1.2) simulate!(simpleModel, Tsit5(), stopTime = 1.2u"s") # Produce a line plot +@usingPlotPackage # Use plot package defined with + # ENV["SignalTablesPlotPackage"] = "PyPlot" or with + # usePlotPackage("PyPlot") plot(simpleModel, ("x", "der(x)")) ``` @@ -56,11 +56,11 @@ Integrator `Tsit5` is an [adaptive Runge-Kutta method of order 5/4 from Tsitoura Function call `plot(..)` produces a line plot. Variables to be plotted are defined as tuples or arrays of variable names. Tuples are displayed in one diagram. A Vector or matrix of tuples or strings are displayed as vector or matrix of diagrams. -When `ENV["MODIA_PLOT"] = "GLMakie"` is set, then command `plot(..)` produces the following image +When `ENV["SignalTablesPlotPackage"] = "GLMakie"` is set, then command `plot(..)` produces the following image ![SimpleModel Plot](../../resources/images/SimpleModel_GLMakie.png) -When `ENV["MODIA_PLOT"] = "PyPlot"` is set, the following image is produced: +When `ENV["SignalTablesPlotPackage"] = "PyPlot"` is set, the following image is produced: ![SimpleModel Plot](../../resources/images/SimpleModel_PyPlot.png) diff --git a/docs/src/tutorial/Modeling.md b/docs/src/tutorial/Modeling.md index 7a9ded7..c2856c9 100644 --- a/docs/src/tutorial/Modeling.md +++ b/docs/src/tutorial/Modeling.md @@ -149,7 +149,7 @@ The returned arguments are typically numbers or arrays (see below). It is also possible to return an instance of a struct and, say, pass this instance as input to another function call. -However, it is currently not supported that a function call modifies one of its arguments, +It is currently not supported that a function call modifies one of its arguments, or that a function call returns no argument at all: ``` @@ -553,8 +553,6 @@ is constructed with these libraries in the following way: ```julia using Modia -@usingModiaPlot - include("$(Modia.modelsPath)/Electric.jl") FilterCircuit = Model( @@ -571,6 +569,7 @@ FilterCircuit = Model( filterCircuit = @instantiateModel(FilterCircuit) simulate!(filterCircuit, Tsit5(), stopTime=10.0) +@usingPlotPackage plot(filterCircuit, ["C.v", "C.i"], figure=3) ``` diff --git a/docs/src/tutorial/Simulation.md b/docs/src/tutorial/Simulation.md index f145cb5..a949a1d 100644 --- a/docs/src/tutorial/Simulation.md +++ b/docs/src/tutorial/Simulation.md @@ -4,7 +4,7 @@ A particular model is instantiated, simulated and results plotted with the comma ```julia using Modia -@usingModiaPlot +@usingPlotPackage filter = @instantiateModel(Filter) simulate!(filter, stopTime=10.0) @@ -55,7 +55,7 @@ It is also possible to specify the integrator as second argument of `simulate!`: ```julia using Modia -@usingModiaPlot +@usingPlotPackage filter = @instantiateModel(Filter) sol = simulate!(filter, Tsit5(), stopTime=10.0, merge=Map(T=0.5, x=0.8)) @@ -85,7 +85,7 @@ used on the return argument `sol` of `simulate!`. ## 3.4 Plotting A short overview of the most important plot commands is given in -section [Plotting](@ref) +section [Results and Plotting](@ref) ## 3.5 State selection (DAEs) diff --git a/docs/src/tutorial/Tutorial.md b/docs/src/tutorial/Tutorial.md index b9a180d..6ade71c 100644 --- a/docs/src/tutorial/Tutorial.md +++ b/docs/src/tutorial/Tutorial.md @@ -5,19 +5,21 @@ to construct component-based and equation-based models with the **Modia language on a high level, symbolically transforming these models into ODEs (Ordinary Differential Equations in state space form), simulating them and plotting result variables. -Note, all examples in this tutorial can be executed with\ -`using Modia; include("$(Modia.path)/examples/Tutorial.jl")` +Note, all examples in this tutorial can be executed with +```julia +using Modia +include("$(Modia.path)/examples/Tutorial.jl") +``` -Modeling of 3D components is explained in the [Modia3D Tutorial](https://modiasim.github.io/Modia3D.jl/stable/tutorial/Tutorial.html#Modia3D-Tutorial) +Modeling of 3D components (= multibody systems) is explained in the [Modia3D Tutorial](https://modiasim.github.io/Modia3D.jl/stable/tutorial/Tutorial.html#Modia3D-Tutorial) !!! info - Modia has an interface to various plot packages. A plot package can be - either selected by setting `ENV["MODIA_PLOT"] = XXX`, for example in the `config/startup.jl` - file of Julia or by command `Modia.usePlotPackage(XXX)`. Possible values for `XXX`: + Modia is based on SignalTables that has an interface to various plot packages. A plot package can be + either selected by setting `ENV["SignalTablesPlotPackage"] = XXX`, for example in the `config/startup.jl` + file of Julia, or by command `usePlotPackage(XXX)`. Possible values for `XXX`: - "[PyPlot](https://github.com/JuliaPy/PyPlot.jl)" (plots with Matplotlib from Python), - "[GLMakie](https://github.com/JuliaPlots/GLMakie.jl)" (interactive plots in an OpenGL window), - "[WGLMakie](https://github.com/JuliaPlots/WGLMakie.jl)" (interactive plots in a browser window), - - "[CairoMakie](https://github.com/JuliaPlots/CairoMakie.jl)" (static plots on file with publication quality), - - "NoPlot" (= all `plot(...)` calls are ignored), or + - "[CairoMakie](https://github.com/JuliaPlots/CairoMakie.jl)" (static plots on file with publication quality), or - "SilentNoPlot" (= NoPlot without messages). diff --git a/examples/Tutorial.jl b/examples/Tutorial.jl index fba9cc7..d48b24f 100644 --- a/examples/Tutorial.jl +++ b/examples/Tutorial.jl @@ -3,7 +3,6 @@ module Tutorial # 1 Getting started using Modia -@usingModiaPlot # Define model SimpleModel = Model( @@ -21,7 +20,8 @@ simulate!(simpleModel, stopTime = 1.2) # Simulate with a specific integrator (Tsit5) and use a unit for stopTime simulate!(simpleModel, Tsit5(), stopTime = 1.2u"s") -# Produce a line plot with GLMakie +# Produce a line plot +@usingPlotPackage plot(simpleModel, ("x", "der(x)"), figure=1) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 2a0612f..f9316c8 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -318,18 +318,18 @@ mutable struct SimulationModel{FloatType,TimeType} # = false, either before first outputs!(..) call or at first outputs!(..) after init!(..) and # an error was triggered and simulate!(..) should be returned with nothing. unitless::Bool # = true, if simulation is performed without units. - + timeName::String w_invariant_names::Vector{String} - hideResult_names::Vector{String} # Names of hidden variables - vEliminated::Vector{Int} + hideResult_names::Vector{String} # Names of hidden variables + vEliminated::Vector{Int} vProperty::Vector{Int} - var_name::Function + var_name::Function result::Union{Result,Missing} # Result data structure upto current time instant - + parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor equationInfo::Modia.EquationInfo # Invariant part of equations are available - + # Available after propagateEvaluateAndInstantiate!(..) called instantiateFunctions::Vector{Tuple{Union{Expr,Symbol},OrderedDict{Symbol,Any},String}} # All definitions `_instantiateFunction = Par(functionName = XXX)` in the model to call @@ -402,10 +402,10 @@ mutable struct SimulationModel{FloatType,TimeType} success = false w_invariant_names = String[string(name) for name in w_invariant_names] - + # Initialize other data result = missing - instantiateResult = true + instantiateResult = true newResultSegment = false parameters = deepcopy(parameterDefinition) @@ -417,7 +417,7 @@ mutable struct SimulationModel{FloatType,TimeType} hold, hold_names, hold_dict, isInitial, solve_leq, true, storeResult, convert(TimeType, 0), nGetDerivatives, nf, odeIntegrator, daeCopyInfo, algorithmName, sundials, addEventPointsDueToDEBug, success, unitless, - string(timeName), w_invariant_names, hideResult_names, vEliminated, vProperty, var_name, result, + string(timeName), w_invariant_names, hideResult_names, vEliminated, vProperty, var_name, result, parameters, equationInfo) end @@ -485,8 +485,8 @@ SimulationModel{MonteCarloMeasurements.StaticParticles{T,N}}(args...; kwargs...) timeType(m::SimulationModel{FloatType,TimeType}) where {FloatType,TimeType} = TimeType -# The following rule is important that simulation is efficient. -# See, https://github.com/SciML/DiffEqBase.jl/issues/791 +# The following rule is important for DiffEqBase version 6.91.6 and later +# (https://github.com/SciML/DiffEqBase.jl/issues/791) if Base.isdefined(DiffEqBase, :anyeltypedual) DiffEqBase.anyeltypedual(::SimulationModel) = Any end @@ -661,7 +661,7 @@ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit @info "getLastValue(model,\"$name\"): No results yet available." return nothing end - + result = m.result if haskey(result.info, name) # Time varying variable stored in m.result @@ -707,7 +707,7 @@ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit segment = id.segment if segment < length(result.t) return missing - end + end ibeg = id.index iend = ibeg + prod(id.size) - 1 value = ibeg == iend ? result.der_x[segment][end][ibeg] : result.der_x[segment][end][ibeg:iend] @@ -727,7 +727,7 @@ function getLastValue(m::SimulationModel{FloatType,TimeType}, name::String; unit segment = id.segment if segment < length(result.t) return missing - end + end value = result.w_segmented[segment][end][id.index] if unit && resInfo.unit != "" && eltype(value) <: AbstractFloat value *= uparse(resInfo.unit) @@ -980,7 +980,7 @@ setNextEvent!(m::SimulationModel{FloatType,TimeType}, nextEventTime) where {Floa setNextEvent!(m.eventHandler, convert(TimeType,nextEventTime)) -function setFullRestartEvent!(m::SimulationModel) +function setFullRestartEvent!(m::SimulationModel) m.eventHandler.restart = FullRestart return nothing end @@ -1063,9 +1063,9 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti eh = m.eventHandler m.instantiateFunctions = Tuple{Union{Expr,Symbol}, OrderedDict{Symbol,Any}, String}[] m.nsegments = 1 - m.result = Result{FloatType,TimeType}(m.equationInfo, m.timeName, m.w_invariant_names, m.vEliminated, m.vProperty, m.var_name) + m.result = Result{FloatType,TimeType}(m.equationInfo, m.timeName, m.w_invariant_names, m.vEliminated, m.vProperty, m.var_name) result = m.result - + if length(m.options.merge) > 0 m.parameters = mergeModels(m.parameters, m.options.merge) end @@ -1093,14 +1093,14 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti # Provide storage for x and der_x utility vectors nx = length(m.x_start) - nxSegmented = nx-equationInfo.nxInvariant + nxSegmented = nx-equationInfo.nxInvariant m.x_vec = [zeros(FloatType, equationInfo.x_info[i].length) for i in equationInfo.nx_info_fixedLength+1:equationInfo.nx_info_invariant] m.x_init = zeros(FloatType,nx) m.x_segmented = zeros(FloatType, nxSegmented) m.der_x_invariant = zeros(FloatType,equationInfo.nxInvariant) m.der_x_segmented = zeros(FloatType, nxSegmented) m.der_x = zeros(FloatType,nx) - + # Log parameters if m.options.logParameters parameters = m.parameters @@ -1165,7 +1165,7 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where m.options.startTime = m.time reinitEventHandlerForFullRestart!(eh, m.time, m.options.stopTime, m.options.logEvents) newResultSegment!(m.result, m.equationInfo, m.nsegments) - + # Evaluate instantiate functions for fc in m.instantiateFunctions logInstantiatedFunctionCalls = false @@ -1184,8 +1184,8 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where push!(resInfo.id, id) resInfo = m.result.info[xi_info.der_x_name] push!(resInfo.id, id) - end - + end + # Resize states and results nx = length(m.x_start) nxSegmented = nx - m.equationInfo.nxInvariant @@ -1486,8 +1486,8 @@ function affectEvent!(integrator, stateEvent::Bool, eventIndex::Int)::Nothing else printstyled(" restart = ", eh.restart, "\n", color=:red) end - end - + end + # Compute outputs and store them after the event occurred if m.addEventPointsDueToDEBug push!(integrator.sol.t, deepcopy(integrator.t)) @@ -1654,21 +1654,21 @@ end instantiatedModel::SimulationModel, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; nominal::Float64 = NaN, unbounded::Bool = false)::Int - + Reserves storage location for a new x_segmented and der_x_segmented variable and returns the index (= x_segmented_startIndex) to access this storage location, in particular - to copy state values from instantiatedModel.x_segmented[index:index+prod(dims(startOrInit))-1] into this storage location -- to copy state derivative values of this storage location to +- to copy state derivative values of this storage location to instantiatedModel.der_x_segmented[index:index+prod(dims(startOrInit))-1] Value startOrInit is the start/init value used during re-initialization of the new segment with initFullRestart!(..). -""" +""" function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_name::String, der_x_name::String, startOrInit, x_unit::String=""; nominal::Float64 = NaN, unbounded::Bool = false)::Int where {FloatType,TimeType} - eqInfo = m.equationInfo - result = m.result + eqInfo = m.equationInfo + result = m.result @assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known) new_result_info = true if haskey(result.info, x_name) @@ -1686,8 +1686,8 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam # error("new_x_segmented_variable(.. $x_name, $der_x_name, startOrInit,...): typeof(startOrInit) is neither a Number nor an AbstractVector)") #end @assert(get(x_info.signal,:unit,"") == x_unit) - @assert(haskey(result.info, der_x_name)) - der_x_info = result.info[der_x_name] + @assert(haskey(result.info, der_x_name)) + der_x_info = result.info[der_x_name] @assert(der_x_info.kind == RESULT_DER_X) end @@ -1707,24 +1707,24 @@ function new_x_segmented_variable!(m::SimulationModel{FloatType,TimeType}, x_nam eqInfo.x_dict[x_name] = x_infoIndex eqInfo.der_x_dict[der_x_name] = x_infoIndex eqInfo.nxSegmented += length(startOrInit) - + if new_result_info # result.info can be only partially instantiated, because x_startIndex is only known # after function initialStateVector!(...) was called. t_unit = get(result.info[result.timeName].signal, :unit, "") der_x_unit = x_unit == "" ? SignalTables.unitAsParseableString(unit(1/uparse(t_unit))) : SignalTables.unitAsParseableString(unit(uparse(x_unit)/uparse(t_unit))) if x_unit == "" - x_var = Var(start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) + x_var = Var(start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) else x_var = Var(unit=x_unit, start=xi_info.startOrInit, fixed=xi_info.fixed, state=true, der=xi_info.der_x_name) end - result.info[x_name] = ResultInfo(RESULT_X, x_var, FloatType) + result.info[x_name] = ResultInfo(RESULT_X, x_var, FloatType) if der_x_unit == "" - result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(), FloatType) + result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(), FloatType) else result.info[der_x_name] = ResultInfo(RESULT_DER_X, Var(unit=der_x_unit), FloatType) end - end + end return x_segmented_startIndex end @@ -1732,8 +1732,8 @@ end """ x_startIndex = get_x_startIndex_from_x_segmented_startIndex(instantiatedModel::SimulationModel, x_segmented_startIndex) -Return the startindex of an x_segmented state with respect to the x-vector, -given the startIndex with respect to the x_segmented vector +Return the startindex of an x_segmented state with respect to the x-vector, +given the startIndex with respect to the x_segmented vector (x_segmented_startIndex is the return value of new_x_segmented_variable!(..)). """ get_x_startIndex_from_x_segmented_startIndex(m::SimulationModel, x_segmented_startIndex::Int) = m.equationInfo.nxInvariant + x_segmented_startIndex @@ -1754,7 +1754,7 @@ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented push!(result.w_segmented_names, name) push!(result.w_segmented_temp, deepcopy(w_segmented_default)) w_index = length(result.w_segmented_temp) - + if haskey(result.info, name) # Variable was already defined in one of the previous segments v_info = result.info[name] @@ -1771,7 +1771,7 @@ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented signal = Var() else signal = Var(unit=unit) - end + end result.info[name] = ResultInfo(RESULT_W_SEGMENTED, signal, ValuesID(m.nsegments, w_index, w_size), eltypeOrType(w_segmented_default)) end #println("new_w_segmented_variable: w_segmented_temp = ", result.w_segmented_temp) diff --git a/src/Modia.jl b/src/Modia.jl index 0c52a50..5574ac1 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.9.0-dev" -const Date = "2022-07-04" +const Date = "2022-07-05" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -50,7 +50,24 @@ macro usingModiaPlot() if haskey(ENV, "SignalTablesPlotPackage") PlotPackage = ENV["SignalTablesPlotPackage"] if !(PlotPackage in AvailablePlotPackages) - @warn "ENV[\"SignalTablesPlotPackage\"] = \"$PlotPackage\" is not supported!. Using \"SilentNoPlot\"." + @info "ENV[\"SignalTablesPlotPackage\"] = \"$PlotPackage\" is not supported!. Using \"SilentNoPlot\"." + @goto USE_NO_PLOT + elseif PlotPackage == "NoPlot" + @goto USE_NO_PLOT + elseif PlotPackage == "SilentNoPlot" + expr = :( import SignalTables.SilentNoPlot: plot, showFigure, saveFigure, closeFigure, closeAllFigures ) + return esc( expr ) + else + PlotPackage = Symbol("SignalTablesInterface_" * PlotPackage) + expr = :(using $PlotPackage) + println("$expr") + return esc( :(using $PlotPackage) ) + end + + elseif haskey(ENV, "MODIA_PLOT_PACKAGE") + PlotPackage = ENV["MODIA_PLOT_PACKAGE"] + if !(PlotPackage in AvailablePlotPackages) + @info "ENV[\"MODIA_PLOT_PACKAGE\"] = \"$PlotPackage\" is not supported!. Using \"SilentNoPlot\"." @goto USE_NO_PLOT elseif PlotPackage == "NoPlot" @goto USE_NO_PLOT @@ -65,7 +82,7 @@ macro usingModiaPlot() end else - @warn "No plot package activated. Using \"SilentNoPlot\"." + @info "No plot package activated. Using \"SilentNoPlot\"." @goto USE_NO_PLOT end @@ -76,7 +93,6 @@ macro usingModiaPlot() end export @usingModiaPlot - export ModiaBase export CVODE_BDF, IDA export instantiateModel, @instantiateModel, assert, stringifyDefinition @@ -100,6 +116,10 @@ const CVODE_BDF = Sundials.CVODE_BDF const IDA = Sundials.IDA +# Deprecated functions - only provided for backwards compatibility +export signalNames, timeSignalName, hasOneTimeSignal, printResultInfo + + using Base.Meta: isexpr using OrderedCollections: OrderedDict diff --git a/src/SignalTablesInterface.jl b/src/SignalTablesInterface.jl index 6c23449..3f6373f 100644 --- a/src/SignalTablesInterface.jl +++ b/src/SignalTablesInterface.jl @@ -389,18 +389,11 @@ end - Second form: Return the **complete result** in form of a DataFrame object. Therefore, the whole functionality of package [DataFrames](https://dataframes.juliadata.org/stable/) can be used, including storing the result on file in different formats. - Furthermore, also plot can be used on dataFrame. - Parameters and zero-value variables are stored as SignalTables.OneValueVector inside dataFrame - (are treated as vectors, but actually only the value and the number - of time points is stored). If `onlyStates=true`, then only the states and the signals + Only scalar Var(..) variables are included in the DataFrame object. + If `onlyStates=true`, then only the states and the signals identified with `extraNames::Vector{String}` are stored in `dataFrame`. If `onlyStates=false` and `extraNames` given, then only the signals identified with `extraNames` are stored in `dataFrame`. - These keyword arguments are useful, if `dataFrame` shall be - utilized as reference result used in compareResults(..). - -In both cases, a **view** on the internal result memory is provided -(so result data is not copied). # Example @@ -437,85 +430,35 @@ reference = get_result(pendulum, onlyStates=true) println("Check results: success = $success") ``` """ -function get_result(m::SimulationModel, name::AbstractString; unit=true) - #(xsig, xsigLegend, ysig, ysigLegend, yIsConstant) = SignalTables.getPlotSignal(m, "time", name) - - #resIndex = m.variables[name] - #ysig = ResultView(m.result, abs(resIndex), resIndex < 0) - - #if SignalTables.timeSignalName(m) != 1 - if length(m.result.t) > 1 - error("Error in Modia.get_result(\"$name\"), because function cannot be used for a segmented simulation with more as one segmented.") - end - - (tsig2, ysig2, ysigType) = SignalTables.rawSignal(m, name) - ysig = ysig2[1] - ysig = unit ? ysig : stripUnit.(ysig) - - #= - if yIsConstant - if ndims(ysig) == 1 - ysig = fill(ysig[1], length(xsig)) - else - ysig = fill(ysig[1,:], length(xsig)) - end - end - =# - - return ysig -end - - -function setEvaluatedParametersInDataFrame!(obj::OrderedDict{Symbol,Any}, result_info, dataFrame::DataFrames.DataFrame, path::String, nResult::Int)::Nothing - for (key,value) in zip(keys(obj), obj) - name = appendName(path, key) - if typeof(value) <: OrderedDict{Symbol,Any} - setEvaluatedParametersInDataFrame!(value, result_info, dataFrame, name, nResult) - elseif !haskey(result_info, name) - dataFrame[!,name] = SignalTables.OneValueVector(value,nResult) - end - end - return nothing -end - +get_result(m::SimulationModel, name::AbstractString; unit=true) = unit ? getValuesWithUnit(m,name) : getValues(m,name) function get_result(m::SimulationModel; onlyStates=false, extraNames=missing) - error("get_result(instantiatedModel) is no longer supported") - - #= - if length(m.result.t) > 1 - error("Error in Modia.get_result(...), because function cannot be used for a segmented simulation with more as one segmented.") - end - dataFrame = DataFrames.DataFrame() - - (timeSignal, signal, signalType) = SignalTables.rawSignal(m, "time") - dataFrame[!,"time"] = timeSignal[1] + dataFrame[!,"time"] = getValues(m, "time") if onlyStates || !ismissing(extraNames) if onlyStates - for name in keys(m.equationInfo.x_dict) - (timeSignal, signal, signalType) = SignalTables.rawSignal(m, name) - dataFrame[!,name] = signal[1] + for name in getStateNames(m) + dataFrame[!,name] = getValues(m, name) end end if !ismissing(extraNames) for name in extraNames - (timeSignal, signal, signalType) = SignalTables.rawSignal(m, name) - dataFrame[!,name] = signal[1] + dataFrame[!,name] = getValues(m, name) end end else - for name in keys(m.result.info) + for name in getSignalNames(m, par=false) if name != "time" - (timeSignal, signal, signalType) = SignalTables.rawSignal(m, name) - dataFrame[!,name] = signal[1] + dataFrame[!,name] = getValues(m,name) end end - - setEvaluatedParametersInDataFrame!(m.evaluatedParameters, m.result.info, dataFrame, "", length(timeSignal[1])) end return dataFrame - =# -end \ No newline at end of file +end + +timeSignalName( m::SimulationModel) = "time" +hasOneTimeSignal(m::SimulationModel) = true +signalNames(m::SimulationModel) = sort!( getSignalNames(m) ) +printResultInfo(m::SimulationModel) = showInfo(m) diff --git a/src/SimulateAndPlot.jl b/src/SimulateAndPlot.jl index 653ac89..37e4315 100644 --- a/src/SimulateAndPlot.jl +++ b/src/SimulateAndPlot.jl @@ -64,10 +64,10 @@ and `simulate!(instantiatedModel, IDA(), ...)` can be used (instead of `import Sundials; simulate!(instantiatedModel, Sundials.xxx(), ...)`). The simulation results are stored in `instantiatedModel` and can be plotted with -`plot(instantiatedModel, ...)` and the result values -can be retrieved with `rawSignal(..)` or `getPlotSignal(..)`. `showResultInfo(instantiatedModel)` -prints information about the signals in the result file. -For more details, see sections [Parameters/Init/Start](@ref), [Results](@ref), [Plotting](@ref). +`plot(instantiatedModel, ...)`. The result values +can be retrieved with `getValues(..)` for Var(..) and `getValue(..)` for Par(..). +`showInfo(instantiatedModel)` prints information about the signals in the result. +For more details, see sections [Parameters/Init/Start](@ref), [Results and Plotting](@ref). The return argument `solution` is the return argument from `DifferentialEquations.solve(..)` and therefore all post-processing functionality from `DifferentialEqautions.jl` can be used. Especially, diff --git a/test/TestFirstOrder2.jl b/test/TestFirstOrder2.jl index 3a420d2..01922a7 100644 --- a/test/TestFirstOrder2.jl +++ b/test/TestFirstOrder2.jl @@ -7,35 +7,46 @@ using Modia.Test inputSignal(t) = sin(t) FirstOrder1 = Model( - T = 0.2, + T = 0.2u"s", x = Var(init=0.3), equations = :[u = inputSignal(time/u"s"), T * der(x) + x = u, y = 2*x] ) -FirstOrder2 = FirstOrder1 | Map(T = 0.3, x = Var(init=0.6)) +FirstOrder2 = FirstOrder1 | Map(T = 0.3u"s", x = Var(init=0.6)) firstOrder = @instantiateModel(FirstOrder2, logCode=false) -simulate!(firstOrder, Tsit5(), stopTime = 10, merge = Map(T = 0.4, x = 0.9), +simulate!(firstOrder, Tsit5(), stopTime = 10, merge = Map(T = 0.4u"s", x = 0.9), log=false, logParameters=true, logStates=true, requiredFinalStates = [-0.17964872595554535]) + +# Get result info +println("\n\n+++ Use SignalTables functions for post processing") + +println("\n... Show overview of result") showInfo(firstOrder) +println("\n... Get signal names, signals and signal info") +@show getSignalNames(firstOrder) +@show getStateNames(firstOrder) +sig_x = getSignal(firstOrder, "x") +@show getSignalInfo(firstOrder, "x") -# Get result info println("\n... Get values") -t = getValues(firstOrder, "time") -y = getValues(firstOrder, "y") -T = getValue( firstOrder, "T") -tWithUnit = getValuesWithUnit(firstOrder, "time") -@show t[1:10] -@show y[1:10] -@show T -@show tWithUnit[1:10] - -# Store result info on file +@show getValues(firstOrder, "time")[1:5] +@show getValues(firstOrder, "y")[1:5] +@show getValue( firstOrder, "T") + +@show getValuesWithUnit(firstOrder, "time")[1:5] +@show getValuesWithUnit(firstOrder, "y")[1:5] +@show getValueWithUnit( firstOrder, "T") + +sig_der_x_flattened = getFlattenedSignal(firstOrder, "der(x)") +@show sig_der_x_flattened[:flattenedValues][1:5] +@show sig_der_x_flattened[:legend] + println("\n... Store result on file in JSON format") writeSignalTable("TestFirstOrder2.json", firstOrder; indent=2, log=true) @@ -43,8 +54,29 @@ println("\n... Store states on file in JSON format") stateNames = getStateNames(firstOrder) writeSignalTable("TestFirstOrder2_states.json", firstOrder; signalNames=stateNames, indent=2, log=true) + +println("\n\n+++ Check deprecated functions\n") +result1 = get_result(firstOrder) +@show(result1[1:5,:]) +println() +@show(result1[1:5, ["time", "u", "y"]]) + +println() +result2 = get_result(firstOrder, onlyStates=true, extraNames=["y"]) +@show(result2[1:5,:]) + +println() +result3 = get_result(firstOrder, extraNames=["y"]) +@show(result3[1:5,:]) + +@show signalNames(firstOrder) +@show timeSignalName(firstOrder) +@show hasOneTimeSignal(firstOrder) +printResultInfo(firstOrder) + + # Linearize -println("\n... Linearize at stopTime = 0 and 10:") +println("\n\n+++ Linearize at stopTime = 0 and 10:") (A_0 , x_0) = linearize!(firstOrder, analytic = true) (A_10, x_10) = linearize!(firstOrder, stopTime=10, analytic = true) (A_10_numeric, x_10_numeric) = linearize!(firstOrder, stopTime=10, analytic=false) From 17c1b18caa7e7360236b92fe13c55fe0c3f8a2fc Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 5 Jul 2022 14:02:32 +0200 Subject: [PATCH 61/63] Add json file for docu --- docs/resources/fileio/firstOrder.json | 2546 +++++++++++++++++++++++++ 1 file changed, 2546 insertions(+) create mode 100644 docs/resources/fileio/firstOrder.json diff --git a/docs/resources/fileio/firstOrder.json b/docs/resources/fileio/firstOrder.json new file mode 100644 index 0000000..0660796 --- /dev/null +++ b/docs/resources/fileio/firstOrder.json @@ -0,0 +1,2546 @@ +{ + "_class": "SignalTable", + "_classVersion": "0.3.1", + "time": { + "_class": "Var", + "unit": "s", + "independent": true, + "values": [ + 0.0, + 0.02, + 0.04, + 0.06, + 0.08, + 0.1, + 0.12, + 0.14, + 0.16, + 0.18, + 0.2, + 0.22, + 0.24, + 0.26, + 0.28, + 0.3, + 0.32, + 0.34, + 0.36, + 0.38, + 0.4, + 0.42, + 0.44, + 0.46, + 0.48, + 0.5, + 0.52, + 0.54, + 0.56, + 0.58, + 0.6, + 0.62, + 0.64, + 0.66, + 0.68, + 0.7, + 0.72, + 0.74, + 0.76, + 0.78, + 0.8, + 0.82, + 0.84, + 0.86, + 0.88, + 0.9, + 0.92, + 0.94, + 0.96, + 0.98, + 1.0, + 1.02, + 1.04, + 1.06, + 1.08, + 1.1, + 1.12, + 1.14, + 1.16, + 1.18, + 1.2, + 1.22, + 1.24, + 1.26, + 1.28, + 1.3, + 1.32, + 1.34, + 1.36, + 1.38, + 1.4, + 1.42, + 1.44, + 1.46, + 1.48, + 1.5, + 1.52, + 1.54, + 1.56, + 1.58, + 1.6, + 1.62, + 1.64, + 1.66, + 1.68, + 1.7, + 1.72, + 1.74, + 1.76, + 1.78, + 1.8, + 1.82, + 1.84, + 1.86, + 1.88, + 1.9, + 1.92, + 1.94, + 1.96, + 1.98, + 2.0, + 2.02, + 2.04, + 2.06, + 2.08, + 2.1, + 2.12, + 2.14, + 2.16, + 2.18, + 2.2, + 2.22, + 2.24, + 2.26, + 2.28, + 2.3, + 2.32, + 2.34, + 2.36, + 2.38, + 2.4, + 2.42, + 2.44, + 2.46, + 2.48, + 2.5, + 2.52, + 2.54, + 2.56, + 2.58, + 2.6, + 2.62, + 2.64, + 2.66, + 2.68, + 2.7, + 2.72, + 2.74, + 2.76, + 2.78, + 2.8, + 2.82, + 2.84, + 2.86, + 2.88, + 2.9, + 2.92, + 2.94, + 2.96, + 2.98, + 3.0, + 3.02, + 3.04, + 3.06, + 3.08, + 3.1, + 3.12, + 3.14, + 3.16, + 3.18, + 3.2, + 3.22, + 3.24, + 3.26, + 3.28, + 3.3, + 3.32, + 3.34, + 3.36, + 3.38, + 3.4, + 3.42, + 3.44, + 3.46, + 3.48, + 3.5, + 3.52, + 3.54, + 3.56, + 3.58, + 3.6, + 3.62, + 3.64, + 3.66, + 3.68, + 3.7, + 3.72, + 3.74, + 3.76, + 3.78, + 3.8, + 3.82, + 3.84, + 3.86, + 3.88, + 3.9, + 3.92, + 3.94, + 3.96, + 3.98, + 4.0, + 4.02, + 4.04, + 4.06, + 4.08, + 4.1, + 4.12, + 4.14, + 4.16, + 4.18, + 4.2, + 4.22, + 4.24, + 4.26, + 4.28, + 4.3, + 4.32, + 4.34, + 4.36, + 4.38, + 4.4, + 4.42, + 4.44, + 4.46, + 4.48, + 4.5, + 4.52, + 4.54, + 4.56, + 4.58, + 4.6, + 4.62, + 4.64, + 4.66, + 4.68, + 4.7, + 4.72, + 4.74, + 4.76, + 4.78, + 4.8, + 4.82, + 4.84, + 4.86, + 4.88, + 4.9, + 4.92, + 4.94, + 4.96, + 4.98, + 5.0, + 5.02, + 5.04, + 5.06, + 5.08, + 5.1, + 5.12, + 5.14, + 5.16, + 5.18, + 5.2, + 5.22, + 5.24, + 5.26, + 5.28, + 5.3, + 5.32, + 5.34, + 5.36, + 5.38, + 5.4, + 5.42, + 5.44, + 5.46, + 5.48, + 5.5, + 5.52, + 5.54, + 5.56, + 5.58, + 5.6, + 5.62, + 5.64, + 5.66, + 5.68, + 5.7, + 5.72, + 5.74, + 5.76, + 5.78, + 5.8, + 5.82, + 5.84, + 5.86, + 5.88, + 5.9, + 5.92, + 5.94, + 5.96, + 5.98, + 6.0, + 6.02, + 6.04, + 6.06, + 6.08, + 6.1, + 6.12, + 6.14, + 6.16, + 6.18, + 6.2, + 6.22, + 6.24, + 6.26, + 6.28, + 6.3, + 6.32, + 6.34, + 6.36, + 6.38, + 6.4, + 6.42, + 6.44, + 6.46, + 6.48, + 6.5, + 6.52, + 6.54, + 6.56, + 6.58, + 6.6, + 6.62, + 6.64, + 6.66, + 6.68, + 6.7, + 6.72, + 6.74, + 6.76, + 6.78, + 6.8, + 6.82, + 6.84, + 6.86, + 6.88, + 6.9, + 6.92, + 6.94, + 6.96, + 6.98, + 7.0, + 7.02, + 7.04, + 7.06, + 7.08, + 7.1, + 7.12, + 7.14, + 7.16, + 7.18, + 7.2, + 7.22, + 7.24, + 7.26, + 7.28, + 7.3, + 7.32, + 7.34, + 7.36, + 7.38, + 7.4, + 7.42, + 7.44, + 7.46, + 7.48, + 7.5, + 7.52, + 7.54, + 7.56, + 7.58, + 7.6, + 7.62, + 7.64, + 7.66, + 7.68, + 7.7, + 7.72, + 7.74, + 7.76, + 7.78, + 7.8, + 7.82, + 7.84, + 7.86, + 7.88, + 7.9, + 7.92, + 7.94, + 7.96, + 7.98, + 8.0, + 8.02, + 8.04, + 8.06, + 8.08, + 8.1, + 8.12, + 8.14, + 8.16, + 8.18, + 8.2, + 8.22, + 8.24, + 8.26, + 8.28, + 8.3, + 8.32, + 8.34, + 8.36, + 8.38, + 8.4, + 8.42, + 8.44, + 8.46, + 8.48, + 8.5, + 8.52, + 8.54, + 8.56, + 8.58, + 8.6, + 8.62, + 8.64, + 8.66, + 8.68, + 8.7, + 8.72, + 8.74, + 8.76, + 8.78, + 8.8, + 8.82, + 8.84, + 8.86, + 8.88, + 8.9, + 8.92, + 8.94, + 8.96, + 8.98, + 9.0, + 9.02, + 9.04, + 9.06, + 9.08, + 9.1, + 9.12, + 9.14, + 9.16, + 9.18, + 9.2, + 9.22, + 9.24, + 9.26, + 9.28, + 9.3, + 9.32, + 9.34, + 9.36, + 9.38, + 9.4, + 9.42, + 9.44, + 9.46, + 9.48, + 9.5, + 9.52, + 9.54, + 9.56, + 9.58, + 9.6, + 9.62, + 9.64, + 9.66, + 9.68, + 9.7, + 9.72, + 9.74, + 9.76, + 9.78, + 9.8, + 9.82, + 9.84, + 9.86, + 9.88, + 9.9, + 9.92, + 9.94, + 9.96, + 9.98, + 10.0 + ] + }, + "x": { + "_class": "Var", + "start": 0.9, + "fixed": true, + "state": true, + "der": "der(x)", + "values": [ + 0.9, + 0.8565982352579431, + 0.8162883820630357, + 0.7789190587163852, + 0.7443458777011582, + 0.7124311042983924, + 0.6830433294226499, + 0.6560571694793818, + 0.6313529650339109, + 0.6088165023811362, + 0.5883387697791976, + 0.5698156586748554, + 0.5531477894255408, + 0.5382402268804796, + 0.5250022785568708, + 0.5133473362556056, + 0.5031926025645421, + 0.49445894621024844, + 0.4870707648647274, + 0.4809557373191824, + 0.4760446980414887, + 0.47227153157238916, + 0.469572971191424, + 0.46788845051080363, + 0.4671600298285677, + 0.46733227310406295, + 0.46835205074468017, + 0.4701684897066516, + 0.4727328932570714, + 0.4759985975073567, + 0.47992084745107716, + 0.4844567599176045, + 0.48956525641887577, + 0.4952069214566648, + 0.501343922798723, + 0.5079399800981385, + 0.5149603111381504, + 0.5223715140773448, + 0.5301414941682792, + 0.5382394474729053, + 0.5466358107705377, + 0.5553021917721903, + 0.5642112745509354, + 0.5733368144605867, + 0.5826535948996154, + 0.5921374050400957, + 0.6017649386395428, + 0.6115137661081619, + 0.6213623287533296, + 0.6312898950755759, + 0.6412765434628062, + 0.6513030780922622, + 0.6613510175674602, + 0.6714025919084436, + 0.6814407009289839, + 0.6914489088759876, + 0.7014113771519744, + 0.7113128491916927, + 0.7211386504621206, + 0.7308746713545446, + 0.740507332873744, + 0.7500235761425502, + 0.7594108188077999, + 0.7686569539211948, + 0.7777503499393023, + 0.7866798398289473, + 0.7954346754723045, + 0.8040045313438655, + 0.8123794742996325, + 0.8205499612275748, + 0.8285068390476285, + 0.8362413447116959, + 0.8437451018026174, + 0.8510100596918102, + 0.8580284838992834, + 0.8647929695155617, + 0.8712964380981615, + 0.8775321376715912, + 0.8834936427273516, + 0.8891748542239352, + 0.894569981275442, + 0.8996734513176099, + 0.9044799697719661, + 0.9089845255747637, + 0.9131823890745424, + 0.917069112032129, + 0.9206405276206373, + 0.9238927389903993, + 0.9268220415096394, + 0.9294249535733635, + 0.9316982463939087, + 0.9336389439467769, + 0.9352443229706352, + 0.9365119129673148, + 0.9374394878040079, + 0.9380249806578439, + 0.9382665136992564, + 0.9381624393231933, + 0.9377113395419854, + 0.9369120259853461, + 0.9357635399003719, + 0.9342651434790417, + 0.9324162365495077, + 0.9302163856721876, + 0.9276653688973338, + 0.9247631759271093, + 0.9215100081155881, + 0.9179062784687546, + 0.9139526001975913, + 0.9096496994395332, + 0.9049984579386919, + 0.8999999527842305, + 0.8946554561677271, + 0.8889664353831751, + 0.882934552826982, + 0.8765616484770593, + 0.8698496546023675, + 0.8628006540506648, + 0.8554169092246189, + 0.8477008618666222, + 0.839655133058792, + 0.8312825232229709, + 0.822585983259938, + 0.8135685405799888, + 0.8042333704121106, + 0.7945838111043143, + 0.7846233640808712, + 0.7743556938423126, + 0.7637846277017275, + 0.7529141091488882, + 0.7417481544265105, + 0.7302909203806491, + 0.7185467098676414, + 0.7065199717541081, + 0.6942153009169525, + 0.6816374354895186, + 0.668791192537012, + 0.6556814671331432, + 0.6423132819604379, + 0.6286917874920527, + 0.6148222619917771, + 0.6007101115140321, + 0.5863608594815349, + 0.5717800766688449, + 0.5569734194749433, + 0.5419466534565509, + 0.5267056525809867, + 0.5112563992261692, + 0.49560498418061344, + 0.4797575800236832, + 0.46372039199894377, + 0.4474997099733483, + 0.4311019117586864, + 0.41453346309060657, + 0.3978009176286149, + 0.38091091541280087, + 0.3638701363511825, + 0.3466852977115287, + 0.32936318523635466, + 0.3119106511883391, + 0.2943346143503238, + 0.2766420600253153, + 0.25884003062392225, + 0.24093557830526974, + 0.2229357961478195, + 0.20484782269914156, + 0.18667884095239334, + 0.1684360783463202, + 0.15012680667461548, + 0.13175831611183625, + 0.1133379011889344, + 0.0948728837713298, + 0.07637060773512665, + 0.057838438967112944, + 0.0392837653647616, + 0.020713992509908945, + 0.0021365128572256144, + -0.016441275555525704, + -0.03501197285625358, + -0.05356817959563506, + -0.07210249674711632, + -0.09060752572214205, + -0.10907588442297514, + -0.12750020951774438, + -0.1458731504873097, + -0.16418737963608498, + -0.18243559209203808, + -0.20061050580669063, + -0.21870486357680444, + -0.23671145627870127, + -0.2546230848423538, + -0.27243258772257795, + -0.2901328521672389, + -0.3077168142172515, + -0.325177458706579, + -0.34250781926223484, + -0.35970097830428, + -0.37675007873538097, + -0.393648309883841, + -0.4103888987156194, + -0.42696514719500556, + -0.4433704328316828, + -0.45959820868073104, + -0.47564200334262163, + -0.491495420963224, + -0.5071521457963817, + -0.5226059046121583, + -0.5378504948059546, + -0.5528798122916981, + -0.5676878515040037, + -0.5822687053981777, + -0.5966165654502144, + -0.6107257227284227, + -0.6245905477809309, + -0.6382054622383442, + -0.6515649989450867, + -0.664663809420763, + -0.6774966638601544, + -0.6900584511332215, + -0.7023441787851026, + -0.714348965719734, + -0.7260679857528834, + -0.7374965162724549, + -0.7486299702577763, + -0.7594638963099389, + -0.7699939786517939, + -0.7802160371279548, + -0.7901260247916257, + -0.799719972051436, + -0.8089939969914384, + -0.8179443648636598, + -0.8265674902966469, + -0.8348599372954619, + -0.842818419241687, + -0.8504397981839735, + -0.8577210370045906, + -0.8646591754709685, + -0.871251405933291, + -0.8774950804665336, + -0.8833877108704655, + -0.8889269686696483, + -0.8941106848834469, + -0.8989368084781059, + -0.9034033611363448, + -0.9075085192260695, + -0.9112506258017946, + -0.9146281906046424, + -0.9176398900623441, + -0.9202845671464538, + -0.9225611909855597, + -0.9244688032893533, + -0.9260066020962575, + -0.927173955676972, + -0.9279704025344732, + -0.9283956514040145, + -0.9284495810098127, + -0.9281321951520967, + -0.927443572452179, + -0.9263839500292788, + -0.9249537354448624, + -0.9231535067026436, + -0.9209840122485841, + -0.9184461701916481, + -0.915541013263216, + -0.9122696542939989, + -0.908633366068284, + -0.9046335888257583, + -0.9002719302615096, + -0.895550165526026, + -0.890470234617942, + -0.8850341737438407, + -0.8792441088220262, + -0.8731023241555405, + -0.8666112654447986, + -0.8597735397875871, + -0.8525919156790652, + -0.8450693155335764, + -0.8372087357714905, + -0.8290132758548727, + -0.8204861873259481, + -0.8116308741429792, + -0.8024508926802633, + -0.7929499517281349, + -0.7831318943007293, + -0.7730006190773465, + -0.7625601403777232, + -0.7518146134408926, + -0.7407683342424489, + -0.7294257394945517, + -0.7177914065894163, + -0.7058700154875813, + -0.693666298035065, + -0.6811851050615423, + -0.6684314139983423, + -0.6554103288784512, + -0.6421270803365093, + -0.6285870231763357, + -0.6147955765328467, + -0.6007582218829027, + -0.5864805507151761, + -0.5719682648164878, + -0.5572271762718043, + -0.5422632074642364, + -0.5270823796283539, + -0.5116907477541665, + -0.49609444084863424, + -0.48029968069814943, + -0.46431278122802233, + -0.44814014850247574, + -0.4317882806966074, + -0.41526373704079633, + -0.3985731025625752, + -0.381723034020657, + -0.36472026064003366, + -0.3475715841119704, + -0.3302838785940118, + -0.3128640873824501, + -0.2953191750953447, + -0.27765614022168666, + -0.25988203485861616, + -0.2420039627478515, + -0.22402907927569585, + -0.2059645914730311, + -0.18781774295442497, + -0.1695957779746208, + -0.1513059740466132, + -0.1329556390075606, + -0.11455211075450134, + -0.09610275724435705, + -0.07761497523320811, + -0.05909615940200198, + -0.04055370827305208, + -0.02199503262462688, + -0.0034275513567013534, + 0.015141308509036711, + 0.03370411182919006, + 0.05225342484657266, + 0.07078183496667288, + 0.08928193218910896, + 0.10774631974590226, + 0.12616761457784567, + 0.14453844733450982, + 0.1628514642394603, + 0.18109934606759245, + 0.1992747886045692, + 0.21737051876240307, + 0.23537930027204537, + 0.25329393368339287, + 0.2711072563652812, + 0.28881214250549, + 0.3064015286598028, + 0.32386838931524714, + 0.34120570360437136, + 0.3584065171401999, + 0.37546394278284284, + 0.3923711606394899, + 0.4091214180644169, + 0.4257080296589782, + 0.4421243772716159, + 0.45836391003030735, + 0.4744201342035553, + 0.49028660146227837, + 0.5059569473886251, + 0.5214248983715758, + 0.5366842716069499, + 0.5517289750973985, + 0.5665530076556223, + 0.5811504685728967, + 0.5955154997625265, + 0.6096423188371141, + 0.6235252569417028, + 0.6371587587537729, + 0.6505373824832462, + 0.6636557998724812, + 0.6765087962109143, + 0.6890912495763188, + 0.7013980893463508, + 0.7134243606246256, + 0.7251652391373933, + 0.7366160312335435, + 0.7477721738845997, + 0.7586292346847249, + 0.7691829077796379, + 0.7794289515251445, + 0.7893632225778422, + 0.7989817232326639, + 0.8082806018818076, + 0.8172561530147402, + 0.8259048172181935, + 0.8342231797248292, + 0.8422079165012685, + 0.8498557839713899, + 0.8571636907306843, + 0.8641287024894667, + 0.8707480420728747, + 0.8770190894208698, + 0.8829393813762016, + 0.8885065704267063, + 0.8937183802081385, + 0.8985726877257645, + 0.9030675352803323, + 0.9072011304680742, + 0.9109718461807045, + 0.9143782205550706, + 0.9174189211082179, + 0.9200926842485485, + 0.9223983992726965, + 0.9243351251605426, + 0.9259020905752148, + 0.9270986938630881, + 0.9279245030210196, + 0.9283792201712311, + 0.9284626169989881, + 0.9281746185248785, + 0.9275153206424119, + 0.9264849901180203, + 0.9250840645910577, + 0.9233131524572371, + 0.9211729909983937, + 0.9186643888508338, + 0.9157883098203079, + 0.9125458864064132, + 0.9089384198025945, + 0.9049673798961436, + 0.9006344046282564, + 0.8959412463731505, + 0.8908897339296598, + 0.8854818518501539, + 0.879719748164385, + 0.8736057343794883, + 0.86714228547998, + 0.8603320373284216, + 0.8531777182035908, + 0.8456821425375541, + 0.837848277385476, + 0.829679245039067, + 0.821178323026584, + 0.8123489441128317, + 0.8031946882751377, + 0.7937192035100462, + 0.7839262372763351, + 0.7738196812273413, + 0.7634035712719819, + 0.7526820875747576, + 0.7416595545557513, + 0.7303404209172931, + 0.7187291850912106, + 0.7068304561386672, + 0.6946489740364391, + 0.6821896094970831, + 0.6694573639689315, + 0.6564573694596935, + 0.6431948472263584, + 0.6296750671307768, + 0.6159034093460247, + 0.6018853690184681, + 0.5876265562677679, + 0.5731326961868758, + 0.5584096252891738, + 0.5434632308696737, + 0.5282994599379637, + 0.5129243573939016, + 0.49734406540302156, + 0.48156482339652507, + 0.4655929680712877, + 0.44943491881888914, + 0.43309711934760076, + 0.41658608147155246, + 0.3999083954212266, + 0.38307072937987535, + 0.3660798294835263, + 0.3489425195221907, + 0.3316656655045036, + 0.3142561562916227, + 0.29672093984541875, + 0.279067021519296, + 0.2613014640581988, + 0.24343138759860874, + 0.225463964154063, + 0.2074063728313271, + 0.18926582203186845, + 0.17104955782117817, + 0.15276486222791397, + 0.13441905324390668, + 0.11601948482414896, + 0.09757352708822618, + 0.07908854621696682, + 0.060571928817045075, + 0.042031075567069184, + 0.023473401215096345, + 0.004906334578627861, + -0.013662684535363366, + -0.03222623331367467, + -0.05077689019980227, + -0.06930723863534724, + -0.08780986991095488, + -0.10627738316632404, + -0.12470238539149257, + -0.14307750364175914, + -0.1613953927014523, + -0.17964872595554732 + ] + }, + "der(x)": { + "_class": "Var", + "unit": "1/s", + "values": [ + -2.25, + -2.091498921411525, + -1.9407476196910036, + -1.7973876305923515, + -1.6610779593299636, + -1.5314942191289105, + -1.4083278053343262, + -1.291285137087863, + -1.1800868960491622, + -1.07446732238828, + -0.974173597460341, + -0.8789650889849651, + -0.7886129074960154, + -0.702899187470811, + -0.6216165749818925, + -0.5445678239856651, + -0.4715651048710609, + -0.4024296351735851, + -0.3369913289740936, + -0.27508816976549927, + -0.21656588933209542, + -0.16127769628204752, + -0.10908376531356095, + -0.05985085886320962, + -0.013452135717712116, + 0.03023316375035015, + 0.07132021774764144, + 0.10991875486615399, + 0.14613326165952997, + 0.1800633482112922, + 0.21180406485989553, + 0.24144600154925144, + 0.2690754623587908, + 0.29477482629192253, + 0.31862275304936405, + 0.3406942678488814, + 0.36106090208330666, + 0.37979099387700055, + 0.3969498773556804, + 0.4125999293187621, + 0.42680070032246276, + 0.4396090948867637, + 0.45107961354980963, + 0.46126437108672563, + 0.4702132099983847, + 0.47797376146846926, + 0.484591703492058, + 0.49011083574238085, + 0.49457309886917156, + 0.4980186885409865, + 0.5004861033627258, + 0.5020123596427519, + 0.5026330241896956, + 0.5023822260913565, + 0.501292764889909, + 0.49939612796361943, + 0.49672266256132663, + 0.4933016173104762, + 0.48916114577411574, + 0.4843283526336892, + 0.4788293827337056, + 0.47268945044129346, + 0.46593295160434756, + 0.45858346917330234, + 0.45066377587480666, + 0.44219586397061417, + 0.4332010616149018, + 0.4237000258786347, + 0.4137128203392093, + 0.4032589228619621, + 0.39235722735207923, + 0.3810260453500597, + 0.36928311597267255, + 0.35714575929958664, + 0.3446309015958915, + 0.3317550427212318, + 0.3185342646935538, + 0.3049842323347196, + 0.29112019375653664, + 0.2769569806870123, + 0.26250905441515787, + 0.24779073038228516, + 0.23281602886801894, + 0.21759866085443252, + 0.20215203280883387, + 0.18648924605084882, + 0.1706230959601604, + 0.1545660996128856, + 0.1383306890699476, + 0.12192913308670283, + 0.105373461210716, + 0.08867546233419843, + 0.07184668295453223, + 0.0548984252789983, + 0.03784176616896867, + 0.02068776757392643, + 0.003447399965171294, + -0.013868563252482091, + -0.03124954688454279, + -0.0486851767588406, + -0.06616528268672539, + -0.08367987989103598, + -0.10121896399032021, + -0.11877258714053374, + -0.13633097347454326, + -0.15388452319558904, + -0.17142381640677995, + -0.18893961708027235, + -0.2064228485472705, + -0.2238643795453979, + -0.2412551352977546, + -0.2585862013703599, + -0.27584882770826824, + -0.2930344334076229, + -0.3101346116151499, + -0.32714109075084763, + -0.34404552643029024, + -0.36083965245384625, + -0.3775153586361066, + -0.39406469577421444, + -0.4104798812691027, + -0.4267533048594255, + -0.4428774623139181, + -0.4588447764602416, + -0.4746477815159972, + -0.4902791675008947, + -0.5057317863919732, + -0.5209986584840245, + -0.5360729781865022, + -0.5509480039831677, + -0.5656169565126159, + -0.5800731949220264, + -0.5943102371974827, + -0.6083217670594072, + -0.6221016409377034, + -0.635643888139222, + -0.6489425571624868, + -0.6619917205867276, + -0.6747856063384555, + -0.687318605477274, + -0.6995852795896801, + -0.7115803682424456, + -0.7232987704367563, + -0.7347353771306453, + -0.745885174534581, + -0.7567433106064211, + -0.7673051008896743, + -0.7775660362609965, + -0.7875217907159512, + -0.7971681626405686, + -0.8065009598476913, + -0.8155161373567963, + -0.8242098136052113, + -0.8325782783258436, + -0.8406180004967543, + -0.8483256324487759, + -0.8556979015627162, + -0.8627316119876046, + -0.8694237304235211, + -0.8757713892339362, + -0.8817718944447597, + -0.8874227337404513, + -0.8927215609225773, + -0.8976660854927178, + -0.9022541585476158, + -0.9064837921059744, + -0.9103531644831336, + -0.913860628202475, + -0.9170047176549878, + -0.9197840920218331, + -0.922197508039414, + -0.9242438852361345, + -0.9259223003767356, + -0.9272319951752078, + -0.9281723839637391, + -0.928743050498822, + -0.9289436785042567, + -0.9287741059655115, + -0.928234323220408, + -0.9273244747198689, + -0.9260448663693402, + -0.9243959727671406, + -0.9223784042809193, + -0.9199929084977513, + -0.9172403921710351, + -0.914121903181021, + -0.9106386374431227, + -0.9067919457341985, + -0.9025833353798459, + -0.8980144188226565, + -0.8930870152509127, + -0.8878030883917883, + -0.8821647247166748, + -0.8761741397191336, + -0.8698336840924566, + -0.8631458498043473, + -0.8561132760663135, + -0.8487387259714738, + -0.8410251273886463, + -0.832975600571638, + -0.8245933702823066, + -0.8158817698308525, + -0.8068442463648043, + -0.797484366036938, + -0.7878058190500412, + -0.7778124131700714, + -0.7675081724980315, + -0.7568972718605999, + -0.7459839716096908, + -0.7347726220168421, + -0.7232676675385263, + -0.7114736509452774, + -0.6993952146339144, + -0.6870371547606169, + -0.6744044959451531, + -0.6615023445109205, + -0.6483358732560623, + -0.6349103247327204, + -0.6212310143797158, + -0.6073033335074018, + -0.5931327704244551, + -0.5787250542409691, + -0.5640860357521543, + -0.549221609772327, + -0.5341377172880873, + -0.5188403475332578, + -0.5033355399089012, + -0.48762939178058434, + -0.4717281997192363, + -0.4556384351520715, + -0.4393665969245114, + -0.42291920691399615, + -0.40630281100657833, + -0.38952397991452975, + -0.37258931160827624, + -0.35550555139877565, + -0.33827965214764, + -0.32091858520223615, + -0.3034293225597015, + -0.28581883672606945, + -0.26809410041548104, + -0.25026208666456107, + -0.23232987208201689, + -0.21430474914506253, + -0.19619402033900224, + -0.17800496705634467, + -0.1597448483412403, + -0.14142089947616232, + -0.1230403307683875, + -0.10461042678992699, + -0.08613867843446282, + -0.06763257151027546, + -0.049099549789092256, + -0.030547012660388784, + -0.011982312633207759, + 0.006587246705200556, + 0.025154301207074292, + 0.043711303476171026, + 0.06225073515730983, + 0.08076514004156932, + 0.09924712745622621, + 0.1176893757989042, + 0.1360846342664343, + 0.1544255890716817, + 0.17270478109395554, + 0.19091480961095697, + 0.2090483552862782, + 0.22709818453722552, + 0.24505715403580403, + 0.26291820882290345, + 0.280674215469634, + 0.29831795072616296, + 0.3158422782193204, + 0.33324016112285526, + 0.350504667417699, + 0.36762897527168326, + 0.3846063598411234, + 0.40142999910008387, + 0.4180930521545878, + 0.4345887876744117, + 0.4509105906766439, + 0.46705196857544234, + 0.4830065573352277, + 0.49876808224430497, + 0.5143301678709447, + 0.5296864944502141, + 0.5448308676231208, + 0.5597572246125504, + 0.574459640944123, + 0.5889323371112118, + 0.6031695901845598, + 0.6171656140740873, + 0.6309147343203659, + 0.6444114142600035, + 0.6576502622174932, + 0.6706260387656833, + 0.6833336579707328, + 0.6957680451858561, + 0.7079241395271697, + 0.7197970205539563, + 0.7313819165439047, + 0.7426742121033384, + 0.753669455825193, + 0.764363339374986, + 0.7747515424950938, + 0.7848298414413459, + 0.794594163707488, + 0.8040405942744094, + 0.8131653834898142, + 0.8219649549037739, + 0.8304358355582498, + 0.8385745757899061, + 0.8463778720298207, + 0.8538425766191355, + 0.8609657057970811, + 0.8677444476959038, + 0.8741761620206925, + 0.8802582685060569, + 0.885988286285514, + 0.8913638912250834, + 0.8963829189958628, + 0.9010433730432338, + 0.9053434325406075, + 0.9092814226722724, + 0.9128557326879128, + 0.9160649053360717, + 0.9189076373891014, + 0.9213827868113111, + 0.9234893805534236, + 0.9252266191576944, + 0.9265938072884495, + 0.9275903761959076, + 0.9282159123784043, + 0.928470154822715, + 0.9283530025271065, + 0.9278645219685205, + 0.9270049307410605, + 0.9257745554613236, + 0.9241738854714533, + 0.922203553457493, + 0.9198643414019061, + 0.9171571876536063, + 0.9140831892586762, + 0.9106435614317737, + 0.9068396932404345, + 0.9026731140644928, + 0.8981454860257082, + 0.8932586105589655, + 0.8880144348909366, + 0.8824150584236093, + 0.8764626751474656, + 0.8701596409190357, + 0.8635085627581677, + 0.8565121502384956, + 0.8491732194412874, + 0.841494698715965, + 0.8334796343284621, + 0.8251311959951888, + 0.8164526823003498, + 0.8074475259133566, + 0.7981193241139946, + 0.7884718731923371, + 0.7785090771063696, + 0.7682349350456488, + 0.7576535461050751, + 0.7467691138279148, + 0.7355859506081985, + 0.7241084577954862, + 0.7123412744762697, + 0.7002891987831139, + 0.6879570971748102, + 0.6753499081585276, + 0.6624726458696084, + 0.6493304035075942, + 0.6359283565904983, + 0.6222718179960501, + 0.6083663446795073, + 0.5942175794562085, + 0.5798312164575592, + 0.5652130036775666, + 0.5503687453672165, + 0.5353043042757222, + 0.5200256139154624, + 0.5045388363480441, + 0.4888502787342966, + 0.4729662766108411, + 0.45689319420620544, + 0.4406374257466891, + 0.42420539660415313, + 0.4076035679135917, + 0.3908385721833413, + 0.37391723965784496, + 0.3568464195432272, + 0.33963296800097215, + 0.32228374833974865, + 0.3048056310472555, + 0.2872054941921817, + 0.26949032628039826, + 0.2516673370500047, + 0.23374375130983366, + 0.2157267783576236, + 0.19762361105402387, + 0.1794414247378942, + 0.16118737610919198, + 0.14286869149054277, + 0.12449281649134447, + 0.10606720430098693, + 0.08759927183080385, + 0.06909639768839876, + 0.05056591999760468, + 0.03201513414688384, + 0.01345137911604899, + -0.005117803755554928, + -0.023684882987884404, + -0.042242383741703804, + -0.0607828909043176, + -0.07929905232226447, + -0.09778358188831104, + -0.11622915838857106, + -0.13462828533902987, + -0.1529735043300684, + -0.17125743278452288, + -0.18947276804307134, + -0.20761229158635347, + -0.22566887179225392, + -0.2436353343741507, + -0.26150437198182636, + -0.27926874727535134, + -0.2969213171140267, + -0.3144550375614963, + -0.33186296901466655, + -0.34913827495600874, + -0.36627405616928205, + -0.38326334056998423, + -0.4000992549829732, + -0.4167750373922091, + -0.43328404276766597, + -0.4496197490006634, + -0.46577574288523244, + -0.48174552827988965, + -0.49752261096143363, + -0.5131006168006793, + -0.5284732983561224, + -0.5436345414086036, + -0.5585783715869402, + -0.5732989111485212, + -0.5877901993970266, + -0.6020463518144903, + -0.6160616177396355, + -0.6298303869582859, + -0.6433471968179373, + -0.6566067389730146, + -0.6696037633647391, + -0.6823329839311205, + -0.6947892402568928, + -0.7069675166727899, + -0.7188629497567074, + -0.730470835888935, + -0.741786629976278, + -0.7528058015093749, + -0.7635238645942901, + -0.7739364811328651, + -0.7840394670410963, + -0.7938288000646789, + -0.803300627627076, + -0.8124512382795686, + -0.8212769236599138, + -0.8297740958920776, + -0.8379393213091516, + -0.8457693272578377, + -0.8532610100754213, + -0.8604114423301553, + -0.8672177922273383, + -0.8736772831925296, + -0.8797872924912331, + -0.8855453549527633, + -0.8909491709613994, + -0.8959966144387083, + -0.9006857270276462, + -0.905014614088065, + -0.9089815081371202, + -0.9125847976876885, + -0.9158230308866316, + -0.9186949233773026, + -0.9211993661310176, + -0.9233353837479216, + -0.925102091958644, + -0.9264987662554203, + -0.9275248336834908, + -0.9281798804644783, + -0.9284636595763907, + -0.9283760905810482, + -0.9279171971377372, + -0.9270871537589748, + -0.9258862838085069, + -0.9243150596609162, + -0.9223741099211393, + -0.9200642265704191, + -0.917386341504988, + -0.9143415143765843, + -0.9109309623345561 + ] + }, + "u": { + "_class": "Var", + "values": [ + 0.0, + 0.01999866669333308, + 0.03998933418663416, + 0.059964006479444595, + 0.0799146939691727, + 0.09983341664682815, + 0.11971220728891936, + 0.1395431146442365, + 0.15931820661424598, + 0.17902957342582418, + 0.19866933079506122, + 0.21822962308086932, + 0.23770262642713458, + 0.2570805518921551, + 0.27635564856411376, + 0.29552020666133955, + 0.31456656061611776, + 0.3334870921408144, + 0.35227423327508994, + 0.3709204694129827, + 0.3894183423086505, + 0.40776045305957015, + 0.4259394650659996, + 0.4439481069655198, + 0.46177917554148284, + 0.479425538604203, + 0.49688013784373675, + 0.5141359916531132, + 0.5311861979208834, + 0.5480239367918736, + 0.5646424733950354, + 0.5810351605373051, + 0.5971954413623921, + 0.6131168519734338, + 0.6287930240184686, + 0.644217687237691, + 0.6593846719714731, + 0.674287911628145, + 0.6889214451105513, + 0.7032794192004101, + 0.7173560908995228, + 0.7311458297268958, + 0.7446431199708593, + 0.757842562895277, + 0.7707388788989693, + 0.7833269096274834, + 0.795601620036366, + 0.8075581004051142, + 0.8191915683009983, + 0.8304973704919705, + 0.8414709848078965, + 0.852108021949363, + 0.8624042272433384, + 0.8723554823449863, + 0.8819578068849475, + 0.8912073600614354, + 0.9001004421765051, + 0.9086334961158832, + 0.9168031087717669, + 0.9246060124080203, + 0.9320390859672263, + 0.9390993563190676, + 0.945783999449539, + 0.9520903415905158, + 0.9580158602892249, + 0.963558185417193, + 0.9687151001182652, + 0.9734845416953194, + 0.9778646024353163, + 0.9818535303723597, + 0.9854497299884601, + 0.9886517628517197, + 0.9914583481916864, + 0.9938683634116449, + 0.99588084453764, + 0.9974949866040544, + 0.998710143975583, + 0.9995258306054791, + 0.9999417202299663, + 0.9999576464987401, + 0.9995736030415051, + 0.998789743470524, + 0.9976063813191737, + 0.9960239899165367, + 0.994043202198076, + 0.9916648104524686, + 0.9888897660047015, + 0.9857191788355535, + 0.9821543171376185, + 0.9781966068080447, + 0.9738476308781951, + 0.9691091288804563, + 0.9639829961524481, + 0.9584712830789142, + 0.9525761942715953, + 0.9463000876874145, + 0.9396454736853249, + 0.9326150140222005, + 0.9252115207881683, + 0.9174379552818098, + 0.9092974268256817, + 0.9007931915226273, + 0.8919286509533796, + 0.8827073508159741, + 0.8731329795075164, + 0.8632093666488737, + 0.8529404815528762, + 0.8423304316366457, + 0.8313834607786831, + 0.8201039476213741, + 0.8084964038195901, + 0.7965654722360865, + 0.7843159250844198, + 0.7717526620201259, + 0.758880708180922, + 0.7457052121767203, + 0.7322314440302514, + 0.7184647930691263, + 0.7044107657701763, + 0.6900749835569364, + 0.675463180551151, + 0.6605812012792007, + 0.6454349983343708, + 0.6300306299958922, + 0.6143742578057118, + 0.5984721441039564, + 0.5823306495240819, + 0.5659562304487028, + 0.5493554364271266, + 0.5325349075556212, + 0.5155013718214642, + 0.49826164241183857, + 0.48082261498864826, + 0.4631912649303452, + 0.44537464454187115, + 0.4273798802338298, + 0.4092141696720173, + 0.3908847788984522, + 0.3723990394250557, + 0.3537643453011431, + 0.3349881501559051, + 0.3160779642170538, + 0.2970413513068324, + 0.2778859258165868, + 0.25861934966111083, + 0.23924932921398243, + 0.21978361222511694, + 0.20022998472177053, + 0.18059626789423291, + 0.16089031496745576, + 0.1411200080598672, + 0.12129325503062975, + 0.10141798631660187, + 0.08150215176026912, + 0.06155371742991315, + 0.04158066243329049, + 0.02159097572609596, + 0.0015926529164868282, + -0.01840630693305381, + -0.03839790450523538, + -0.058374143427580086, + -0.0783270334708653, + -0.09824859374510868, + -0.11813085589181738, + -0.13796586727122684, + -0.1577456941432482, + -0.17746242484086014, + -0.19710817293466984, + -0.21667508038737962, + -0.236155320696897, + -0.2555411020268312, + -0.274824670323124, + -0.2939983124155676, + -0.3130543591029702, + -0.3319851882207341, + -0.35078322768961984, + -0.3694409585444771, + -0.3879509179417303, + -0.4063057021444168, + -0.4244979694835826, + -0.44252044329485246, + -0.4603659148289983, + -0.47802724613534286, + -0.4954973729168449, + -0.5127693073557238, + -0.5298361409084934, + -0.5466910470692872, + -0.56332728410037, + -0.5797381977287428, + -0.5959172238077639, + -0.6118578909427189, + -0.6275538230792933, + -0.6429987420539088, + -0.6581864701049049, + -0.6731109323435617, + -0.6877661591839738, + -0.7021462887308054, + -0.7162455691239705, + -0.7300583608392995, + -0.7435791389442746, + -0.7568024953079282, + -0.7697231407640238, + -0.7823359072266528, + -0.7946357497573968, + -0.8066177485832405, + -0.8182771110644103, + -0.8296091736113709, + -0.8406094035501945, + -0.8512734009355745, + -0.8615969003107405, + -0.8715757724135882, + -0.8812060258283253, + -0.8904838085819885, + -0.8994054096851777, + -0.9079672606164054, + -0.9161659367494549, + -0.9239981587231879, + -0.9314607937532425, + -0.9385508568851079, + -0.9452655121880633, + -0.9516020738895161, + -0.9575580074492711, + -0.9631309305733167, + -0.9683186141667072, + -0.9731189832251739, + -0.977530117665097, + -0.9815502530915153, + -0.9851777815038595, + -0.9884112519391305, + -0.991249371052267, + -0.9936910036334644, + -0.9957351730622453, + -0.9973810616980933, + -0.9986280112074989, + -0.999475522827284, + -0.9999232575641008, + -0.9999710363300245, + -0.9996188400141854, + -0.9988668094904142, + -0.9977152455608933, + -0.9961646088358407, + -0.9942155195492713, + -0.9918687573109126, + -0.9891252607943698, + -0.9859861273616704, + -0.9824526126243325, + -0.9785261299411385, + -0.9742082498528091, + -0.9695006994538088, + -0.9644053617015305, + -0.9589242746631385, + -0.9530596307003677, + -0.9468137755926089, + -0.9401892075986287, + -0.9331885764572976, + -0.9258146823277325, + -0.918070474669267, + -0.9099590510617106, + -0.9014836559663548, + -0.8926476794282346, + -0.8834546557201531, + -0.8739082619290224, + -0.8640123164850744, + -0.8537707776345433, + -0.8431877418564167, + -0.8322674422239013, + -0.821014246711247, + -0.8094326564466194, + -0.7975273039117043, + -0.7853029510887806, + -0.7727644875559871, + -0.759916928531561, + -0.7467654128678123, + -0.7333152009956565, + -0.7195716728205075, + -0.7055403255703919, + -0.6912267715971271, + -0.6766367361314569, + -0.6617760549930376, + -0.6466506722561834, + -0.6312666378723216, + -0.6156301052500863, + -0.5997473287940438, + -0.5836246614030073, + -0.5672685519289686, + -0.5506855425976376, + -0.5338822663916443, + -0.5168654443974288, + -0.49964188311690244, + -0.48221847174493154, + -0.46460217941375737, + -0.44680005240543, + -0.4288192113333959, + -0.41066684829434086, + -0.39235022399145386, + -0.373876664830236, + -0.35525355998804264, + -0.3364883584585042, + -0.31758856607203484, + -0.2985617424935936, + -0.27941549819892586, + -0.2601574914304689, + -0.2407954251341592, + -0.22133704387835954, + -0.2017901307561289, + -0.18216250427209588, + -0.1624620152151542, + -0.14269654351825858, + -0.12287399510655005, + -0.10300229873509785, + -0.0830894028174964, + -0.06314327224661277, + -0.04317188520872868, + -0.02318322999237945, + -0.0031853017931379904, + 0.016813900484349713, + 0.03680637742582692, + 0.05678413230707805, + 0.07673917429251892, + 0.09666352163141724, + 0.11654920485049364, + 0.13638826994159764, + 0.1561727815432119, + 0.175894826114484, + 0.19554651510054427, + 0.21511998808781552, + 0.23460741594807993, + 0.2540010039700231, + 0.27329299497701237, + 0.2924756724298697, + 0.31154136351337786, + 0.3304824422053109, + 0.34929133232673487, + 0.36796051057238466, + 0.38648250951987934, + 0.4048499206165983, + 0.42305539714299684, + 0.44109165715120235, + 0.4589514863776903, + 0.4766277411288995, + 0.49411335113860816, + 0.5114013223959524, + 0.5284847399429308, + 0.545356770640302, + 0.562010665900743, + 0.5784397643882002, + 0.5946374946823286, + 0.6105973779069791, + 0.6263130303216559, + 0.6417781658749337, + 0.6569865987187891, + 0.6719322456828615, + 0.6866091287076385, + 0.7010113772355981, + 0.7151332305593578, + 0.7289690401258759, + 0.7425132717958017, + 0.7557605080570537, + 0.7687054501917558, + 0.78134292039565, + 0.7936678638491531, + 0.8056753507392133, + 0.8173605782311729, + 0.8287188723898353, + 0.8397456900489799, + 0.8504366206285644, + 0.8607873878989017, + 0.8707938516910911, + 0.8804520095530344, + 0.8897579983503596, + 0.8987080958116269, + 0.907298722017184, + 0.9155264408310896, + 0.9233879612755189, + 0.9308801388471136, + 0.9379999767747389, + 0.9447446272181538, + 0.951111392407109, + 0.957097725720417, + 0.9627012327045701, + 0.9679196720314863, + 0.9727509563950137, + 0.9771931533458229, + 0.9812444860643621, + 0.9849033340715608, + 0.9881682338770004, + 0.9910378795642898, + 0.9935111233134158, + 0.9955869758598548, + 0.9972646068902659, + 0.998543345374605, + 0.9994226798345279, + 0.9999022585479752, + 0.9999818896898556, + 0.9996615414087742, + 0.998941341839772, + 0.9978215790530743, + 0.9963027009388656, + 0.9943853150281404, + 0.992070188249698, + 0.9893582466233818, + 0.9862505748896837, + 0.9827484160758622, + 0.9788531709987474, + 0.974566397704435, + 0.9698898108450863, + 0.9648252809930913, + 0.9593748338928642, + 0.9535406496505743, + 0.94732506186213, + 0.9407305566797731, + 0.9337597718176507, + 0.9264154954967662, + 0.9187006653297247, + 0.9106183671457304, + 0.9021718337562933, + 0.893364443662152, + 0.8841997197019127, + 0.8746813276429652, + 0.8648130747152218, + 0.8545989080882805, + 0.8440429132926041, + 0.833149312585366, + 0.8219224632616022, + 0.8103668559113548, + 0.7984871126234903, + 0.7862879851369292, + 0.7737743529400134, + 0.7609512213187744, + 0.7478237193548898, + 0.7343970978741133, + 0.7206767273460181, + 0.706668095735878, + 0.6923768063095604, + 0.6778085753922867, + 0.6629692300821833, + 0.6478647059195176, + 0.6325010445125663, + 0.6168843911210448, + 0.6010209921980904, + 0.5849171928917617, + 0.5685794345070696, + 0.5520142519295329, + 0.5352282710113162, + 0.5182282059209752, + 0.5010208564578846, + 0.4836131053324, + 0.4660119154128711, + 0.4482243269405849, + 0.4302574547137687, + 0.4121184852417566, + 0.39381467387048763, + 0.37535334188046277, + 0.3567418735583286, + 0.3379877132432676, + 0.3190983623493521, + 0.300081376365085, + 0.2809443618313018, + 0.2616949732986626, + 0.24234091026592378, + 0.22288991410024764, + 0.20334976494075557, + 0.183728278586583, + 0.1640333033706535, + 0.14427271702045727, + 0.1244544235070617, + 0.10458634988363526, + 0.08467644311472142, + 0.06473266689756589, + 0.04476299847674028, + 0.024775425453357765, + 0.0047779425901285115, + -0.015221451386431743, + -0.03521475698538918, + -0.05519397715107451, + -0.0751511204618093, + -0.09507820432636095, + -0.11496725817687455, + -0.1348103266569955, + -0.15459947280389894, + -0.17432678122297965, + -0.19398436125389723, + -0.2135643501267387, + -0.2330589161070144, + -0.2524602616282581, + -0.27176062641094245, + -0.2909522905664908, + -0.310027577685123, + -0.32897885790632714, + -0.347798550970695, + -0.3664791292519284, + -0.38501312076778266, + -0.4033931121687696, + -0.42161175170339216, + -0.43966175215875003, + -0.4575358937753214, + -0.4752270271347798, + -0.49272807601966023, + -0.5100320402437544, + -0.527131998452086, + -0.5440211108893698 + ] + }, + "y": { + "_class": "Var", + "values": [ + 1.8, + 1.7131964705158862, + 1.6325767641260713, + 1.5578381174327705, + 1.4886917554023165, + 1.4248622085967848, + 1.3660866588452998, + 1.3121143389587635, + 1.2627059300678218, + 1.2176330047622723, + 1.1766775395583953, + 1.1396313173497108, + 1.1062955788510815, + 1.0764804537609591, + 1.0500045571137415, + 1.0266946725112112, + 1.0063852051290842, + 0.9889178924204969, + 0.9741415297294548, + 0.9619114746383648, + 0.9520893960829774, + 0.9445430631447783, + 0.939145942382848, + 0.9357769010216073, + 0.9343200596571354, + 0.9346645462081259, + 0.9367041014893603, + 0.9403369794133032, + 0.9454657865141428, + 0.9519971950147134, + 0.9598416949021543, + 0.968913519835209, + 0.9791305128377515, + 0.9904138429133296, + 1.002687845597446, + 1.015879960196277, + 1.0299206222763009, + 1.0447430281546897, + 1.0602829883365583, + 1.0764788949458106, + 1.0932716215410754, + 1.1106043835443806, + 1.128422549101871, + 1.1466736289211734, + 1.1653071897992309, + 1.1842748100801914, + 1.2035298772790857, + 1.2230275322163238, + 1.2427246575066593, + 1.2625797901511517, + 1.2825530869256123, + 1.3026061561845244, + 1.3227020351349204, + 1.3428051838168873, + 1.3628814018579678, + 1.3828978177519753, + 1.4028227543039489, + 1.4226256983833854, + 1.4422773009242411, + 1.4617493427090893, + 1.481014665747488, + 1.5000471522851004, + 1.5188216376155999, + 1.5373139078423896, + 1.5555006998786045, + 1.5733596796578946, + 1.590869350944609, + 1.608009062687731, + 1.624758948599265, + 1.6410999224551497, + 1.657013678095257, + 1.6724826894233917, + 1.6874902036052348, + 1.7020201193836204, + 1.7160569677985669, + 1.7295859390311235, + 1.742592876196323, + 1.7550642753431824, + 1.7669872854547033, + 1.7783497084478703, + 1.789139962550884, + 1.7993469026352198, + 1.8089599395439322, + 1.8179690511495274, + 1.8263647781490848, + 1.834138224064258, + 1.8412810552412746, + 1.8477854779807985, + 1.8536440830192789, + 1.858849907146727, + 1.8633964927878175, + 1.8672778878935539, + 1.8704886459412704, + 1.8730238259346297, + 1.8748789756080158, + 1.8760499613156878, + 1.8765330273985128, + 1.8763248786463866, + 1.8754226790839708, + 1.8738240519706921, + 1.8715270798007437, + 1.8685302869580833, + 1.8648324730990153, + 1.8604327713443751, + 1.8553307377946675, + 1.8495263518542187, + 1.8430200162311763, + 1.8358125569375092, + 1.8279052003951826, + 1.8192993988790664, + 1.8099969158773839, + 1.799999905568461, + 1.7893109123354543, + 1.7779328707663502, + 1.765869105653964, + 1.7531232969541186, + 1.739699309204735, + 1.7256013081013295, + 1.7108338184492378, + 1.6954017237332444, + 1.679310266117584, + 1.6625650464459418, + 1.645171966519876, + 1.6271370811599777, + 1.6084667408242213, + 1.5891676222086286, + 1.5692467281617424, + 1.5487113876846252, + 1.527569255403455, + 1.5058282182977765, + 1.483496308853021, + 1.4605818407612983, + 1.4370934197352827, + 1.4130399435082162, + 1.388430601833905, + 1.3632748709790372, + 1.337582385074024, + 1.3113629342662865, + 1.2846265639208758, + 1.2573835749841054, + 1.2296445239835543, + 1.2014202230280642, + 1.1727217189630699, + 1.1435601533376898, + 1.1139468389498866, + 1.0838933069131018, + 1.0534113051619733, + 1.0225127984523383, + 0.9912099683612269, + 0.9595151600473664, + 0.9274407839978875, + 0.8949994199466966, + 0.8622038235173728, + 0.8290669261812131, + 0.7956018352572298, + 0.7618218308256017, + 0.727740272702365, + 0.6933705954230573, + 0.6587263704727093, + 0.6238213023766782, + 0.5886692287006476, + 0.5532841200506305, + 0.5176800612478445, + 0.4818711566105395, + 0.445871592295639, + 0.4096956453982831, + 0.3733576819047867, + 0.3368721566926404, + 0.30025361334923095, + 0.2635166322236725, + 0.2266758023778688, + 0.1897457675426596, + 0.1527412154702533, + 0.11567687793422589, + 0.0785675307295232, + 0.04142798501981789, + 0.004273025714451229, + -0.03288255111105141, + -0.07002394571250715, + -0.10713635919127013, + -0.14420499349423263, + -0.1812150514442841, + -0.21815176884595028, + -0.25500041903548876, + -0.2917463009746194, + -0.32837475927216997, + -0.36487118418407616, + -0.40122101161338125, + -0.4374097271536089, + -0.47342291255740254, + -0.5092461696847076, + -0.5448651754451559, + -0.5802657043344778, + -0.615433628434503, + -0.650354917413158, + -0.6850156385244697, + -0.71940195660856, + -0.7535001574707619, + -0.787296619767682, + -0.8207777974312388, + -0.8539302943900111, + -0.8867408656633656, + -0.9191964173614621, + -0.9512840066852433, + -0.982990841926448, + -1.0143042915927634, + -1.0452118092243166, + -1.0757009896119092, + -1.1057596245833963, + -1.1353757030080074, + -1.1645374107963553, + -1.1932331309004287, + -1.2214514454568455, + -1.2491810955618619, + -1.2764109244766884, + -1.3031299978901734, + -1.329327618841526, + -1.3549933277203088, + -1.380116902266443, + -1.4046883575702052, + -1.428697931439468, + -1.452135971505767, + -1.4749930325449099, + -1.4972599405155527, + -1.5189277926198779, + -1.5399879573035877, + -1.5604320742559097, + -1.5802520495832515, + -1.599439944102872, + -1.6179879939828767, + -1.6358887297273197, + -1.6531349805932938, + -1.6697198745909239, + -1.685636838483374, + -1.700879596367947, + -1.7154420740091811, + -1.729318350941937, + -1.742502811866582, + -1.7549901609330671, + -1.766775421740931, + -1.7778539373392965, + -1.7882213697668938, + -1.7978736169562117, + -1.8068067222726896, + -1.815017038452139, + -1.8225012516035892, + -1.8292563812092848, + -1.8352797801246883, + -1.8405691342929076, + -1.8451223819711193, + -1.8489376065787066, + -1.852013204192515, + -1.854347911353944, + -1.8559408050689463, + -1.856791302808029, + -1.8568991620196253, + -1.8562643903041933, + -1.854887144904358, + -1.8527679000585575, + -1.8499074708897247, + -1.8463070134052872, + -1.8419680244971681, + -1.8368923403832962, + -1.831082026526432, + -1.8245393085879977, + -1.817266732136568, + -1.8092671776515166, + -1.8005438605230193, + -1.791100331052052, + -1.780940469235884, + -1.7700683474876815, + -1.7584882176440524, + -1.746204648311081, + -1.7332225308895972, + -1.7195470795751742, + -1.7051838313581305, + -1.690138631067153, + -1.674417471542981, + -1.6580265517097454, + -1.6409723746518963, + -1.6232617482859584, + -1.6049017853605265, + -1.5858999034562697, + -1.5662637886014585, + -1.546001238154693, + -1.5251202807554465, + -1.5036292268817852, + -1.4815366684848978, + -1.4588514789891034, + -1.4355828131788326, + -1.4117400309751627, + -1.38733259607013, + -1.3623702101230846, + -1.3368628279966845, + -1.3108206577569024, + -1.2842541606730187, + -1.2571740463526715, + -1.2295911530656933, + -1.2015164437658055, + -1.1729611014303523, + -1.1439365296329755, + -1.1144543525436086, + -1.0845264149284728, + -1.0541647592567078, + -1.023381495508333, + -0.9921888816972685, + -0.9605993613962989, + -0.9286255624560447, + -0.8962802970049515, + -0.8635765613932148, + -0.8305274740815927, + -0.7971462051251504, + -0.763446068041314, + -0.7294405212800673, + -0.6951431682239408, + -0.6605677571880236, + -0.6257281747649002, + -0.5906383501906894, + -0.5553122804433733, + -0.5197640697172323, + -0.484007925495703, + -0.4480581585513917, + -0.4119291829460622, + -0.37563548590884993, + -0.3391915559492416, + -0.3026119480932264, + -0.2659112780151212, + -0.22910422150900267, + -0.1922055144887141, + -0.15522995046641622, + -0.11819231880400397, + -0.08110741654610416, + -0.04399006524925376, + -0.006855102713402707, + 0.030282617018073422, + 0.06740822365838012, + 0.10450684969314532, + 0.14156366993334576, + 0.17856386437821792, + 0.21549263949180453, + 0.25233522915569134, + 0.28907689466901965, + 0.3257029284789206, + 0.3621986921351849, + 0.3985495772091384, + 0.43474103752480614, + 0.47075860054409074, + 0.5065878673667857, + 0.5422145127305624, + 0.57762428501098, + 0.6128030573196056, + 0.6477367786304943, + 0.6824114072087427, + 0.7168130342803998, + 0.7509278855656857, + 0.7847423212789798, + 0.8182428361288338, + 0.8514160593179564, + 0.8842487545432318, + 0.9167278200606147, + 0.9488402684071106, + 0.9805732029245567, + 1.0119138947772501, + 1.0428497967431516, + 1.0733685432138997, + 1.103457950194797, + 1.1331060153112447, + 1.1623009371457933, + 1.191030999525053, + 1.2192846376742281, + 1.2470505138834056, + 1.2743175175075458, + 1.3010747649664924, + 1.3273115997449625, + 1.3530175924218286, + 1.3781824991526377, + 1.4027961786927017, + 1.426848721249251, + 1.4503304782747866, + 1.473232062467087, + 1.4955443477691994, + 1.5172584693694497, + 1.5383658155592759, + 1.558857903050289, + 1.5787264451556844, + 1.5979634464653278, + 1.6165612037636152, + 1.6345123060294804, + 1.651809634436387, + 1.6684463594496584, + 1.684415833002537, + 1.6997115679427799, + 1.7143273814613686, + 1.7282574049789334, + 1.7414960841457494, + 1.7540381788417396, + 1.7658787627524033, + 1.7770131408534127, + 1.787436760416277, + 1.797145375451529, + 1.8061350705606647, + 1.8144022609361483, + 1.821943692361409, + 1.8287564411101411, + 1.8348378422164358, + 1.840185368497097, + 1.844796798545393, + 1.8486702503210852, + 1.8518041811504296, + 1.8541973877261761, + 1.8558490060420392, + 1.8567584403424622, + 1.8569252339979763, + 1.856349237049757, + 1.8550306412848239, + 1.8529699802360406, + 1.8501681291821155, + 1.8466263049144742, + 1.8423459819967873, + 1.8373287777016676, + 1.8315766196406158, + 1.8250917728128264, + 1.817876839605189, + 1.8099347597922872, + 1.8012688092565128, + 1.791882492746301, + 1.7817794678593195, + 1.7709637037003079, + 1.75943949632877, + 1.7472114687589766, + 1.73428457095996, + 1.7206640746568431, + 1.7063554364071816, + 1.6913642850751083, + 1.675696554770952, + 1.659358490078134, + 1.642356646053168, + 1.6246978882256633, + 1.6063893765502755, + 1.5874384070200924, + 1.5678524745526703, + 1.5476393624546827, + 1.5268071425439638, + 1.5053641751495153, + 1.4833191091115026, + 1.4606808418345862, + 1.4374583701824213, + 1.4136609122773345, + 1.3892979480728782, + 1.3643792189941661, + 1.338914727937863, + 1.312914738919387, + 1.286389694452717, + 1.2593501342615536, + 1.2318068186920494, + 1.2037707380369362, + 1.1752531125355359, + 1.1462653923737516, + 1.1168192505783476, + 1.0869264617393475, + 1.0565989198759274, + 1.0258487147878033, + 0.9946881308060431, + 0.9631296467930501, + 0.9311859361425754, + 0.8988698376377783, + 0.8661942386952015, + 0.8331721629431049, + 0.7998167908424532, + 0.7661414587597507, + 0.7321596589670526, + 0.6978850390443814, + 0.6633313310090072, + 0.6285123125832454, + 0.5934418796908375, + 0.558134043038592, + 0.5226029281163976, + 0.4868627751972175, + 0.450927928308126, + 0.4148127456626542, + 0.3785316440637369, + 0.34209911564235634, + 0.30552972445582793, + 0.26883810648781337, + 0.23203896964829793, + 0.19514705417645237, + 0.15817709243393363, + 0.12114385763409015, + 0.08406215113413837, + 0.04694680243019269, + 0.009812669157255722, + -0.027325369070726732, + -0.06445246662734934, + -0.10155378039960454, + -0.13861447727069448, + -0.17561973982190976, + -0.21255476633264808, + -0.24940477078298515, + -0.2861550072835183, + -0.3227907854029046, + -0.35929745191109463 + ] + }, + "T": { + "_class": "Par", + "value": 0.4, + "unit": "s" + } +} From c7c7b0ca66275d031d93904befff61c6c4066f94 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 5 Jul 2022 15:07:24 +0200 Subject: [PATCH 62/63] Require newest SignalTables version --- Manifest.toml | 18 +++++++++--------- Project.toml | 2 +- src/Modia.jl | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 9117641..f32825e 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -142,9 +142,9 @@ uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" [[deps.ConstructionBase]] deps = ["LinearAlgebra"] -git-tree-sha1 = "c096d0e321368ac23eb1be1ea405814f8b32adb3" +git-tree-sha1 = "59d00b3139a9de4eb961057eabb65ac6522be954" uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" -version = "1.3.1" +version = "1.4.0" [[deps.CpuId]] deps = ["Markdown"] @@ -794,10 +794,10 @@ deps = ["Distributed", "Mmap", "Random", "Serialization"] uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" [[deps.SignalTables]] -deps = ["DataFrames", "OrderedCollections", "Pkg", "Test", "Unitful"] -git-tree-sha1 = "7ba002d3fb8587dbcdcc44d9d2bd610ce68b26be" +deps = ["DataFrames", "JSON", "OrderedCollections", "Pkg", "Tables", "Test", "Unitful"] +git-tree-sha1 = "b8f0cd15fe115b38eae285d9b23386e848fc7c6b" uuid = "3201582d-3078-4276-ba5d-0a1254d79d7c" -version = "0.2.0" +version = "0.3.3" [[deps.SimpleTraits]] deps = ["InteractiveUtils", "MacroTools"] @@ -826,9 +826,9 @@ version = "1.24.0" [[deps.SpecialFunctions]] deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "a9e798cae4867e3a41cae2dd9eb60c047f1212db" +git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.1.6" +version = "2.1.7" [[deps.Static]] deps = ["IfElse"] @@ -975,9 +975,9 @@ version = "1.11.0" [[deps.VectorizationBase]] deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static"] -git-tree-sha1 = "9d87c8c1d27dc20ba8be6bdca85d36556c371172" +git-tree-sha1 = "39e55018bccc5a858217db32aa3d9e7decbefd0c" uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" -version = "0.21.38" +version = "0.21.40" [[deps.VertexSafeGraphs]] deps = ["Graphs"] diff --git a/Project.toml b/Project.toml index 59147e9..6bbcc08 100644 --- a/Project.toml +++ b/Project.toml @@ -39,7 +39,7 @@ MonteCarloMeasurements = "1" OrderedCollections = "1" RecursiveFactorization = "0.2" Reexport = "1" -SignalTables = "0.2, 0.3" +SignalTables = "0.3.3" StaticArrays = "1" Sundials = "4" TimerOutputs = "0.5" diff --git a/src/Modia.jl b/src/Modia.jl index 5574ac1..f712163 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -9,7 +9,7 @@ Main module of Modia. module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory -const Version = "0.9.0-dev" +const Version = "0.9.0" const Date = "2022-07-05" const modelsPath = joinpath(Modia.path, "models") From b27782462cf580a1bfcd28cb9402086b6418c098 Mon Sep 17 00:00:00 2001 From: "Martin.Otter@dlr.de" Date: Tue, 5 Jul 2022 16:40:27 +0200 Subject: [PATCH 63/63] Require latest SignalTables version --- Manifest.toml | 2 +- Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index f32825e..f5ff297 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -797,7 +797,7 @@ uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" deps = ["DataFrames", "JSON", "OrderedCollections", "Pkg", "Tables", "Test", "Unitful"] git-tree-sha1 = "b8f0cd15fe115b38eae285d9b23386e848fc7c6b" uuid = "3201582d-3078-4276-ba5d-0a1254d79d7c" -version = "0.3.3" +version = "0.3.4" [[deps.SimpleTraits]] deps = ["InteractiveUtils", "MacroTools"] diff --git a/Project.toml b/Project.toml index 6bbcc08..8fc4973 100644 --- a/Project.toml +++ b/Project.toml @@ -39,7 +39,7 @@ MonteCarloMeasurements = "1" OrderedCollections = "1" RecursiveFactorization = "0.2" Reexport = "1" -SignalTables = "0.3.3" +SignalTables = "0.3.4" StaticArrays = "1" Sundials = "4" TimerOutputs = "0.5"