Skip to content

Commit 797cfec

Browse files
committed
Further improvements of built-in components
1 parent fdb94a9 commit 797cfec

10 files changed

+107
-100
lines changed

docs/src/index.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,19 @@ functionalities of these packages.
4444

4545
### Version 0.10.0
4646

47-
-
47+
- Initial support of segmented simulations where the number of states can change during simulation.
48+
For examples, see `Modia/test/TestHeatTransfer2.jl` and models in directory `Modia3D/test/Segmented`
49+
(of release 0.12.0 and later). The tutorial will be updated for this feature in an upcoming version.
50+
4851

49-
**Non-backwards** compatible changes (should usually not influende user models)
52+
**Non-backwards** compatible changes
53+
54+
These changes should usually not influence user models.
5055

5156
- `_buildFunction = <functionName>` changed to `_buildFunction = Par(functionName = <functionName>)` and
52-
additional argument `unitless` added to `<functionName>`.
53-
- `_instantiateFunction = Par(..)` changed to `_initSegmentFunction = Par(..)`
57+
changed argument list of `<functionName>`.
58+
- `_instantiateFunction = Par(..)` changed to `_initSegmentFunction = Par(functionName = <functionName>)`
59+
and changed argument list of `<functionName>`.
5460

5561

5662
### Version 0.9.4

models/HeatTransfer.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ For more details see Appendix B1 of [DOI: 10.3390/electronics12030500](https://d
9595
- `der(T)': Vector of derivatives of `T`.
9696
"""
9797
InsulatedRod2 = Model(;
98-
_buildFunction = Par(functionName = :(buildInsulatedRod2!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated
99-
_initSegmentFunction = Par(functionName = :(initInsulatedRod2ForNewSegment!)), # Called once before initialization of a new simulation segment
98+
_buildFunction = Par(functionName = :(build_InsulatedRod2!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated
99+
_initSegmentFunction = Par(functionName = :(initSegment_InsulatedRod2!)), # Called once before initialization of a new simulation segment
100100
L = 1.0u"m", # Length of rod
101101
A = 0.0004u"m^2", # Rod area
102102
rho = 7500.0u"kg/m^3", # Density of rod material

models/HeatTransfer/InsulatedRod2.jl

+30-37
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
# Structure holding the internal memory of the insulated rod
88
mutable struct InsulatedRodStruct{FloatType}
99
# Parameters
10-
path::String # path name of instance
1110
Ge::FloatType # = lambda*A/dx
1211
Ge2::FloatType # = 2*Ge
1312
k::FloatType # = Ge / (c*rho*A*dx)
@@ -19,17 +18,35 @@ mutable struct InsulatedRodStruct{FloatType}
1918

2019
# Start index of state and state derivative vectors
2120
T_startIndex::Int
21+
22+
InsulatedRodStruct{FloatType}() where {FloatType} = new()
23+
end
24+
25+
26+
# Called from @instantiateModel(..) before getDerivatives!(..) is generated
27+
function build_InsulatedRod2!(model::AbstractDict, FloatType, TimeType, unitless::Bool, ID, pathAST)
28+
model = model | Model(
29+
insRod = Var(hideResult=true), # InsulatedRodStruct instance (an equation to return this variable is generated by _buildFunction)
30+
success = Var(hideResult=true), # Dummy return argument
31+
equations = :[
32+
# copy states into insRod.T and return insRod
33+
insRod = openInsulatedRod!(instantiatedModel, $ID)
34+
35+
# equations at the boundaries
36+
port_a.Q_flow = getGe2(insRod, Val($unitless))*(port_a.T - getT1( insRod, Val($unitless)))
37+
port_b.Q_flow = getGe2(insRod, Val($unitless))*(port_b.T - getTend(insRod, Val($unitless)))
2238

23-
InsulatedRodStruct{FloatType}(path::String) where {FloatType} = new(path,false)
39+
# compute insRod.der_T and copy it into state derivatives
40+
success = computeInsulatedRodDerivatives!(instantiatedModel, insRod, port_a.T, port_b.T) # instantiatedModel is provided in the generated code
41+
])
42+
43+
return (model, InsulatedRodStruct{FloatType}())
2444
end
2545

2646

2747
# Called once before initialization of first simulation segment
28-
function initInsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambda, c, T0, nT)::Nothing where {FloatType}
29-
#L, A, rho=7500.0u"kg/m^3", lambda=74.0u"W/(m*K)", c=450.0u"J/(kg*K)", T0=293.15u"K", nT=1)::Nothing where {FloatType}
30-
48+
function initFirstSegment_InsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambda, c, T0, nT)::Nothing where {FloatType}
3149
# Convert to SI units, strip units and check that values are positives
32-
path = obj.path
3350
#=
3451
@show L
3552
@Modia.strippedPositive!(path, L)
@@ -65,37 +82,13 @@ function initInsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambd
6582
end
6683

6784

68-
# Called from @instantiateModel(..) before getDerivatives!(..) is generated
69-
function buildInsulatedRod2!(model::AbstractDict, FloatType, TimeType, unitless::Bool, buildDict, path)
70-
pathAsString = Modia.modelPathAsString(path)
71-
extraModelCode = Model( # extra code to be merged with model
72-
insRod = Var(hideResult=true), # InsulatedRodStruct instance (an equation to return this variable is generated by _buildFunction)
73-
success = Var(hideResult=true), # Dummy return argument
74-
equations = :[
75-
# copy states into insRod.T and return insRod
76-
insRod = openInsulatedRod!(instantiatedModel, $pathAsString)
77-
78-
# equations at the boundaries
79-
port_a.Q_flow = getGe2(insRod, Val($unitless))*(port_a.T - getT1( insRod, Val($unitless)))
80-
port_b.Q_flow = getGe2(insRod, Val($unitless))*(port_b.T - getTend(insRod, Val($unitless)))
81-
82-
# compute insRod.der_T and copy it into state derivatives
83-
success = computeInsulatedRodDerivatives!(instantiatedModel, insRod, port_a.T, port_b.T) # instantiatedModel is provided in the generated code
84-
])
85-
86-
# Store build info in buildDict
87-
buildDict[pathAsString] = InsulatedRodStruct{FloatType}(pathAsString)
88-
return extraModelCode
89-
end
90-
91-
9285
# Called once before initialization of a new simulation segment
93-
function initInsulatedRod2ForNewSegment!(instantiatedModel::SimulationModel{FloatType,TimeType},
94-
parameters::AbstractDict, path::String; log=false)::Nothing where {FloatType,TimeType}
95-
obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path]
96-
86+
function initSegment_InsulatedRod2!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String, ID,
87+
parameters::AbstractDict; log=false)::Nothing where {FloatType,TimeType}
88+
obj::InsulatedRodStruct{FloatType} = Modia.get_instantiatedSubmodel(instantiatedModel, ID)
89+
9790
if Modia.isFirstInitialOfAllSegments(instantiatedModel)
98-
initInsulatedRod2!(obj; parameters...)
91+
initFirstSegment_InsulatedRod2!(obj; parameters...)
9992
end
10093

10194
# Define a vector of new state and state derivative variables
@@ -105,8 +98,8 @@ end
10598

10699

107100
# Open an initialized InsulatedRod2 model and return a reference to it
108-
function openInsulatedRod!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::InsulatedRodStruct{FloatType} where {FloatType,TimeType}
109-
obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path]
101+
function openInsulatedRod!(instantiatedModel::SimulationModel{FloatType,TimeType}, ID)::InsulatedRodStruct{FloatType} where {FloatType,TimeType}
102+
obj::InsulatedRodStruct{FloatType} = Modia.get_instantiatedSubmodel(instantiatedModel, ID)
110103
Modia.get_Vector_x_segmented_value!(instantiatedModel, obj.T_startIndex, obj.T)
111104
return obj
112105
end

src/CodeGeneration.jl

+9
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,15 @@ function addToResult!(m::SimulationModel{FloatType,TimeType}, x, time, w_invaria
16661666
end
16671667

16681668

1669+
"""
1670+
obj = get_instantiatedSubmodel(instantiatedModel, ID)
1671+
1672+
Return reference `obj` to an instantiated submodel struct, given `intantiatedModel` and the `ID` of the submodel.
1673+
"""
1674+
get_instantiatedSubmodel(instantiatedModel, ID) = instantiatedModel.buildDict[ID]
1675+
1676+
1677+
16691678
"""
16701679
index = new_x_segmented_variable!(
16711680
instantiatedModel::SimulationModel,

src/EvaluateParameters.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType
405405
if log
406406
println(" 13: +++ Instantiated $path: $instantiateFunction will be called to instantiate sub-model and define varying states\n\n")
407407
end
408-
Core.eval(modelModule, :($instantiateFunction($m, $current, $path, log=$log)))
408+
Core.eval(modelModule, :($instantiateFunction($m, $path, $path, $current, log=$log)))
409409
push!(m.instantiateFunctions, (instantiateFunction, current, path))
410410
end
411411
return current

src/Modia.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Modia
1010

1111
const path = dirname(dirname(@__FILE__)) # Absolute path of package directory
1212
const Version = "0.10.0"
13-
const Date = "2023-05-22"
13+
const Date = "2023-05-29"
1414
const modelsPath = joinpath(Modia.path, "models")
1515

1616
print(" \n\nWelcome to ")

src/ModiaLang.jl

+22-23
Original file line numberDiff line numberDiff line change
@@ -837,56 +837,55 @@ appendSymbol(path::Nothing, name::Symbol) = name
837837
appendSymbol(path , name::Symbol) = :( $path.$name )
838838

839839
"""
840-
modifiedModel = buildSubModels!(model, modelModule, FloatType, TimeType, unitless, buildDict::OrderedDict)
840+
modifiedModel = buildSubmodels!(model, modelModule, FloatType, TimeType, unitless, buildDict::OrderedDict)
841841
842-
Traverse `model` and for every `<subModel>` that is a `Model(..)` and has a key-value pair
843-
`:_buildFunction = <buildFunction>` and optionally `:_buildOption=<buildOption>`, call
842+
Traverse `model` and for every `<submodel>` that is a `Model(..)` and has a key-value pair
843+
`:_buildFunction = Par(functionName = <buildFunction>)` and optionally `:_buildOption=<buildOption>`, call
844844
845845
```
846-
buildCode = <buildFunction>(<subModel>, modelModule, FloatType::Type, TimeType::Type, unitless::Bool,
847-
buildDict::OrderedDict{String,Any},
848-
modelPath::Union{Expr,Symbol,Nothing},
849-
buildOption = <buildOption>)
846+
updatedSubmodel = <buildFunction>(submodel, FloatType::Type, TimeType::Type, unitless::Bool,
847+
ID, pathAST::Union{Expr,Symbol,Nothing}, buildOption = <buildOption>)
850848
```
851849
852-
The`buildCode` is merged to the corresponding `<subModel>` in the calling environment.
850+
A new `updatedSubmodel` is generated from `submodel` merged with additional code and then returned.
853851
The arguments of `<buildFunction>`are:
854852
855-
- `subModel`: The returned `buildCode` is merged to `submodel`
853+
- `updatedSubmodel`: A potentially new reference to the updated `submodel`
856854
- `FloatType`, `TimeType`: Types used when instantiating `SimulationModel{FloatType,TimeType}`
857855
- `unitless`: Argument `unitless` of `@instantiateModel`.
858-
- `modelPath`: Path upto `<subModel>`, such as: `:( a.b.c )`.
859-
- `buildDict`: Dictionary, that will be stored in the corresponding SimulationModel instance and
860-
that allows to store information about the build-process,
861-
typically with key `string(modelPath)` (if modelPath==Nothing, key="" is used).
856+
- `ID`: Unique ID to identify the generated submodel (to be used in the code merged into the submodel)
857+
- `pathAST`: Path upto `<submodel>` as Abstract Syntax Tree, such as: `:( a.b.c )`
858+
(this path might be used as part of a variable name in the code merged into the submodel).
862859
- `buildOption`: Option used for the generation of `buildCode`.
863860
864-
Note, keys `_buildFunction` and `_buildOption` are deleted from the corresponding `<subModel>`.
861+
Note, keys `_buildFunction` and `_buildOption` have been deleted in the returned `updatedSubmodel`.
865862
"""
866-
function buildSubModels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, unitless::Bool,
867-
buildDict::OrderedDict{String,Any}; path::Union{Expr,Symbol,Nothing}=nothing)
863+
function buildSubmodels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, unitless::Bool,
864+
buildDict::OrderedDict{String,Any}; pathAST::Union{Expr,Symbol,Nothing}=nothing)
868865
if haskey(model, :_buildFunction)
869866
_buildFunction = model[:_buildFunction]
870867
if haskey(_buildFunction, :functionName)
871868
buildFunction = _buildFunction[:functionName]
872869
else
873-
@error "Model $path has key :_buildFunction but its value has no key :functionName"
870+
@error "Model $pathAST has key :_buildFunction but its value has no key :functionName"
874871
end
875872
delete!(model, :_buildFunction)
876-
quotedPath = Meta.quot(path)
873+
ID = modelPathAsString(pathAST)
874+
quotedPathAST = Meta.quot(pathAST)
877875
if haskey(model, :_buildOption)
878876
buildOption = model[:_buildOption]
879877
delete!(model, :_buildOption)
880-
buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $buildDict, $quotedPath, buildOption=$buildOption)) )
878+
(model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $ID, $quotedPathAST, buildOption=$buildOption)) )
881879
else
882-
buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $buildDict, $quotedPath)))
880+
(model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $ID, $quotedPathAST)))
883881
end
884-
return model | buildCode
882+
buildDict[ID] = instantiatedSubmodelStruct
883+
return model
885884
end
886885

887886
for (key,value) in model
888887
if typeof(value) <: OrderedDict && haskey(value, :_class) && value[:_class] == :Model
889-
model[key] = buildSubModels!(value, modelModule, FloatType, TimeType, unitless, buildDict; path=appendSymbol(path,key))
888+
model[key] = buildSubmodels!(value, modelModule, FloatType, TimeType, unitless, buildDict; pathAST=appendSymbol(pathAST,key))
890889
end
891890
end
892891
return model
@@ -959,7 +958,7 @@ function instantiateModel(model; modelName="", modelModule=nothing, source=nothi
959958
FloatType <: MonteCarloMeasurements.AbstractParticles;
960959
baseType(FloatType) else FloatType end # baseType(..) is defined in CodeGeneration.jl
961960
model = deepcopy(model)
962-
model = buildSubModels!(model, modelModule, FloatType, TimeType, unitless, buildDict)
961+
model = buildSubmodels!(model, modelModule, FloatType, TimeType, unitless, buildDict)
963962

964963
if logModel
965964
@showModel(model)

test/TestHeatTransfer2.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ HeatedRod2 = Model(
1313
)
1414

1515
# Model with unit
16-
heatedRod2a = @instantiateModel(HeatedRod2, logCode=false, unitless=true)
16+
heatedRod2a = @instantiateModel(HeatedRod2, logCode=false, unitless=false)
1717
simulate!(heatedRod2a, stopTime = 1e5, log=true, merge=Map(rod = Map(nT=8)), logParameters=true, logEvaluatedParameters=true)
1818
showInfo(heatedRod2a)
1919

0 commit comments

Comments
 (0)