Skip to content

Commit

Permalink
Merge pull request #153 from ModiaSim/improve_SignalTables
Browse files Browse the repository at this point in the history
Improve signal tables
  • Loading branch information
MartinOtter authored Aug 5, 2022
2 parents 009b497 + fe13924 commit f0fec8a
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 191 deletions.
194 changes: 104 additions & 90 deletions Manifest.toml

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
authors = ["Hilding Elmqvist <[email protected]>", "Martin Otter <[email protected]>"]
name = "Modia"
uuid = "cb905087-75eb-5f27-8515-1ce0ec8e839e"
version = "0.9.2"
version = "0.9.3"

[deps]
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
Expand All @@ -27,7 +27,7 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[compat]
DiffEqBase = "6.82.0"
DiffEqBase = "6"
DataFrames = "1"
DifferentialEquations = "7"
FiniteDiff = "2"
Expand All @@ -39,7 +39,7 @@ MonteCarloMeasurements = "1"
OrderedCollections = "1"
RecursiveFactorization = "0.2"
Reexport = "1"
SignalTables = "0.3.5"
SignalTables = "0.4.0"
StaticArrays = "1"
Sundials = "4"
TimerOutputs = "0.5"
Expand Down
18 changes: 13 additions & 5 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,29 @@ functionalities of these packages.

## Release Notes

### Version 0.9.3

- Requires SignalTables 0.4.0 (introduces Map-signal)
- getSignalNames(...; getVar=true, getPar=true, getMap=true): New keyword arguments to filter names.
- writeSignalTable(instantiatedModel,..): Include attributes = Map(model=..., experiment=...).
- Some internal bug-fixes.


### Version 0.9.2

- Bug fix: integrator IDA() can be used (especially to avoid solving large linear equation systems in the model).\
Extend some test models to use IDA().


### Version 0.9.1

- Requires SignalTables 0.3.5.

- [`@usingModiaPlot`](@ref): corrected and fixed in docu. Alternatively, @usingPlotPackage can be used,
provided package SignalTables is present in your current environment.

- Internal: A function call in the generated code prefixed with `Modia.`.


### Version 0.9.0

Expand All @@ -77,13 +85,13 @@ functionalities of these packages.
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),
- 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.

- 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`).
(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.

Expand Down
28 changes: 17 additions & 11 deletions src/CodeGeneration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ mutable struct SimulationModel{FloatType,TimeType}

parameters::OrderedDict{Symbol,Any} # Parameters as provided to SimulationModel constructor
equationInfo::Modia.EquationInfo # Invariant part of equations are available
x_terminate::Vector{FloatType} # States x used at the last terminate!(..) call or [], if terminate!(..) not yet called.

# Available after propagateEvaluateAndInstantiate!(..) called
instantiateFunctions::Vector{Tuple{Union{Expr,Symbol},OrderedDict{Symbol,Any},String}}
Expand All @@ -353,6 +354,7 @@ mutable struct SimulationModel{FloatType,TimeType}
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,
previousVars, preVars, holdVars,
parameterDefinition, timeName, w_invariant_names, hideResult_names;
Expand Down Expand Up @@ -408,6 +410,7 @@ mutable struct SimulationModel{FloatType,TimeType}
instantiateResult = true
newResultSegment = false
parameters = deepcopy(parameterDefinition)
x_terminate = FloatType[]

new(modelModule, modelName, buildDict, TimerOutputs.TimerOutput(), UInt64(0), UInt64(0), SimulationOptions{FloatType,TimeType}(), getDerivatives!,
equationInfo, linearEquations, eventHandler,
Expand All @@ -418,7 +421,7 @@ mutable struct SimulationModel{FloatType,TimeType}
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,
parameters, equationInfo)
parameters, equationInfo, x_terminate)
end

#=
Expand Down Expand Up @@ -876,11 +879,11 @@ Return the names of the elements of the x-vector in a Vector{String}.
get_xNames(m::SimulationModel) = Modia.get_xNames(m.equationInfo)



"""
isInitial(instantiatedModel)
Return true, if **initialization phase** of simulation.
Return true, if **initialization phase** of simulation
(of the current segment of a segmented simulation).
"""
isInitial(m::SimulationModel) = m.eventHandler.initial
initial( m::SimulationModel) = m.eventHandler.initial
Expand All @@ -898,19 +901,20 @@ isFirstInitialOfAllSegments(m::SimulationModel) = m.eventHandler.firstInitialOfA
"""
isTerminal(instantiatedModel)
Return true, if **terminal phase** of simulation.
Return true, if **terminal phase** of simulation
(of the current segment of a segmented simulation).
"""
isTerminal(m::SimulationModel) = m.eventHandler.terminal
terminal( m::SimulationModel) = m.eventHandler.terminal


"""
isTerminalOfAllSegmenteds(instantiatedModel)
isTerminalOfAllSegments(instantiatedModel)
Return true, if **terminal phase** of simulation of the **last segment**
of a segmented simulation.
"""
isTerminalOfAllSegmenteds(m::SimulationModel) = m.eventHandler.terminalOfAllSegments
isTerminalOfAllSegments(m::SimulationModel) = m.eventHandler.terminalOfAllSegments


"""
Expand Down Expand Up @@ -1073,7 +1077,6 @@ 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)
Expand Down Expand Up @@ -1122,7 +1125,7 @@ function init!(m::SimulationModel{FloatType,TimeType})::Bool where {FloatType,Ti
# 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)
show(stdout, x_table; allrows=true, allcols=true, rowlabel = Symbol("#"), summary=false, eltypes=false, truncate=60)
println("\n")
end

Expand Down Expand Up @@ -1171,9 +1174,10 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where
logInstantiatedFunctionCalls = false
Core.eval(m.modelModule, :($(fc[1])($m, $(fc[2]), $(fc[3]), log=$logInstantiatedFunctionCalls)))
end
resizeLinearEquations!(m, m.evaluatedParameters, m.options.log)

# Get initial state vector
m.x_start = initialStateVector!(m.equationInfo, FloatType)
m.x_start = initialStateVector!(m)

# update equationInfo
x_info = m.equationInfo.x_info
Expand Down Expand Up @@ -1222,7 +1226,6 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where
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
Expand Down Expand Up @@ -1287,8 +1290,11 @@ function terminate!(m::SimulationModel, x, t)::Nothing
#println("... terminate! called at time = $t")
eh = m.eventHandler
eh.terminal = true
eh.terminalOfAllSegments = m.eventHandler.restart != Modia.FullRestart
invokelatest_getDerivatives_without_der_x!(x, m, t)
eh.terminal = false
eh.terminalOfAllSegments = false
m.x_terminate = deepcopy(x)
return nothing
end

Expand Down Expand Up @@ -1886,7 +1892,7 @@ function initialStateVector!(m::SimulationModel{FloatType,TimeType})::Vector{Flo
# differential equation der_x[1] = -x[1], with state name _dummy_x
new_x_segmented_variable!(m, "_dummy_x", "der(_dummy_x)", FloatType(0))
end
return initialStateVector!(m.equationInfo, FloatType)
return initialStateVector!(m.equationInfo, FloatType, !isFullRestart(m), m.x_terminate)
end


Expand Down
52 changes: 36 additions & 16 deletions src/EquationAndStateInfo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -744,13 +744,13 @@ end


"""
x_start = initialStateVector!(eqInfo::EquationInfo, FloatType)::Vector{FloatType}
x_start = initialStateVector!(eqInfo::EquationInfo, FloatType, isFirstSegment, x_terminate)::Vector{FloatType}
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}
function initialStateVector!(eqInfo::EquationInfo, FloatType::Type, isFirstSegment::Bool, x_terminate)::Vector{FloatType}
@assert(eqInfo.status == EquationInfo_Initialized_Before_All_States_Are_Known)
nx_info_fixedLength = eqInfo.nx_info_fixedLength
x_info = eqInfo.x_info
Expand All @@ -770,7 +770,7 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa
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]
Expand All @@ -792,31 +792,51 @@ function initialStateVector!(eqInfo::EquationInfo, FloatType::Type)::Vector{Floa

# Construct x_start
x_start = zeros(FloatType, eqInfo.nx)
startIndex = 1
for xe_info in eqInfo.x_info
if xe_info.scalar
@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))
@assert(length(xe_start) == xe_info.length)
copyto!(x_start, startIndex, xe_start, 1, length(xe_start))
startIndex += length(xe_start)
if isFirstSegment
startIndex = 1
for xe_info in x_info
if xe_info.scalar
@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))
@assert(length(xe_start) == xe_info.length)
copyto!(x_start, startIndex, xe_start, 1, length(xe_start))
startIndex += length(xe_start)
end
end
else
for i in 1:eqInfo.nxInvariant
x_start[i] = x_terminate[i]
end
startIndex = eqInfo.nxInvariant+1
for i = eqInfo.nx_info_invariant+1:length(x_info)
xe_info = x_info[i]
if xe_info.scalar
@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))
@assert(length(xe_start) == xe_info.length)
copyto!(x_start, startIndex, xe_start, 1, length(xe_start))
startIndex += length(xe_start)
end
end
end

@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
end
return x_start
end
Expand Down
2 changes: 2 additions & 0 deletions src/EvaluateParameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ function getConstructorAsString(path, constructor, parameters):String
end
if typeof(value) == Symbol
svalue = ":" * string(value)
elseif typeof(value) == String
svalue = value
elseif typeof(value) <: AbstractDict
svalue = "..." # Do not show dictionaries, since too much output, especially due to pointers to Object3Ds
else
Expand Down
8 changes: 4 additions & 4 deletions src/Modia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Main module of Modia.
module Modia

const path = dirname(dirname(@__FILE__)) # Absolute path of package directory
const Version = "0.9.2"
const Date = "2022-07-12"
const Version = "0.9.3"
const Date = "2022-08-05"
const modelsPath = joinpath(Modia.path, "models")

print(" \n\nWelcome to ")
Expand Down Expand Up @@ -43,11 +43,11 @@ import SignalTables: AvailablePlotPackages

"""
@usingModiaPlot()
Execute `using XXX`, where `XXX` is the Plot package that was activated with `usePlotPackage(plotPackage)`.
So this is similar to @usingPlotPackage (from SignalTables, that is reexported from Modia).
There is, however, a difference when XXX = "SilentNoPlot":
There is, however, a difference when XXX = "SilentNoPlot":
- @usingPlotPackage() executes `using SignalTables.SilentNoPlot` and therefore requires that package `SignalTables` is available in your environment.
- @usingModiaPlot() executes `using Modia.SignalTables.SilentNoPlot` and therefore requires that package `Modia` is available in your environment.
Expand Down
Loading

0 comments on commit f0fec8a

Please sign in to comment.