From fdb94a971e65b84ec29312b8a78d09bd769d0833 Mon Sep 17 00:00:00 2001 From: Martin Otter Date: Mon, 29 May 2023 12:50:19 +0200 Subject: [PATCH 1/5] Updated code for acausal built-in components + added new test model TestHeatTransfer2 where code size is independent from number of temperature nodes. --- Project.toml | 2 +- docs/src/index.md | 11 +++ models/HeatTransfer.jl | 36 +++++++ models/HeatTransfer/InsulatedRod2.jl | 138 +++++++++++++++++++++++++++ src/CodeGeneration.jl | 2 +- src/EvaluateParameters.jl | 16 ++-- src/EventHandler.jl | 2 +- src/Modia.jl | 33 ++++++- src/ModiaLang.jl | 30 +++--- test/TestHeatTransfer2.jl | 28 ++++++ test/TestLinearSystems.jl | 6 +- test/TestMultiReturningFunction10.jl | 14 +-- test/include_all.jl | 1 + 13 files changed, 285 insertions(+), 34 deletions(-) create mode 100644 models/HeatTransfer/InsulatedRod2.jl create mode 100644 test/TestHeatTransfer2.jl diff --git a/Project.toml b/Project.toml index bd35b2d..73b989d 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.9.4" +version = "0.10.0-dev" [deps] DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" diff --git a/docs/src/index.md b/docs/src/index.md index d083ec5..b0fd048 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -42,6 +42,17 @@ functionalities of these packages. ## Release Notes +### Version 0.10.0 + +- + +**Non-backwards** compatible changes (should usually not influende user models) + +- `_buildFunction = ` changed to `_buildFunction = Par(functionName = )` and + additional argument `unitless` added to ``. +- `_instantiateFunction = Par(..)` changed to `_initSegmentFunction = Par(..)` + + ### Version 0.9.4 - Precompile statements included (compilation of Modia package takes more time, but startup of Modia model simulations is faster). diff --git a/models/HeatTransfer.jl b/models/HeatTransfer.jl index 1a57659..323b69f 100644 --- a/models/HeatTransfer.jl +++ b/models/HeatTransfer.jl @@ -70,4 +70,40 @@ InsulatedRod = Model( ] ) + +include("HeatTransfer/InsulatedRod2.jl") + +""" + insulatedRod = InsulatedRod2(; 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") +Generate a Model(..) instance of an insulated rod with length `L` and cross sectional area `A` that +models 1D heat transfer from port_a to port_b. The rod is discretized with `nT` internal temperature nodes that are initialized with `T0`. +This is an acausal built-in component where the code size does not depend on `nT` and +`nT` can still be changed after model code is generated and compiled. + +For more details see Appendix B1 of [DOI: 10.3390/electronics12030500](https://doi.org/10.3390/electronics12030500). + +# Optional Arguments: +- `rho`: density of rod material +- `lambda`: thermal conductivity of rod material +- `c`: specific heat capacity of rod material +- `T0`: initial temperature of internal temperature nodes +- `nT`: number of temperature nodes (`nT > 0`). + +# Internal variables that can be inquired/plotted: +- `T`: Vector of temperatures at the internal temperature nodes +- `der(T)': Vector of derivatives of `T`. +""" +InsulatedRod2 = Model(; + _buildFunction = Par(functionName = :(buildInsulatedRod2!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated + _initSegmentFunction = Par(functionName = :(initInsulatedRod2ForNewSegment!)), # Called once before initialization of a new simulation segment + L = 1.0u"m", # Length of rod + A = 0.0004u"m^2", # Rod area + rho = 7500.0u"kg/m^3", # Density of rod material + lambda = 74.0u"W/(m*K)", # Thermal conductivity of rod material + c = 450.0u"J/(kg*K)", # Specific heat capacity of rod material + T0 = 293.15u"K", # Initial temperature of internal temperature nodes + nT = 1, # Number of temperature nodes (nT > 0). + port_a = HeatPort, # heat port on left side + port_b = HeatPort # heat port on right side +) diff --git a/models/HeatTransfer/InsulatedRod2.jl b/models/HeatTransfer/InsulatedRod2.jl new file mode 100644 index 0000000..d0d0701 --- /dev/null +++ b/models/HeatTransfer/InsulatedRod2.jl @@ -0,0 +1,138 @@ +# License for this file: MIT (expat) +# Copyright 2023, DLR Institute of System Dynamics and Control +# +# This file is included in Modia/models/HeatTranser.jl + + +# Structure holding the internal memory of the insulated rod +mutable struct InsulatedRodStruct{FloatType} + # Parameters + path::String # path name of instance + Ge::FloatType # = lambda*A/dx + Ge2::FloatType # = 2*Ge + k::FloatType # = Ge / (c*rho*A*dx) + T_init::Vector{FloatType} # initial states + + # Internal states and state deriatives + T::Vector{FloatType} # states + der_T::Vector{FloatType} # state derivatives + + # Start index of state and state derivative vectors + T_startIndex::Int + + InsulatedRodStruct{FloatType}(path::String) where {FloatType} = new(path,false) +end + + +# Called once before initialization of first simulation segment +function initInsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambda, c, T0, nT)::Nothing where {FloatType} + #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} + + # Convert to SI units, strip units and check that values are positives + path = obj.path + #= + @show L + @Modia.strippedPositive!(path, L) + @Modia.strippedPositive!(path, A) + @Modia.strippedPositive!(path, rho) + @Modia.strippedPositive!(path, lambda) + @Modia.strippedPositive!(path, c) + @Modia.strippedPositive!(path, T0) + @Modia.strippedPositive!(path, nT) + @show L + @show A + @show rho + @show lambda + =# + L = stripUnit(L) + A = stripUnit(A) + rho = stripUnit(rho) + lambda = stripUnit(lambda) + c = stripUnit(c) + T0 = stripUnit(T0) + + # Compute derived parameters + dx = L/nT + obj.Ge = lambda*A/dx + obj.Ge2 = 2*obj.Ge + obj.k = obj.Ge / ( c*rho*A*dx ) + obj.T_init = fill(T0, nT) + + # Allocate and initialize internal states + obj.T = copy(obj.T_init) + obj.der_T = zeros(nT) + return nothing +end + + +# Called from @instantiateModel(..) before getDerivatives!(..) is generated +function buildInsulatedRod2!(model::AbstractDict, FloatType, TimeType, unitless::Bool, buildDict, path) + pathAsString = Modia.modelPathAsString(path) + extraModelCode = Model( # extra code to be merged with model + insRod = Var(hideResult=true), # InsulatedRodStruct instance (an equation to return this variable is generated by _buildFunction) + success = Var(hideResult=true), # Dummy return argument + equations = :[ + # copy states into insRod.T and return insRod + insRod = openInsulatedRod!(instantiatedModel, $pathAsString) + + # equations at the boundaries + port_a.Q_flow = getGe2(insRod, Val($unitless))*(port_a.T - getT1( insRod, Val($unitless))) + port_b.Q_flow = getGe2(insRod, Val($unitless))*(port_b.T - getTend(insRod, Val($unitless))) + + # compute insRod.der_T and copy it into state derivatives + success = computeInsulatedRodDerivatives!(instantiatedModel, insRod, port_a.T, port_b.T) # instantiatedModel is provided in the generated code + ]) + + # Store build info in buildDict + buildDict[pathAsString] = InsulatedRodStruct{FloatType}(pathAsString) + return extraModelCode +end + + +# Called once before initialization of a new simulation segment +function initInsulatedRod2ForNewSegment!(instantiatedModel::SimulationModel{FloatType,TimeType}, + parameters::AbstractDict, path::String; log=false)::Nothing where {FloatType,TimeType} + obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path] + + if Modia.isFirstInitialOfAllSegments(instantiatedModel) + initInsulatedRod2!(obj; parameters...) + end + + # Define a vector of new state and state derivative variables + obj.T_startIndex = Modia.new_x_segmented_variable!(instantiatedModel, path*".T", path*".der(T)", obj.T, "K") + return nothing +end + + +# Open an initialized InsulatedRod2 model and return a reference to it +function openInsulatedRod!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::InsulatedRodStruct{FloatType} where {FloatType,TimeType} + obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path] + Modia.get_Vector_x_segmented_value!(instantiatedModel, obj.T_startIndex, obj.T) + return obj +end + + +# Functions to inquire values from InsulatedRodStruct +getT1( insRod::InsulatedRodStruct, Unitless::Val{true}) = insRod.T[1] +getT1( insRod::InsulatedRodStruct, Unitless::Val{false}) = insRod.T[1]*u"K" + +getTend(insRod::InsulatedRodStruct, Unitless::Val{true}) = insRod.T[end] +getTend(insRod::InsulatedRodStruct, Unitless::Val{false}) = insRod.T[end]*u"K" + +getGe2( insRod::InsulatedRodStruct, Unitless::Val{true}) = insRod.Ge2 +getGe2( insRod::InsulatedRodStruct, Unitless::Val{false}) = insRod.Ge2*u"W/K" + +T_grad1(T,Ta,i) = if i == 1 ; (Ta - T[1])*2 else T[i-1] - T[i] end +T_grad2(T,Tb,i) = if i == length(T); (T[i] - Tb)*2 else T[i] - T[i+1] end + +function computeInsulatedRodDerivatives!(instantiatedModel, obj::InsulatedRodStruct{FloatType}, Ta, Tb)::Bool where {FloatType} + Ta::FloatType = stripUnit(Ta) + Tb::FloatType = stripUnit(Tb) + T = obj.T + k = obj.k + 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) + return true +end diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index f1a2b7c..4ce0425 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -336,7 +336,7 @@ mutable struct SimulationModel{FloatType,TimeType} # Available after propagateEvaluateAndInstantiate!(..) called instantiateFunctions::Vector{Tuple{Union{Expr,Symbol},OrderedDict{Symbol,Any},String}} - # All definitions `_instantiateFunction = Par(functionName = XXX)` in the model to call + # All definitions `_initSegmentFunction = Par(functionName = XXX)` in the model to call # `XXX(instantiatedModel, submodel, submodelPath)` in the order occurring during evaluation # of the parameters where, instantiatedFunctions[i] = (XXX, submodel, submodelPath) nsegments::Int # Current simulation segment diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index 7dfb682..ce40d38 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -210,7 +210,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType end current = OrderedDict{Symbol,Any}() # should be Map() - # Determine, whether "parameters" has a ":_constructor" or "_instantiateFunction" key and handle this specially + # Determine, whether "parameters" has a ":_constructor" or "_initSegmentFunction" key and handle this specially constructor = nothing instantiateFunction = nothing usePath = false @@ -248,13 +248,13 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType end end - elseif haskey(parameters, :_instantiateFunction) - # For example: obj = (_instantiateFunction = Par(functionName = :(instantiateLinearStateSpace!)) - _instantiateFunction = parameters[:_instantiateFunction] - if haskey(_instantiateFunction, :functionName) - instantiateFunction = _instantiateFunction[:functionName] + elseif haskey(parameters, :_initSegmentFunction) + # For example: obj = (_initSegmentFunction = Par(functionName = :(instantiateLinearStateSpace!)) + _initSegmentFunction = parameters[:_initSegmentFunction] + if haskey(_initSegmentFunction, :functionName) + instantiateFunction = _initSegmentFunction[:functionName] else - @warn "Model $path has key :_instantiateFunction but its value has no key :functionName" + @warn "Model $path has key :_initSegmentFunction but its value has no key :functionName" end elseif haskey(parameters, :value) @@ -269,7 +269,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType if log println(" 2: ... key = $k, value = $v") end - if k == :_constructor || k == :_buildFunction || k == :_buildOption || k == :_instantiateFunction || + if k == :_constructor || k == :_buildFunction || k == :_buildOption || k == :_initSegmentFunction || k == :_path || k == :_instantiatedModel || (k == :_class && !isnothing(constructor)) if log println(" 3: ... key = $k") diff --git a/src/EventHandler.jl b/src/EventHandler.jl index 35d2633..cb751f9 100644 --- a/src/EventHandler.jl +++ b/src/EventHandler.jl @@ -73,7 +73,7 @@ mutable struct EventHandler{FloatType,TimeType} nz::Int # Number of event indicators nzInvariant::Int # Number of event indicators defined in visible model equations # More event indicators can be defined by objects that are not visible in the generated code, i.e. nz >= nzInvariant - # These event indicators are defined in propagateEvaluateAndInstantiate!(..) via _instantiateFunction(..) + # These event indicators are defined in propagateEvaluateAndInstantiate!(..) via _initSegmentFunction(..) z::Vector{FloatType} # Vector of event indicators (zero crossings). If one of z[i] passes # zero, that is beforeEvent(z[i])*z[i] < 0, an event is triggered # (allocated during instanciation according to nz). diff --git a/src/Modia.jl b/src/Modia.jl index d0d0332..83fd29a 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -9,8 +9,8 @@ Main module of Modia. module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory -const Version = "0.9.4" -const Date = "2023-05-21" +const Version = "0.10.0" +const Date = "2023-05-22" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") @@ -170,6 +170,35 @@ The function is defined as: `stripUnit(v) = ustrip.(upreferred.(v))`. """ stripUnit(v) = ustrip.(upreferred.(v)) + +""" + @strippedPositive!(path, name) + +Convert `name` to its preferred units (default are the SI units), strip units and check that value is positive. +In case of error, use `string(name)` and `path` in the error message: + +# Example +``` +using Unitful +L1 = 2.0u"m" +@strippedPositive!("insulatedRod", L1) +# L1 = 2.0 + +L2 = -2.0u"m" +@strippedPositive!("insulatedRod", L2) +# error message: +# Error from +# insulatedRod = ...(..., L2 = -2.0u"m",...): L2 > 0 required.) +``` +""" +macro strippedPositive!(path, name) + nameAsString = string(name) + expr = :( $name = strippedPositive!($path, $(esc(name)), $nameAsString) ) + return expr +end +strippedPositive!(path::String, value, name) = stripUnit(value) > 0 ? stripUnit(value) : error("\nError from\n $path = ...(..., $name = $value, ...): $name > 0 required") + + """ str = modelPathAsString(modelPath::Union{Expr,Symbol,Nothing}) diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index 9841be8..bff1d54 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -499,7 +499,8 @@ function stateSelectionAndCodeGeneration(modStructure, Gexplicit, name, modelMod if logCalculations var = string(unknowns[v]) solutionString = string(solution) - return :(println("Calculating: ", $solutionString); $solution; println(" Result: ", $var, " = ", upreferred.($(solution.args[1])))) + #return :(println("Calculating: ", $solutionString); $solution; println(" Result: ", $var, " = ", upreferred.($(solution.args[1])))) + return :(println("Calculating: ", $solutionString); $solution; println(" Result: ", $var, " = ", $(solution.args[1]))) else return solution end @@ -836,13 +837,13 @@ appendSymbol(path::Nothing, name::Symbol) = name appendSymbol(path , name::Symbol) = :( $path.$name ) """ - modifiedModel = buildSubModels!(model, modelModule, FloatType, TimeType, buildDict::OrderedDict) + modifiedModel = buildSubModels!(model, modelModule, FloatType, TimeType, unitless, buildDict::OrderedDict) Traverse `model` and for every `` that is a `Model(..)` and has a key-value pair `:_buildFunction = ` and optionally `:_buildOption=`, call ``` -buildCode = (, modelModule, FloatType::Type, TimeType::Type, +buildCode = (, modelModule, FloatType::Type, TimeType::Type, unitless::Bool, buildDict::OrderedDict{String,Any}, modelPath::Union{Expr,Symbol,Nothing}, buildOption = ) @@ -853,6 +854,7 @@ The arguments of ``are: - `subModel`: The returned `buildCode` is merged to `submodel` - `FloatType`, `TimeType`: Types used when instantiating `SimulationModel{FloatType,TimeType}` +- `unitless`: Argument `unitless` of `@instantiateModel`. - `modelPath`: Path upto ``, such as: `:( a.b.c )`. - `buildDict`: Dictionary, that will be stored in the corresponding SimulationModel instance and that allows to store information about the build-process, @@ -861,25 +863,30 @@ The arguments of ``are: Note, keys `_buildFunction` and `_buildOption` are deleted from the corresponding ``. """ -function buildSubModels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, +function buildSubModels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, unitless::Bool, buildDict::OrderedDict{String,Any}; path::Union{Expr,Symbol,Nothing}=nothing) if haskey(model, :_buildFunction) - buildFunction = model[:_buildFunction] + _buildFunction = model[:_buildFunction] + if haskey(_buildFunction, :functionName) + buildFunction = _buildFunction[:functionName] + else + @error "Model $path has key :_buildFunction but its value has no key :functionName" + end delete!(model, :_buildFunction) quotedPath = Meta.quot(path) if haskey(model, :_buildOption) buildOption = model[:_buildOption] delete!(model, :_buildOption) - buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $buildDict, $quotedPath, buildOption=$buildOption)) ) + buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $buildDict, $quotedPath, buildOption=$buildOption)) ) else - buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $buildDict, $quotedPath))) + buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $buildDict, $quotedPath))) end return model | buildCode end for (key,value) in model if typeof(value) <: OrderedDict && haskey(value, :_class) && value[:_class] == :Model - model[key] = buildSubModels!(value, modelModule, FloatType, TimeType, buildDict; path=appendSymbol(path,key)) + model[key] = buildSubModels!(value, modelModule, FloatType, TimeType, unitless, buildDict; path=appendSymbol(path,key)) end end return model @@ -951,7 +958,8 @@ function instantiateModel(model; modelName="", modelModule=nothing, source=nothi TimeType = if FloatType <: Measurements.Measurement || FloatType <: MonteCarloMeasurements.AbstractParticles; baseType(FloatType) else FloatType end # baseType(..) is defined in CodeGeneration.jl - model = buildSubModels!(model, modelModule, FloatType, TimeType, buildDict) + model = deepcopy(model) + model = buildSubModels!(model, modelModule, FloatType, TimeType, unitless, buildDict) if logModel @showModel(model) @@ -1000,9 +1008,9 @@ function instantiateModel(model; modelName="", modelModule=nothing, source=nothi unique!(allVariables) if ! experimentalTranslation - unknowns = setdiff(allVariables, keys(modelStructure.parameters), keys(modelStructure.inputs), [:time, :instantiatedModel, :_leq_mode, :_x]) + unknowns = setdiff(allVariables, keys(modelStructure.parameters), keys(modelStructure.inputs), [:time, :instantiatedModel, :_leq_mode, :_x, :_path]) else - unknowns = setdiff(allVariables, keys(modelStructure.parameters), [:time, :instantiatedModel, :_leq_mode, :_x]) + unknowns = setdiff(allVariables, keys(modelStructure.parameters), [:time, :instantiatedModel, :_leq_mode, :_x, :_path]) end Avar, states, derivatives = setAvar(unknowns) vActive = [a == 0 for a in Avar] diff --git a/test/TestHeatTransfer2.jl b/test/TestHeatTransfer2.jl new file mode 100644 index 0000000..4fc50f2 --- /dev/null +++ b/test/TestHeatTransfer2.jl @@ -0,0 +1,28 @@ +module TestHeatTransfer2 + +using Modia +using Modia.Test +include("$(Modia.path)/models/HeatTransfer.jl") + +HeatedRod2 = Model( + fixedT = FixedTemperature | Map(T = 493.15u"K"), + fixedQflow = FixedHeatFlow, + rod = InsulatedRod2 | Map(L=1.0u"m", A=0.0004u"m^2", nT = 5), # 5 temperature nodes + equations = :[connect(fixedT.port, rod.port_a), + connect(rod.port_b , fixedQflow.port)] +) + +# Model with unit +heatedRod2a = @instantiateModel(HeatedRod2, logCode=false, unitless=true) +simulate!(heatedRod2a, stopTime = 1e5, log=true, merge=Map(rod = Map(nT=8)), logParameters=true, logEvaluatedParameters=true) +showInfo(heatedRod2a) + +@usingModiaPlot +plot(heatedRod2a, [("fixedT.port.T", "rod.T"), "rod.der(T)"], figure=1) + +# Model without unit +heatedRod2b = @instantiateModel(HeatedRod2, logCode=false, unitless=true) +simulate!(heatedRod2b, stopTime = 1e5, log=true, merge=Map(rod = Map(nT=100)), logParameters=true, logEvaluatedParameters=true) +showInfo(heatedRod2b) +plot(heatedRod2b, [("fixedT.port.T", "rod.T"), "rod.der(T)"], figure=2) +end \ No newline at end of file diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index a3e0962..4664fe6 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -55,8 +55,8 @@ simulate!(ssTest, stopTime=1.0, log=true, logStates=true, plot(ssTest, ("ss.x", "ss.u", "y", "ss.w"), figure=2) ``` """ -LinearStateSpace(; kwargs...) = Model(; _buildFunction = :(buildLinearStateSpace!), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated - _instantiateFunction = Par(functionName = :(instantiateLinearStateSpace!)), # Called once after new A,B,C values are merged +LinearStateSpace(; kwargs...) = Model(; _buildFunction = Par(functionName = :(buildLinearStateSpace!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated + _initSegmentFunction = Par(functionName = :(instantiateLinearStateSpace!)), # Called once after new A,B,C values are merged kwargs...) mutable struct LinearStateSpaceStruct{FloatType} @@ -121,7 +121,7 @@ mutable struct LinearStateSpaceBuild{FloatType} end -function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, +function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, unitless::Bool, buildDict::OrderedCollections.OrderedDict{String,Any}, path::Union{Expr,Symbol,Nothing}) # Called from @instantiatedModel, during instantiation of the model. diff --git a/test/TestMultiReturningFunction10.jl b/test/TestMultiReturningFunction10.jl index 6db0440..bd8b2c3 100644 --- a/test/TestMultiReturningFunction10.jl +++ b/test/TestMultiReturningFunction10.jl @@ -9,7 +9,7 @@ mutable struct MbsData w1::Float64 derw1::Float64 u1::Float64 - + phi2::Vector{Float64} w2::Vector{Float64} derw2::Vector{Float64} @@ -25,14 +25,14 @@ mutable struct MbsData end end -function myBuildFunction(model::AbstractDict, FloatType::Type, TimeType::Type, buildDict::AbstractDict, +function myBuildFunction(model::AbstractDict, FloatType::Type, TimeType::Type, unitless::Bool, buildDict::AbstractDict, modelPath::Union{Expr,Symbol,Nothing}; buildOption = "Default") modelPathAsString = if isnothing(modelPath); "" else string(modelPath) 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 nothing end -MyModelWithBuild(; kwargs...) = Model(; _buildFunction = :myBuildFunction, kwargs...) +MyModelWithBuild(; kwargs...) = Model(; _buildFunction = Par(functionName = :myBuildFunction), kwargs...) Mbs(; kwargs...) = Par(; _constructor = :(MbsData), _path = true, kwargs...) @@ -75,7 +75,7 @@ function getResiduals(mbs::MbsData) return mbs.residuals2 end -Pendulum = MyModelWithBuild(_buildOption = "MyBuildOption", +Pendulum = MyModelWithBuild(_buildOption = "MyBuildOption", phi1 = Var(init=pi/2), w1 = Var(init=0.0), qdd = Var(start=zeros(2)), @@ -83,8 +83,8 @@ Pendulum = MyModelWithBuild(_buildOption = "MyBuildOption", mbs1 = Var(hideResult=true), mbs2 = Var(hideResult=true), mbs3 = Var(hideResult=true), - mbs4 = Var(hideResult=true), - equations = :[ + mbs4 = Var(hideResult=true), + equations = :[ w1 = der(phi1) mbs1 = setStates(mbs,phi1,w1) mbs2 = setAccelerations1(mbs1,der(w1)) @@ -95,7 +95,7 @@ Pendulum = MyModelWithBuild(_buildOption = "MyBuildOption", tau1 = -0.1*w1 ] ) - + pendulum = @instantiateModel(Pendulum , unitless=true, log=false, logDetails=false, logCode=true, logStateSelection=false) simulate!(pendulum, stopTime = 2.0, log=true) showInfo(pendulum) diff --git a/test/include_all.jl b/test/include_all.jl index d617ebf..85fa9de 100644 --- a/test/include_all.jl +++ b/test/include_all.jl @@ -35,6 +35,7 @@ Test.@testset "Test model components" begin include("TestStateSpace.jl") include("TestParameter.jl") include("TestHeatTransfer.jl") + include("TestHeatTransfer2.jl") end From 797cfec9e28d63afbcbf1fc437a2422c2ef06514 Mon Sep 17 00:00:00 2001 From: Martin Otter Date: Mon, 29 May 2023 18:09:34 +0200 Subject: [PATCH 2/5] Further improvements of built-in components --- docs/src/index.md | 14 ++++-- models/HeatTransfer.jl | 4 +- models/HeatTransfer/InsulatedRod2.jl | 67 +++++++++++++--------------- src/CodeGeneration.jl | 9 ++++ src/EvaluateParameters.jl | 2 +- src/Modia.jl | 2 +- src/ModiaLang.jl | 45 +++++++++---------- test/TestHeatTransfer2.jl | 2 +- test/TestLinearSystems.jl | 51 ++++++++++----------- test/TestMultiReturningFunction10.jl | 11 +++-- 10 files changed, 107 insertions(+), 100 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index b0fd048..d4dbb8f 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -44,13 +44,19 @@ functionalities of these packages. ### Version 0.10.0 -- +- Initial support of segmented simulations where the number of states can change during simulation. + For examples, see `Modia/test/TestHeatTransfer2.jl` and models in directory `Modia3D/test/Segmented` + (of release 0.12.0 and later). The tutorial will be updated for this feature in an upcoming version. + -**Non-backwards** compatible changes (should usually not influende user models) +**Non-backwards** compatible changes + +These changes should usually not influence user models. - `_buildFunction = ` changed to `_buildFunction = Par(functionName = )` and - additional argument `unitless` added to ``. -- `_instantiateFunction = Par(..)` changed to `_initSegmentFunction = Par(..)` + changed argument list of ``. +- `_instantiateFunction = Par(..)` changed to `_initSegmentFunction = Par(functionName = )` + and changed argument list of ``. ### Version 0.9.4 diff --git a/models/HeatTransfer.jl b/models/HeatTransfer.jl index 323b69f..ca86e46 100644 --- a/models/HeatTransfer.jl +++ b/models/HeatTransfer.jl @@ -95,8 +95,8 @@ For more details see Appendix B1 of [DOI: 10.3390/electronics12030500](https://d - `der(T)': Vector of derivatives of `T`. """ InsulatedRod2 = Model(; - _buildFunction = Par(functionName = :(buildInsulatedRod2!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated - _initSegmentFunction = Par(functionName = :(initInsulatedRod2ForNewSegment!)), # Called once before initialization of a new simulation segment + _buildFunction = Par(functionName = :(build_InsulatedRod2!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated + _initSegmentFunction = Par(functionName = :(initSegment_InsulatedRod2!)), # Called once before initialization of a new simulation segment L = 1.0u"m", # Length of rod A = 0.0004u"m^2", # Rod area rho = 7500.0u"kg/m^3", # Density of rod material diff --git a/models/HeatTransfer/InsulatedRod2.jl b/models/HeatTransfer/InsulatedRod2.jl index d0d0701..c85a8a6 100644 --- a/models/HeatTransfer/InsulatedRod2.jl +++ b/models/HeatTransfer/InsulatedRod2.jl @@ -7,7 +7,6 @@ # Structure holding the internal memory of the insulated rod mutable struct InsulatedRodStruct{FloatType} # Parameters - path::String # path name of instance Ge::FloatType # = lambda*A/dx Ge2::FloatType # = 2*Ge k::FloatType # = Ge / (c*rho*A*dx) @@ -19,17 +18,35 @@ mutable struct InsulatedRodStruct{FloatType} # Start index of state and state derivative vectors T_startIndex::Int + + InsulatedRodStruct{FloatType}() where {FloatType} = new() +end + + +# Called from @instantiateModel(..) before getDerivatives!(..) is generated +function build_InsulatedRod2!(model::AbstractDict, FloatType, TimeType, unitless::Bool, ID, pathAST) + 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 + equations = :[ + # copy states into insRod.T and return insRod + insRod = openInsulatedRod!(instantiatedModel, $ID) + + # equations at the boundaries + port_a.Q_flow = getGe2(insRod, Val($unitless))*(port_a.T - getT1( insRod, Val($unitless))) + port_b.Q_flow = getGe2(insRod, Val($unitless))*(port_b.T - getTend(insRod, Val($unitless))) - InsulatedRodStruct{FloatType}(path::String) where {FloatType} = new(path,false) + # compute insRod.der_T and copy it into state derivatives + success = computeInsulatedRodDerivatives!(instantiatedModel, insRod, port_a.T, port_b.T) # instantiatedModel is provided in the generated code + ]) + + return (model, InsulatedRodStruct{FloatType}()) end # Called once before initialization of first simulation segment -function initInsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambda, c, T0, nT)::Nothing where {FloatType} - #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} - +function initFirstSegment_InsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambda, c, T0, nT)::Nothing where {FloatType} # Convert to SI units, strip units and check that values are positives - path = obj.path #= @show L @Modia.strippedPositive!(path, L) @@ -65,37 +82,13 @@ function initInsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambd end -# Called from @instantiateModel(..) before getDerivatives!(..) is generated -function buildInsulatedRod2!(model::AbstractDict, FloatType, TimeType, unitless::Bool, buildDict, path) - pathAsString = Modia.modelPathAsString(path) - extraModelCode = Model( # extra code to be merged with model - insRod = Var(hideResult=true), # InsulatedRodStruct instance (an equation to return this variable is generated by _buildFunction) - success = Var(hideResult=true), # Dummy return argument - equations = :[ - # copy states into insRod.T and return insRod - insRod = openInsulatedRod!(instantiatedModel, $pathAsString) - - # equations at the boundaries - port_a.Q_flow = getGe2(insRod, Val($unitless))*(port_a.T - getT1( insRod, Val($unitless))) - port_b.Q_flow = getGe2(insRod, Val($unitless))*(port_b.T - getTend(insRod, Val($unitless))) - - # compute insRod.der_T and copy it into state derivatives - success = computeInsulatedRodDerivatives!(instantiatedModel, insRod, port_a.T, port_b.T) # instantiatedModel is provided in the generated code - ]) - - # Store build info in buildDict - buildDict[pathAsString] = InsulatedRodStruct{FloatType}(pathAsString) - return extraModelCode -end - - # Called once before initialization of a new simulation segment -function initInsulatedRod2ForNewSegment!(instantiatedModel::SimulationModel{FloatType,TimeType}, - parameters::AbstractDict, path::String; log=false)::Nothing where {FloatType,TimeType} - obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path] - +function initSegment_InsulatedRod2!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String, ID, + parameters::AbstractDict; log=false)::Nothing where {FloatType,TimeType} + obj::InsulatedRodStruct{FloatType} = Modia.get_instantiatedSubmodel(instantiatedModel, ID) + if Modia.isFirstInitialOfAllSegments(instantiatedModel) - initInsulatedRod2!(obj; parameters...) + initFirstSegment_InsulatedRod2!(obj; parameters...) end # Define a vector of new state and state derivative variables @@ -105,8 +98,8 @@ end # Open an initialized InsulatedRod2 model and return a reference to it -function openInsulatedRod!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::InsulatedRodStruct{FloatType} where {FloatType,TimeType} - obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path] +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) return obj end diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 4ce0425..34c4dd3 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1666,6 +1666,15 @@ function addToResult!(m::SimulationModel{FloatType,TimeType}, x, time, w_invaria end +""" + obj = get_instantiatedSubmodel(instantiatedModel, ID) + +Return reference `obj` to an instantiated submodel struct, given `intantiatedModel` and the `ID` of the submodel. +""" +get_instantiatedSubmodel(instantiatedModel, ID) = instantiatedModel.buildDict[ID] + + + """ index = new_x_segmented_variable!( instantiatedModel::SimulationModel, diff --git a/src/EvaluateParameters.jl b/src/EvaluateParameters.jl index ce40d38..bba3f09 100644 --- a/src/EvaluateParameters.jl +++ b/src/EvaluateParameters.jl @@ -405,7 +405,7 @@ function propagateEvaluateAndInstantiate2!(m::SimulationModel{FloatType,TimeType if log println(" 13: +++ Instantiated $path: $instantiateFunction will be called to instantiate sub-model and define varying states\n\n") end - Core.eval(modelModule, :($instantiateFunction($m, $current, $path, log=$log))) + Core.eval(modelModule, :($instantiateFunction($m, $path, $path, $current, log=$log))) push!(m.instantiateFunctions, (instantiateFunction, current, path)) end return current diff --git a/src/Modia.jl b/src/Modia.jl index 83fd29a..996187b 100644 --- a/src/Modia.jl +++ b/src/Modia.jl @@ -10,7 +10,7 @@ module Modia const path = dirname(dirname(@__FILE__)) # Absolute path of package directory const Version = "0.10.0" -const Date = "2023-05-22" +const Date = "2023-05-29" const modelsPath = joinpath(Modia.path, "models") print(" \n\nWelcome to ") diff --git a/src/ModiaLang.jl b/src/ModiaLang.jl index bff1d54..39c7a1e 100644 --- a/src/ModiaLang.jl +++ b/src/ModiaLang.jl @@ -837,56 +837,55 @@ 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, unitless, buildDict::OrderedDict) -Traverse `model` and for every `` that is a `Model(..)` and has a key-value pair -`:_buildFunction = ` and optionally `:_buildOption=`, call +Traverse `model` and for every `` that is a `Model(..)` and has a key-value pair +`:_buildFunction = Par(functionName = )` and optionally `:_buildOption=`, call ``` -buildCode = (, modelModule, FloatType::Type, TimeType::Type, unitless::Bool, - buildDict::OrderedDict{String,Any}, - modelPath::Union{Expr,Symbol,Nothing}, - buildOption = ) +updatedSubmodel = (submodel, FloatType::Type, TimeType::Type, unitless::Bool, + ID, pathAST::Union{Expr,Symbol,Nothing}, buildOption = ) ``` -The`buildCode` is merged to the corresponding `` in the calling environment. +A new `updatedSubmodel` is generated from `submodel` merged with additional code and then returned. The arguments of ``are: -- `subModel`: The returned `buildCode` is merged to `submodel` +- `updatedSubmodel`: A potentially new reference to the updated `submodel` - `FloatType`, `TimeType`: Types used when instantiating `SimulationModel{FloatType,TimeType}` - `unitless`: Argument `unitless` of `@instantiateModel`. -- `modelPath`: Path upto ``, such as: `:( a.b.c )`. -- `buildDict`: Dictionary, that will be stored in the corresponding SimulationModel instance and - that allows to store information about the build-process, - typically with key `string(modelPath)` (if modelPath==Nothing, key="" is used). +- `ID`: Unique ID to identify the generated submodel (to be used in the code merged into the submodel) +- `pathAST`: Path upto `` 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` are deleted from the corresponding ``. +Note, keys `_buildFunction` and `_buildOption` have been deleted in the returned `updatedSubmodel`. """ -function buildSubModels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, unitless::Bool, - buildDict::OrderedDict{String,Any}; path::Union{Expr,Symbol,Nothing}=nothing) +function buildSubmodels!(model::AbstractDict, modelModule, FloatType::Type, TimeType::Type, unitless::Bool, + 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 $path has key :_buildFunction but its value has no key :functionName" + @error "Model $pathAST has key :_buildFunction but its value has no key :functionName" end delete!(model, :_buildFunction) - quotedPath = Meta.quot(path) + ID = modelPathAsString(pathAST) + quotedPathAST = Meta.quot(pathAST) if haskey(model, :_buildOption) buildOption = model[:_buildOption] delete!(model, :_buildOption) - buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $buildDict, $quotedPath, buildOption=$buildOption)) ) + (model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $ID, $quotedPathAST, buildOption=$buildOption)) ) else - buildCode = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $buildDict, $quotedPath))) + (model, instantiatedSubmodelStruct) = Core.eval(modelModule, :($buildFunction($model, $FloatType, $TimeType, $unitless, $ID, $quotedPathAST))) end - return model | buildCode + 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; path=appendSymbol(path,key)) + model[key] = buildSubmodels!(value, modelModule, FloatType, TimeType, unitless, buildDict; pathAST=appendSymbol(pathAST,key)) end end return model @@ -959,7 +958,7 @@ function instantiateModel(model; modelName="", modelModule=nothing, source=nothi 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, unitless, buildDict) if logModel @showModel(model) diff --git a/test/TestHeatTransfer2.jl b/test/TestHeatTransfer2.jl index 4fc50f2..f7ee487 100644 --- a/test/TestHeatTransfer2.jl +++ b/test/TestHeatTransfer2.jl @@ -13,7 +13,7 @@ HeatedRod2 = Model( ) # Model with unit -heatedRod2a = @instantiateModel(HeatedRod2, logCode=false, unitless=true) +heatedRod2a = @instantiateModel(HeatedRod2, logCode=false, unitless=false) simulate!(heatedRod2a, stopTime = 1e5, log=true, merge=Map(rod = Map(nT=8)), logParameters=true, logEvaluatedParameters=true) showInfo(heatedRod2a) diff --git a/test/TestLinearSystems.jl b/test/TestLinearSystems.jl index 4664fe6..ce68ce1 100644 --- a/test/TestLinearSystems.jl +++ b/test/TestLinearSystems.jl @@ -55,8 +55,8 @@ simulate!(ssTest, stopTime=1.0, log=true, logStates=true, plot(ssTest, ("ss.x", "ss.u", "y", "ss.w"), figure=2) ``` """ -LinearStateSpace(; kwargs...) = Model(; _buildFunction = Par(functionName = :(buildLinearStateSpace!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated - _initSegmentFunction = Par(functionName = :(instantiateLinearStateSpace!)), # Called once after new A,B,C values are merged +LinearStateSpace(; kwargs...) = Model(; _buildFunction = Par(functionName = :(build_LinearStateSpace!)), # Called once in @instantiateModel(..) before getDerivatives!(..) is generated + _initSegmentFunction = Par(functionName = :(initSegment_LinearStateSpace!)), # Called once before initialization of a new simulation segment kwargs...) mutable struct LinearStateSpaceStruct{FloatType} @@ -75,7 +75,7 @@ mutable struct LinearStateSpaceStruct{FloatType} function LinearStateSpaceStruct{FloatType}(; A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, W::AbstractMatrix = fill(FloatType(0),0,0), x_init::Union{AbstractVector,Nothing}=nothing, - u::AbstractVector, y::AbstractVector, # Code generated with buildLinearStateSpace! provides start values of u and y. + u::AbstractVector, y::AbstractVector, # Code generated with build_LinearStateSpace! provides start values of u and y. path::String, kwargs...) where {FloatType} #println("... 4: LinearStateSpaceStruct called for $path") if length(kwargs) > 0 @@ -121,12 +121,11 @@ mutable struct LinearStateSpaceBuild{FloatType} end -function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType::Type, unitless::Bool, - buildDict::OrderedCollections.OrderedDict{String,Any}, - path::Union{Expr,Symbol,Nothing}) +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. - pathAsString = Modia.modelPathAsString(path) - #println("... 1: buildLinearStateSpace! called for path = ", pathAsString) + pathAsString = Modia.modelPathAsString(pathAST) + #println("... 1: build_LinearStateSpace! called for path = ", pathAsString) # Determine nu,ny from model B = model[:B] @@ -137,29 +136,27 @@ function buildLinearStateSpace!(model::AbstractDict, FloatType::Type, TimeType:: y_zeros = zeros(FloatType,ny) # Define code to be generated - lsCode = Model(ls = Var(hideResult=true), - success = Var(hideResult=true), - u = Var(input = true, start = u_zeros), - y = Var(output = true, start = y_zeros), - equations = :[ - ls = openLinearStateSpace!(instantiatedModel, $pathAsString) - y = computeOutputs!(instantiatedModel, ls) - success = computeStateDerivatives!(instantiatedModel, ls, u)]) - - # Store build info in buildDict - buildDict[pathAsString] = LinearStateSpaceBuild{FloatType}(pathAsString, nu, ny) - return lsCode + model = model | Model(ls = Var(hideResult=true), + success = Var(hideResult=true), + u = Var(input = true, start = u_zeros), + y = Var(output = true, start = y_zeros), + equations = :[ + ls = openLinearStateSpace!(instantiatedModel, $ID) + y = computeOutputs!(instantiatedModel, ls) + success = computeStateDerivatives!(instantiatedModel, ls, u)]) + + return (model, LinearStateSpaceBuild{FloatType}(pathAsString, nu, ny)) end -function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationModel{FloatType,TimeType}, - model::AbstractDict, path::String; log=false)::Nothing where {FloatType,TimeType} +function initSegment_LinearStateSpace!(partiallyInstantiatedModel::SimulationModel{FloatType,TimeType}, path::String, ID, + parameters::AbstractDict; log=false)::Nothing where {FloatType,TimeType} # Called during evaluation of the parameters (before initialization) if log - println("instantiateLinearStateSpace! called for $path with model = $model") + println("initSegment_LinearStateSpace! called for $path with parameters = $parameters") end - lsBuild::LinearStateSpaceBuild{FloatType} = partiallyInstantiatedModel.buildDict[path] - ls = LinearStateSpaceStruct{FloatType}(; path, model...) + lsBuild::LinearStateSpaceBuild{FloatType} = Modia.get_instantiatedSubmodel(partiallyInstantiatedModel, ID) + ls = LinearStateSpaceStruct{FloatType}(; path, parameters...) ls.x_startIndex = Modia.new_x_segmented_variable!(partiallyInstantiatedModel, path*".x", path*".der(x)", ls.x_init) if length(ls.W) > 0 # w = W*x_init @@ -171,8 +168,8 @@ function instantiateLinearStateSpace!(partiallyInstantiatedModel::SimulationMode end -function openLinearStateSpace!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::LinearStateSpaceStruct{FloatType} where {FloatType,TimeType} - ls = instantiatedModel.buildDict[path].ls +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) if Modia.storeResults(instantiatedModel) && length(ls.W) > 0 # w = W*x diff --git a/test/TestMultiReturningFunction10.jl b/test/TestMultiReturningFunction10.jl index bd8b2c3..f58ffd4 100644 --- a/test/TestMultiReturningFunction10.jl +++ b/test/TestMultiReturningFunction10.jl @@ -25,11 +25,14 @@ mutable struct MbsData end end -function myBuildFunction(model::AbstractDict, FloatType::Type, TimeType::Type, unitless::Bool, buildDict::AbstractDict, - modelPath::Union{Expr,Symbol,Nothing}; buildOption = "Default") - modelPathAsString = if isnothing(modelPath); "" else string(modelPath) end +struct Dummy +end; + +function myBuildFunction(model::AbstractDict, FloatType::Type, TimeType::Type, unitless::Bool, + 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 nothing + return (model, Dummy()) end MyModelWithBuild(; kwargs...) = Model(; _buildFunction = Par(functionName = :myBuildFunction), kwargs...) From 1583771ac5c33bcd48587ae4b35ba997b871ee77 Mon Sep 17 00:00:00 2001 From: Martin Otter Date: Mon, 29 May 2023 18:30:16 +0200 Subject: [PATCH 3/5] Project/Manifest files updated --- Manifest.toml | 68 +++++++++++++++++++++++++-------------------------- Project.toml | 2 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 3207f6f..0c74f58 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -39,18 +39,18 @@ version = "0.1.29" [[deps.ArrayLayouts]] deps = ["FillArrays", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "4aff5fa660eb95c2e0deb6bcdabe4d9a96bc4667" +git-tree-sha1 = "4efc22e4c299e49995a38d503d9dbb0544a37838" uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" -version = "0.8.18" +version = "1.0.4" [[deps.Artifacts]] uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [[deps.BandedMatrices]] -deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "SnoopPrecompile", "SparseArrays"] -git-tree-sha1 = "6ef8fc1d77b60f41041d59ce61ef9eb41ed97a83" +deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "PrecompileTools", "SparseArrays"] +git-tree-sha1 = "b18febf0a34ba9192fdcd4fd2c57b535a48d3dd4" uuid = "aae01518-5342-5314-be14-df237901396f" -version = "0.17.18" +version = "0.17.24" [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" @@ -73,10 +73,10 @@ uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" version = "0.4.2" [[deps.CPUSummary]] -deps = ["CpuId", "IfElse", "Static"] -git-tree-sha1 = "2c144ddb46b552f72d7eafe7cc2f50746e41ea21" +deps = ["CpuId", "IfElse", "PrecompileTools", "Static"] +git-tree-sha1 = "89e0654ed8c7aebad6d5ad235d6242c2d737a928" uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" -version = "0.2.2" +version = "0.2.3" [[deps.Calculus]] deps = ["LinearAlgebra"] @@ -227,9 +227,9 @@ uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" [[deps.Distributions]] deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "Test"] -git-tree-sha1 = "5eeb2bd01e5065090ad591a205d8cad432ae6cb6" +git-tree-sha1 = "c72970914c8a21b36bbc244e9df0ed1834a0360b" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.93" +version = "0.25.95" [[deps.DocStringExtensions]] deps = ["LibGit2"] @@ -286,15 +286,15 @@ uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" [[deps.FillArrays]] deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] -git-tree-sha1 = "7072f1e3e5a8be51d525d64f63d3ec1287ff2790" +git-tree-sha1 = "ed569cb9e7e3590d5ba884da7edc50216aac5811" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "0.13.11" +version = "1.1.0" [[deps.FiniteDiff]] deps = ["ArrayInterface", "LinearAlgebra", "Requires", "Setfield", "SparseArrays", "StaticArrays"] -git-tree-sha1 = "6604e18a0220650dbbea7854938768f15955dd8e" +git-tree-sha1 = "abfd952bdf92f6d7195c45dc46d50043bd0d7dbe" uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.20.0" +version = "2.21.0" [[deps.Formatting]] deps = ["Printf"] @@ -325,9 +325,9 @@ uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" [[deps.GPUArraysCore]] deps = ["Adapt"] -git-tree-sha1 = "1cd7f0af1aa58abc02ea1d872953a97359cb87fa" +git-tree-sha1 = "2d6ca471a6c7b536127afccfa7564b5b39227fe0" uuid = "46192b85-c4d5-4398-a991-12ede77f4527" -version = "0.1.4" +version = "0.1.5" [[deps.GenericSchur]] deps = ["LinearAlgebra", "Printf"] @@ -630,10 +630,10 @@ uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.6.0" [[deps.OrdinaryDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "FunctionWrappersWrappers", "IfElse", "LineSearches", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "PrecompileTools", "Preferences", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLNLSolve", "SimpleNonlinearSolve", "SimpleUnPack", "SparseArrays", "SparseDiffTools", "StaticArrayInterface", "StaticArrays", "TruncatedStacktraces"] -git-tree-sha1 = "6ffebfa8971546bace3fc312f9a703795f79f5b9" +deps = ["ADTypes", "Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "FunctionWrappersWrappers", "IfElse", "LineSearches", "LinearAlgebra", "LinearSolve", "Logging", "LoopVectorization", "MacroTools", "MuladdMacro", "NLsolve", "NonlinearSolve", "Polyester", "PreallocationTools", "PrecompileTools", "Preferences", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLNLSolve", "SciMLOperators", "SimpleNonlinearSolve", "SimpleUnPack", "SparseArrays", "SparseDiffTools", "StaticArrayInterface", "StaticArrays", "TruncatedStacktraces"] +git-tree-sha1 = "7f758238ce4202ced5e08aa2903d19d3a4f0dd7c" uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -version = "6.51.2" +version = "6.52.0" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] @@ -791,9 +791,9 @@ version = "0.4.0+0" [[deps.RuntimeGeneratedFunctions]] deps = ["ExprTools", "SHA", "Serialization"] -git-tree-sha1 = "d7d9ebe28062161c1e314ed643097b0c6fe657d9" +git-tree-sha1 = "92fa1dd437690a5e2ac39c81b6353ef106affc0e" uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" -version = "0.5.7" +version = "0.5.8" [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" @@ -824,9 +824,9 @@ version = "0.1.6" [[deps.SciMLOperators]] deps = ["ArrayInterface", "DocStringExtensions", "Lazy", "LinearAlgebra", "Setfield", "SparseArrays", "StaticArraysCore", "Tricks"] -git-tree-sha1 = "90163ebc767cba9f126ea00aeef1d75ed74fe7b0" +git-tree-sha1 = "d9f0f6ce9bb899a657c4d218a846533910e9dea9" uuid = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" -version = "0.2.8" +version = "0.2.9" [[deps.SentinelArrays]] deps = ["Dates", "Random"] @@ -854,10 +854,10 @@ uuid = "3201582d-3078-4276-ba5d-0a1254d79d7c" version = "0.4.2" [[deps.SimpleNonlinearSolve]] -deps = ["ArrayInterface", "DiffEqBase", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "Reexport", "Requires", "SciMLBase", "SnoopPrecompile", "StaticArraysCore"] -git-tree-sha1 = "54c78ac3cc0343a16785adabe5bbf4063c737967" +deps = ["ArrayInterface", "DiffEqBase", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "PrecompileTools", "Reexport", "Requires", "SciMLBase", "StaticArraysCore"] +git-tree-sha1 = "7c55a3e65aad4ce6e610409cdd564b8d590b9726" uuid = "727e6d20-b764-4bd8-a329-72de5adea6c7" -version = "0.1.14" +version = "0.1.15" [[deps.SimpleTraits]] deps = ["InteractiveUtils", "MacroTools"] @@ -890,10 +890,10 @@ deps = ["LinearAlgebra", "Random"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [[deps.SparseDiffTools]] -deps = ["Adapt", "ArrayInterface", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays", "VertexSafeGraphs"] -git-tree-sha1 = "e19ac47477c9a8fcca06dab5e5471417d5d9d723" +deps = ["ADTypes", "Adapt", "ArrayInterface", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "Reexport", "Requires", "SciMLOperators", "SparseArrays", "StaticArrayInterface", "StaticArrays", "Tricks", "VertexSafeGraphs"] +git-tree-sha1 = "04f060e66a61a909ed59efd79f64943688d7568d" uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804" -version = "1.31.0" +version = "2.3.0" [[deps.Sparspak]] deps = ["Libdl", "LinearAlgebra", "Logging", "OffsetArrays", "Printf", "SparseArrays", "Test"] @@ -959,10 +959,10 @@ uuid = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f" version = "1.15.0" [[deps.StochasticDiffEq]] -deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "JumpProcesses", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] -git-tree-sha1 = "073da86200349ddf4ef8bc3e3f3acd62e1d554f7" +deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqNoiseProcess", "DocStringExtensions", "FillArrays", "FiniteDiff", "ForwardDiff", "JumpProcesses", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] +git-tree-sha1 = "619c846726548b7b2e8728b72f288acf10390121" uuid = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" -version = "6.60.0" +version = "6.61.0" [[deps.StrideArraysCore]] deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "SIMDTypes", "Static", "StaticArrayInterface", "ThreadingUtilities"] @@ -986,9 +986,9 @@ version = "5.10.1+0" [[deps.Sundials]] deps = ["CEnum", "DataStructures", "DiffEqBase", "Libdl", "LinearAlgebra", "Logging", "PrecompileTools", "Reexport", "SciMLBase", "SparseArrays", "Sundials_jll"] -git-tree-sha1 = "4289695031d663252f38fd114d3e0020d1461cee" +git-tree-sha1 = "a982ee85e1908d39f58d7fff670e60f991ca2ddb" uuid = "c3572dad-4567-51f8-b174-8c6c989267f4" -version = "4.18.0" +version = "4.19.0" [[deps.Sundials_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS_jll", "Pkg", "SuiteSparse_jll"] diff --git a/Project.toml b/Project.toml index 73b989d..414e417 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.10.0-dev" +version = "0.10.0" [deps] DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" From 689cea36f8f3844fadcc88e0895cb729f994473a Mon Sep 17 00:00:00 2001 From: Martin Otter Date: Mon, 29 May 2023 18:35:37 +0200 Subject: [PATCH 4/5] Use Julia 1.8.5 for action runs --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9ce7f5f..615f2e5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: version: - - '1.8.1' + - '1.8.5' os: - ubuntu-latest - windows-latest From 863b13d0b785ab5ff6069b0623b04c31abd4a9f6 Mon Sep 17 00:00:00 2001 From: Martin Otter Date: Mon, 29 May 2023 19:04:50 +0200 Subject: [PATCH 5/5] InitFullRestart for 2nd and further segment fixed --- src/CodeGeneration.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CodeGeneration.jl b/src/CodeGeneration.jl index 34c4dd3..566a528 100644 --- a/src/CodeGeneration.jl +++ b/src/CodeGeneration.jl @@ -1181,7 +1181,11 @@ function initFullRestart!(m::SimulationModel{FloatType,TimeType})::Nothing where # Evaluate instantiate functions for fc in m.instantiateFunctions logInstantiatedFunctionCalls = false - Core.eval(m.modelModule, :($(fc[1])($m, $(fc[2]), $(fc[3]), log=$logInstantiatedFunctionCalls))) + initSegment = fc[1] + path = fc[3] + ID = path + parameters = fc[2] + Core.eval(m.modelModule, :($initSegment($m, $path, $ID, $parameters, log=$logInstantiatedFunctionCalls))) end resizeLinearEquations!(m, m.evaluatedParameters, m.options.log)