From e81114f819270a39c02f64497d77514a73c77248 Mon Sep 17 00:00:00 2001 From: Martin Otter Date: Sun, 4 Jun 2023 12:55:24 +0200 Subject: [PATCH] Prepare release 0.12.0 - Rename functions of built-in components - Improve docu of built-in components --- Project.toml | 2 +- docs/src/Functions.md | 8 +-- docs/src/Internal.md | 94 +++++++++++++++++----------- docs/src/index.md | 4 +- models/HeatTransfer/InsulatedRod2.jl | 4 +- src/CodeGeneration.jl | 90 ++++++++++++++------------ test/TestLinearSystems.jl | 6 +- 7 files changed, 119 insertions(+), 89 deletions(-) diff --git a/Project.toml b/Project.toml index 502a835..7ceeca0 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.11.0" +version = "0.12.0" [deps] DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" diff --git a/docs/src/Functions.md b/docs/src/Functions.md index 06dd0d0..53ef9e1 100644 --- a/docs/src/Functions.md +++ b/docs/src/Functions.md @@ -60,7 +60,7 @@ showEvaluatedParameters CurrentModule = Modia ``` -The simulation result of a model `instantiatedModel` are provided as a *signal table*, +The simulation result of a model `instantiatedModel` are provided as a *signal table*, see [SignalTables.jl](https://github.com/ModiaSim/SignalTables.jl). Therefore, all [signal table functions](https://modiasim.github.io/SignalTables.jl/stable/Functions/OverviewOfFunctions.html) @@ -68,7 +68,7 @@ can be used on a simulated model To activate the defined plot package, use -- [`@usingModiaPlot`](@ref) +- [`@usingModiaPlot`](@ref) Alternatively, `usingPlotPackage` (from Modia reexported macro of SignalTables) can be used, but then package `SignalTables` must be in your current environment. @@ -87,11 +87,11 @@ FirstOrder = Model( ) simulate!(firstOrder, stopTime=10) showInfo(firstOrder) # list info about the result -t = getValues(firstOrder, "time") +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) +writeSignalTable("firstOrder.json", firstOrder, indent=2, log=true) ``` See the generated [json-file](../resources/fileio/firstOrder.json). diff --git a/docs/src/Internal.md b/docs/src/Internal.md index dbdc7c4..0ab708f 100644 --- a/docs/src/Internal.md +++ b/docs/src/Internal.md @@ -1,69 +1,91 @@ # Internal This chapter documents internal functions that are typically only -for use of the developers of package Modia. +for use of the developers of a model library or of Modia. -## Code Generation - -This section provides functions to **generate Julia code** of the -transformed equations. +## Variables of built-in Components ```@meta CurrentModule = Modia ``` +The following functions are provided to define and access new variables +in built-in components (seee for example model `InsulatedRod2` in `Modia/models/HeatTransfer.jl`). + +| Functions | Description | +|:--------------------------------------------------------|:----------------------------------------------------------------------------------| +| [`new_x_segmented_variable!`](@ref) | Generate new state variable (`x_segmented` and `der_x_segmented` variables) | +| [`new_w_segmented_variable!`](@ref) | Generate new local variable (`w_segmented` variable) | +| [`new_alias_segmented_variable!`](@ref) | Generate new alias variable | +| [`new_z_segmented_variable!`](@ref) | Generate new zero crossing variables (`z_segmented` variables) | +| [`get_x_startIndex_from_x_segmented_startIndex`](@ref) | Return start index of `x_segmented` variable with respect to state vector `x` | +| [`copy_scalar_x_segmented_value_from_state`](@ref) | Return value of scalar `x_segmented` variable from state vector `x` | +| [`copy_SVector3_x_segmented_value_from_state`](@ref) | Return value of `SVector{3,FloatType}` x_segmented variable from state vector `x` | +| [`copy_Vector_x_segmented_value_from_state`](@ref) | Return value of `Vector{FloatType}` x_segmented variable from state vector `x` | +| [`copy_der_x_segmented_value_to_state`](@ref) | Copy value of `der_x_segmented` variable to state derivative vector `der(x)` | +| [`copy_w_segmented_value_to_result`](@ref) | Copy value of local variable (`w-segmented`) to result | + + ```@docs -SimulationModel -generate_getDerivatives! -init! -outputs! -terminate! -derivatives! -DAEresidualsForODE! -affectEvent! -zeroCrossings! -affectStateEvent! -timeEventCondition! -affectTimeEvent! -addToResult! -getFloatType -measurementToString +new_x_segmented_variable! +new_w_segmented_variable! +new_alias_segmented_variable! +new_z_segmented_variable! +get_x_startIndex_from_x_segmented_startIndex +copy_scalar_x_segmented_value_from_state +copy_SVector3_x_segmented_value_from_state +copy_Vector_x_segmented_value_from_state +copy_der_x_segmented_value_to_state +copy_w_segmented_value_to_result ``` -## Inquiries in Model +## Inquiries in built-in Components -The functions in this section can be called in the model code or in -functions that are called from the model code. +The following functions are provided to inquire properties +in built-in components at the current state of the simulation +(see for example model `InsulatedRod2` in `Modia/models/HeatTransfer.jl`). ```@docs isInitial +isFirstInitialOfAllSegments isTerminal +isTerminalOfAllSegments isEvent isFirstEventIteration isFirstEventIterationDirectlyAfterInitial +isFullRestart isAfterSimulationStart isZeroCrossing storeResults getTime ``` -## Variable definitions in functions +## Code Generation -The following functions can be used to define states and algebraic variables inside functions: +This section lists internal functions to **generate Julia code** of the +transformed equations. -```@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! +```@meta +CurrentModule = Modia ``` +```@docs +SimulationModel +generate_getDerivatives! +init! +outputs! +terminate! +derivatives! +DAEresidualsForODE! +affectEvent! +zeroCrossings! +affectStateEvent! +timeEventCondition! +affectTimeEvent! +addToResult! +getFloatType +measurementToString +``` diff --git a/docs/src/index.md b/docs/src/index.md index f6db076..84548cc 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,4 +1,4 @@ -activ# Modia Documentation +# 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 [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 @@ -140,7 +140,7 @@ These changes should usually not influence user models. 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 [Variables of built-in Components](@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. diff --git a/models/HeatTransfer/InsulatedRod2.jl b/models/HeatTransfer/InsulatedRod2.jl index d88fb1b..e9007fa 100644 --- a/models/HeatTransfer/InsulatedRod2.jl +++ b/models/HeatTransfer/InsulatedRod2.jl @@ -101,7 +101,7 @@ end # Open an initialized InsulatedRod2 model and return a reference to it function openInsulatedRod!(instantiatedModel::SimulationModel{FloatType,TimeType}, ID)::InsulatedRodStruct{FloatType} where {FloatType,TimeType} obj::InsulatedRodStruct{FloatType} = Modia.get_instantiatedSubmodel(instantiatedModel, ID) - Modia.get_Vector_x_segmented_value!(instantiatedModel, obj.T_startIndex, obj.T) + Modia.copy_Vector_x_segmented_value_from_state(instantiatedModel, obj.T_startIndex, obj.T) return obj end @@ -127,6 +127,6 @@ function computeInsulatedRodDerivatives!(instantiatedModel, obj::InsulatedRodStr for i in 1:length(T) obj.der_T[i] = k*(T_grad1(T,Ta,i) - T_grad2(T,Tb,i)) end - Modia.add_der_x_segmented_value!(instantiatedModel, obj.T_startIndex, obj.der_T) + Modia.copy_der_x_segmented_value_to_state(instantiatedModel, obj.T_startIndex, obj.der_T) return true end diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 566a528..e7016c0 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1680,20 +1680,22 @@ get_instantiatedSubmodel(instantiatedModel, ID) = instantiatedModel.buildDict[ID """ - 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 + startIndex = new_x_segmented_variable!( + partiallyInstantiatedModel::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 +Generate new states (`x_segmented` and `der_x_segmented` variables) and return the +`startIndex` of the variables in order that actual values can be inquired or copied from the +state `x` and state derivative `der(x)`vectors via [`get_x_startIndex_from_x_segmented_startIndex`](@ref). +`startOrInit` contain the `start` or `init` values of the newly generated `x_segmented` variable. -- 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] +Actual values of these new variables are stored in: -Value startOrInit is the start/init value used during re-initialization of the new segment with initFullRestart!(..). +- `instantiatedModel.x_segmented[startIndex:startIndex+prod(dims(startOrInit))-1]` +- `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!(..)`. """ 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} @@ -1760,23 +1762,26 @@ end """ - x_startIndex = get_x_startIndex_from_x_segmented_startIndex(instantiatedModel::SimulationModel, x_segmented_startIndex) + 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!(..)). +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 + index = new_w_segmented_variable!( + partiallyInstantiatedModel::SimulationModel, name::String, + 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. +Generate new local variable (`w_segmented` variable) and return the `index` of the variable +in order that actual values can be inquired or copied from the result data structure. +New values of `w_segmented` variables need only to be computed at communication points. Value w_segmented_default is stored as default value and defines type and (fixed) size of the variable -in this segment. +in this simulation segment. """ function new_w_segmented_variable!(m::SimulationModel, name::String, w_segmented_default, unit::String="")::Int result = m.result @@ -1810,9 +1815,10 @@ end """ - new_alias_segmented_variable!(partiallyInstantiatedModel, name, aliasName, aliasNegate=false) + new_alias_segmented_variable!(partiallyInstantiatedModel::SimulationModel, + name, aliasName, aliasNegate=false) -Define new alias segmented variable. +Define new alias variable. """ function new_alias_segmented_variable!(m::SimulationModel, name::String, aliasName::String, aliasNegate::Bool=false)::Int result = m.result @@ -1832,8 +1838,8 @@ end """ startIndex = new_z_segmented_variable!(instantiatedModel, nz) -Reserve storage location for nz new segmented zero crossing function and return the startIndex to -copy it in the vectors of zero crossings +Generate `nz` new zero crossing variables and return the startIndex to of the variables +in order that actual values can be copied into the vector of zero crossings. """ function new_z_segmented_variable!(m::SimulationModel{F,TimeType}, nz::Int)::Int where {F,TimeType} eh = m.eventHandler @@ -1850,58 +1856,60 @@ end """ - value = Modia.get_scalar_x_segmented_value(instantiatedModel, startIndex) + value = Modia.copy_scalar_x_segmented_value_from_state(instantiatedModel, startIndex) -Return scalar segmented state value from instantiatedModel given `startIndex` +Return value of scalar x_segmented variable from state vector `x` by providing its `startIndex` (returned from `new_x_segmented_variable!(..)`). """ -get_scalar_x_segmented_value(m::SimulationModel, startIndex::Int) = m.x_segmented[startIndex] +copy_scalar_x_segmented_value_from_state(m::SimulationModel, startIndex::Int) = m.x_segmented[startIndex] """ - value = Modia.get_SVector3_x_segmented_value(instantiatedModel, startIndex) + value = Modia.copy_SVector3_x_segmented_value_from_state(instantiatedModel, startIndex) -Return SVector{3,FloatType}(..) segmented state value from instantiatedModel given `startIndex` +Return value of `SVector{3,FloatType}` x_segmented variable from state vector `x` by providing its `startIndex` (returned from `new_x_segmented_variable!(..)`). """ -@inline get_SVector3_x_segmented_value(m::SimulationModel{FloatType,TimeType}, startIndex::Int) where {FloatType,TimeType} = begin +@inline copy_SVector3_x_segmented_value_from_state(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_segmented_value!(instantiatedModel::SimulationModel, startIndex, xi::Vector{FloatType})::Nothing + Modia.copy_Vector_x_segmented_value_from_state(instantiatedModel::SimulationModel, startIndex, xi::Vector{FloatType})::Nothing -Copy state from `instantiatedModel` at index `startIndex` into pre-allocated vector `xi`. +Return value of `Vector{FloatType}` x_segmented variable from state vector `x` by providing its `startIndex` +(returned from `new_x_segmented_variable!(..)`) and copying it into the pre-allocated vector `xi`. """ -@inline function get_Vector_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, xi::Vector{FloatType})::Nothing where {FloatType,TimeType} +@inline function copy_Vector_x_segmented_value_from_state(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_segmented_value!(instantiatedModel, startIndex, der_x_segmented_value::[FloatType|Vector{FloatType}]) + Modia.copy_der_x_segmented_value_to_state(instantiatedModel, startIndex, der_x_segmented_value::[FloatType|Vector{FloatType}]) -Copy scalar or array segmented state derivative value `der_x_segmented_value` into `instantiatedModel` starting at index `startIndex` -(returned from `new_x_segmented_variable!(..)`). +Copy `der_x_segmented_value` to state derivative vector `der(x)` by providing its `startIndex` +(returned from `new_x_segmented_variable!(..)`) and copying it into the pre-allocated vector `der_x_segmented_value`. """ -@inline function add_der_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segmented_value::FloatType)::Nothing where {FloatType,TimeType} +@inline function copy_der_x_segmented_value_to_state(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 -@inline function add_der_x_segmented_value!(m::SimulationModel{FloatType,TimeType}, startIndex::Int, der_x_segmented_value::Vector{FloatType})::Nothing where {FloatType,TimeType} +@inline function copy_der_x_segmented_value_to_state(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_segmented_value!(instantiatedModel::SimulationModel, index::Int, w_segmented_value)::Nothing + Modia.copy_w_segmented_value_to_result(instantiatedModel::SimulationModel, index::Int, w_segmented_value)::Nothing -Store deepcopy(w_segmented_value) at index in instantiatedModel. +Copy value of local variable (`w-segmented`) to result by providing its `index` +(returned from `new_w_segmented_variable!`), """ -@inline function add_w_segmented_value!(m::SimulationModel, index::Int, w_segmented_value)::Nothing +@inline function copy_w_segmented_value_to_result(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])) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 55eb3f1..9a6c929 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -170,11 +170,11 @@ end function openLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, ID)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} ls = Modia.get_instantiatedSubmodel(instantiatedModel,ID).ls - Modia.get_Vector_x_segmented_value!(instantiatedModel, ls.x_startIndex, ls.x) + Modia.copy_Vector_x_segmented_value_from_state(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_segmented_value!(instantiatedModel, ls.w_index, ls.w) + Modia.copy_w_segmented_value_to_result(instantiatedModel, ls.w_index, ls.w) end return ls end @@ -188,7 +188,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_segmented_value!(instantiatedModel, ls.x_startIndex, ls.der_x) + Modia.copy_der_x_segmented_value_to_state(instantiatedModel, ls.x_startIndex, ls.der_x) return true end