Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 <Hilding.Elmqvist@Mogram.net>", "Martin Otter <Martin.Otter@dlr.de>"]
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