Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare release 0.11.0 #166

Merged
merged 2 commits into from
Jun 4, 2023
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
2 changes: 1 addition & 1 deletion 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.10.0"
version = "0.11.0"

[deps]
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
Expand Down
14 changes: 14 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ functionalities of these packages.

## Release Notes

### Version 0.11.0

- Require ModiaBase 0.11.1
- Manifest.toml file removed.
- test.yml for github actions changed to use Julia 1.9.0

**Non-backwards** compatible changes

These changes only influence models that use the new feature of built-in components.

- `_buildFunction` argument list changed (options of @instantiateModel added)



### Version 0.10.0

- Initial support of segmented simulations where the number of states can change during simulation.
Expand Down
3 changes: 2 additions & 1 deletion models/HeatTransfer/InsulatedRod2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ end


# Called from @instantiateModel(..) before getDerivatives!(..) is generated
function build_InsulatedRod2!(model::AbstractDict, FloatType, TimeType, unitless::Bool, ID, pathAST)
function build_InsulatedRod2!(model::AbstractDict, modelModule, FloatType, TimeType, instantiateModelOptions, ID, pathAST)
unitless = instantiateModelOptions[:unitless]
model = model | Model(
insRod = Var(hideResult=true), # InsulatedRodStruct instance (an equation to return this variable is generated by _buildFunction)
success = Var(hideResult=true), # Dummy return argument
Expand Down
4 changes: 2 additions & 2 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.10.0"
const Date = "2023-05-29"
const Version = "0.11.0"
const Date = "2023-06-04"
const modelsPath = joinpath(Modia.path, "models")

print(" \n\nWelcome to ")
Expand Down
46 changes: 34 additions & 12 deletions src/ModiaLang.jl
Original file line number Diff line number Diff line change
Expand Up @@ -583,13 +583,15 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod
if int_v > 0
value = value / u"s"
end
# if length(value) == 1

if ! (typeof(value) <: AbstractArray)
un = unit(value)
else
elseif length(value) > 0
un = unit.(value)
@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]
else
un = ""
end
return SignalTables.unitAsParseableString(un)
end
Expand Down Expand Up @@ -836,56 +838,59 @@ end
appendSymbol(path::Nothing, name::Symbol) = name
appendSymbol(path , name::Symbol) = :( $path.$name )


"""
modifiedModel = buildSubmodels!(model, modelModule, FloatType, TimeType, unitless, buildDict::OrderedDict)
modifiedModel = buildSubmodels!(model, modelModule, FloatType, TimeType,
instantiateModelOptions, buildDict::AbstractDict)

Traverse `model` and for every `<submodel>` that is a `Model(..)` and has a key-value pair
`:_buildFunction = Par(functionName = <buildFunction>)` and optionally `:_buildOption=<buildOption>`, call

```
updatedSubmodel = <buildFunction>(submodel, FloatType::Type, TimeType::Type, unitless::Bool,
updatedSubmodel = <buildFunction>(submodel, modelModule, FloatType::Type, TimeType::Type, instantiateModelOptions,
ID, pathAST::Union{Expr,Symbol,Nothing}, buildOption = <buildOption>)
```

A new `updatedSubmodel` is generated from `submodel` merged with additional code and then returned.
The arguments of `<buildFunction>`are:

- `updatedSubmodel`: A potentially new reference to the updated `submodel`
- `modelModule`: Module in which the model is defined
- `FloatType`, `TimeType`: Types used when instantiating `SimulationModel{FloatType,TimeType}`
- `unitless`: Argument `unitless` of `@instantiateModel`.
- `instantiateModelOptions`: Optional arguments of `@instantiateModel` provided as `OrderedDict{Symbol,Any}`.
- `ID`: Unique ID to identify the generated submodel (to be used in the code merged into the submodel)
- `pathAST`: Path upto `<submodel>` as Abstract Syntax Tree, such as: `:( a.b.c )`
(this path might be used as part of a variable name in the code merged into the submodel).
- `buildOption`: Option used for the generation of `buildCode`.

Note, keys `_buildFunction` and `_buildOption` have been deleted in the returned `updatedSubmodel`.
"""
function buildSubmodels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, unitless::Bool,
function buildSubmodels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, instantiateModelOptions::OrderedDict{Symbol,Any},
buildDict::OrderedDict{String,Any}; pathAST::Union{Expr,Symbol,Nothing}=nothing)
if haskey(model, :_buildFunction)
_buildFunction = model[:_buildFunction]
if haskey(_buildFunction, :functionName)
buildFunction = _buildFunction[:functionName]
else
@error "Model $pathAST has key :_buildFunction but its value has no key :functionName"
end
end
delete!(model, :_buildFunction)
ID = modelPathAsString(pathAST)
ID = modelPathAsString(pathAST)
quotedPathAST = Meta.quot(pathAST)
if haskey(model, :_buildOption)
buildOption = model[:_buildOption]
delete!(model, :_buildOption)
(model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $ID, $quotedPathAST, buildOption=$buildOption)) )
(model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $modelModule, $FloatType, $TimeType, $instantiateModelOptions, $ID, $quotedPathAST, buildOption=$buildOption)))
else
(model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $ID, $quotedPathAST)))
(model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $modelModule, $FloatType, $TimeType, $instantiateModelOptions, $ID, $quotedPathAST)))
end
buildDict[ID] = instantiatedSubmodelStruct
return model
end

for (key,value) in model
if typeof(value) <: OrderedDict && haskey(value, :_class) && value[:_class] == :Model
model[key] = buildSubmodels!(value, modelModule, FloatType, TimeType, unitless, buildDict; pathAST=appendSymbol(pathAST,key))
model[key] = buildSubmodels!(value, modelModule, FloatType, TimeType, instantiateModelOptions, buildDict; pathAST=appendSymbol(pathAST,key))
end
end
return model
Expand Down Expand Up @@ -954,11 +959,28 @@ function instantiateModel(model; modelName="", modelModule=nothing, source=nothi
if typeof(model) <: NamedTuple || typeof(model) <: Dict || typeof(model) <: OrderedDict
# Traverse model and execute functions _buildFunction(..), to include code into sub-models
buildDict = OrderedDict{String,Any}()
instantiateModelOptions = OrderedDict{Symbol, Any}(
:modelName => modelName,
:source => source,
:aliasReduction => aliasReduction,
:unitless => unitless,
:log => log,
:logModel => logModel,
:logDetails => logDetails,
:logStateSelection => logStateSelection,
:logCode => logCode,
:logExecution => logExecution,
:logCalculations => logCalculations,
:logTiming => logTiming,
:logFile => logFile,
:evaluateParameters => evaluateParameters,
:saveCodeOnFile => saveCodeOnFile)

TimeType = if FloatType <: Measurements.Measurement ||
FloatType <: MonteCarloMeasurements.AbstractParticles;
baseType(FloatType) else FloatType end # baseType(..) is defined in CodeGeneration.jl
model = deepcopy(model)
model = buildSubmodels!(model, modelModule, FloatType, TimeType, unitless, buildDict)
model = buildSubmodels!(model, modelModule, FloatType, TimeType, instantiateModelOptions, buildDict)

if logModel
@showModel(model)
Expand Down
6 changes: 3 additions & 3 deletions test/TestLinearSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ mutable struct LinearStateSpaceBuild{FloatType}
end


function build_LinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, unitless::Bool,
ID, pathAST::Union{Expr,Symbol,Nothing})
# Called from @instantiatedModel, during instantiation of the model.
function build_LinearStateSpace!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type,
instantiateModelOptions, ID, pathAST::Union{Expr,Symbol,Nothing})
# Called from @instantiateModel, during instantiation of the model.
pathAsString = Modia.modelPathAsString(pathAST)
#println("... 1: build_LinearStateSpace! called for path = ", pathAsString)

Expand Down
4 changes: 2 additions & 2 deletions test/TestMultiReturningFunction10.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ end
struct Dummy
end;

function myBuildFunction(model::AbstractDict, FloatType::Type, TimeType::Type, unitless::Bool,
ID, modelPathAST; buildOption = "Default")
function myBuildFunction(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type,
instantiateModelOptions, ID, modelPathAST; buildOption = "Default")
modelPathAsString = if isnothing(modelPathAST); "" else string(modelPathAST) end
println(" TestMultiReturningFunction10: Test output from function myBuildFunction at modelPath = \"$modelPathAsString\":\n Code could be constructed here and merged to the model with buildOption=$buildOption")
return (model, Dummy())
Expand Down