ModiaSim/TinyModia.jl

support for parameter vectors in Model

Opened this issue · 5 comments

I created a Model that starts like this:

SingleTrackModel = Model(
    inputs   = :[delta,T_F,T_R],
    m = 1450,
    I_z = 1.0,
    l_F = 1.1,
    l_R = 1.59,
    h = 0.4,
    I_w = [1.8, 1.8],
    ...

Now in the equations section, I cannot access elements of parameters I_w using I_w[ind...]. A tested workaround I found is to use getindex(I_w, ind...) instead. However, neither does I_w show up in field parametersAndConstantVariables of the instantiated model, nor can I spot its contents in the field p.

However I would like to alter p after model instantiation (machine learning purposes).

Is there any supported and intended way to use and alter parameters in arrays?

It would have been better if you would have provided a complete example illustrating the problem. I successfully tested the following model in my development version:

using TinyModia
using ModiaPlot

SingleTrackModel = Model(
#    inputs   = :[delta,T_F,T_R],
    m = 1450,
    I_z = 1.0,
    l_F = 1.1,
    l_R = 1.59,
    h = 0.4,
    I_w = [1.8, 2.8],
    equations = :[
        I_w_2 = I_w[2...]
    ]
)

model = @instantiateModel(SingleTrackModel, log=true, logCode=true)
simulate!(model)
plot(model, "I_w_2")

So I might have misunderstood you. BTW, why do you want to use: I_w[ind...]

It should be possible to use parameter arrays and also change them in the simulate! call without redoing the symbolic transformation (under development, coming to main soon).

So I created a minimal but complete demonstration:

using TinyModia


function simandprint!(model)
	simulate!(model)

	println("
	m = $(model.p[1])
		x starts at $(get_result(model, "x")[1]) and ends at $(get_result(model, "x")[end])
	")
end


MinimalModel = Model(
	m = 2.0,
	pv = [3.0, 5.0],

	init = Map(x=2.0),

	equations = :[
		#der(x) = m*p[1]*p[2] # THIS LINE does not work
		der(x) = m*getindex(pv, 1)*getindex(pv, 2) # I have to use getindex() instead
	]
)


model = @instantiateModel(MinimalModel)

println("model.p: $(model.p)")
println("model.paramatersAndConstantVariables: $(model.parametersAndConstantVariables)")

simandprint!(model)

# manual altering of a scalar parameter works BUT there is no way to change pv from here!
model.p[1] = 4.0

simandprint!(model)

I marked the relevant bits I was talking about using comments.
If I execute this, I cannot see pv in the model parameters (which I am printing).
(I should mention that I am on [0169e107] TinyModia v0.7.1-dev `dev/TinyModia` )

I suppose yo meant:
der(x) = m*pv[1]*pv[2] instead of
der(x) = m*p[1]*p[2]
and
model.p[1].pv[1] = 4.0
instead of
model.p[1] = 4.0

model.p is the root of the parameters. We are supporting changing (merging) parameters in the simulate! call .

You are right about your first remark (where I mixed up p and pv), this was a remainder of an earlier refactoring.
However, if I try to uncomment
#der(x) = m*pv[1]*pv[2] # THIS LINE does not work,
I am getting the error:

AssertionError: Equation not solved for der(x): der(x) = m * pv[1] * pv[2]
(::TinyModia.var"#getSolvedEquationAST#65"{Bool,Array{Any,1},Array{Any,1}})(::Int64, ::Int64) at TinyModia.jl:460
addSolvedEquations!(::ModiaBase.EquationGraph, ::Array{Int64,1}, ::Array{Int64,1}) at StateSelection.jl:858
getSortedAndSolvedAST(::Array{Array{Int64,1},1}, ::Array{Array{Int64,1},1}, ::Array{Int64,1}, ::Array{Int64,1}, ::Array{Int64,1}, ::ModiaBase.StateSelectionFunctions; log::Bool, logDetails::Bool, logStates::Bool, modelName::String, unitless::Bool, defaultParameterAndStartValues::Nothing) at StateSelection.jl:1247
getSortedAndSolvedAST at StateSelection.jl:1197 [inlined]
stateSelectionAndCodeGeneration(::Tuple{Array{Any,1},Array{Any,1},Array{Array{Int64,1},1},Array{Int64,1},Array{Int64,1},Array{Int64,1},Array{Array{Int64,1},1},OrderedCollections.OrderedDict{Any,Any}}, ::String, ::Module, ::Type{T} where T, ::OrderedCollections.OrderedDict{Any,Any}, ::OrderedCollections.OrderedDict{Any,Any}, ::Array{Int64,1}, ::Array{Int64,1}, ::Array{Union{Expr, Symbol},1}; unitless::Bool, logStateSelection::Bool, logCode::Bool, logExecution::Bool, logTiming::Bool) at TinyModia.jl:588
(::TinyModia.var"#stateSelectionAndCodeGeneration##kw")(::NamedTuple{(:unitless, :logStateSelection, :logCode, :logExecution, :logTiming),NTuple{5,Bool}}, ::typeof(TinyModia.stateSelectionAndCodeGeneration), ::Tuple{Array{Any,1},Array{Any,1},Array{Array{Int64,1},1},Array{Int64,1},Array{Int64,1},Array{Int64,1},Array{Array{Int64,1},1},OrderedCollections.OrderedDict{Any,Any}}, ::String, ::Module, ::Type{T} where T, ::OrderedCollections.OrderedDict{Any,Any}, ::OrderedCollections.OrderedDict{Any,Any}, ::Array{Int64,1}, ::Array{Int64,1}, ::Array{Union{Expr, Symbol},1}) at TinyModia.jl:455
instantiateModel(::NamedTuple{(:m, :pv, :init, :equations),Tuple{Float64,Array{Float64,1},NamedTuple{(:x,),Tuple{Float64}},Expr}}; modelName::String, modelModule::Module, FloatType::Type{T} where T, aliasReduction::Bool, unitless::Bool, log::Bool, logModel::Bool, logDetails::Bool, logStateSelection::Bool, logCode::Bool, logExecution::Bool, logTiming::Bool) at TinyModia.jl:791
(::TinyModia.var"#instantiateModel##kw")(::NamedTuple{(:modelName, :modelModule),Tuple{String,Module}}, ::typeof(instantiateModel), ::NamedTuple{(:m, :pv, :init, :equations),Tuple{Float64,Array{Float64,1},NamedTuple{(:x,),Tuple{Float64}},Expr}}) at TinyModia.jl:711
top-level scope at demo.jl:33

Furthermore, model.p is reported to be an Array{Float64,1} which does not have a field named pv so I do not understand that second remark of yours.

Also, line model.p[1] = 4.0 does exactly what I want: alter the behaviour of model.getDerivatives!.
I am interested in getting model.getDerivatives! to behave differently so that I can

  1. instantiate a model
  2. set a model parameter (possibly located in an array) to a desired value
  3. solve the model using an arbitrary code (in my case solve from DifferentialEquations.jl)
  4. repeat 2. and 3. until the model does what I want it to

I'm appending a more relevant demonstration below:

using TinyModia


function simandprint!(model)
	simulate!(model)

	println("
	m = $(model.p[1])
		x starts at $(get_result(model, "x")[1]) and ends at $(get_result(model, "x")[end])
	")
end


function print_derivatives!(derx, x0, model)
	model.getDerivatives!(derx, x0, model, t0)
	println("m = $(model.p[1]) => dx = $(derx)")
end


MinimalModel = Model(
	m = 2.0,
	pv = [3.0, 5.0],

	init = Map(x=2.0),

	equations = :[
		#der(x) = m*pv[1]*pv[2] # THIS LINE does not work
		der(x) = m*getindex(pv, 1)*getindex(pv, 2) # I have to use getindex() instead
	]
)


model = @instantiateModel(MinimalModel)

println("model.p: $(model.p)")
println("model.paramatersAndConstantVariables: $(model.parametersAndConstantVariables)")

derx = zeros(1)
x0 = similar(derx)
t0 = 0.0

print_derivatives!(derx, x0, model)

#simandprint!(model)

# manual altering of a scalar parameter works BUT there is no way to change pv from here!
model.p[1] = 4.0

print_derivatives!(derx, x0, model)

#simandprint!(model)

You are right. I recently changed how parameters are passed. I tested in the branch "development". We want to make some more updates before merging to main. You might want to use development branch in the mean time.

Support for indexing was added in ModiaBase 11 days ago, so you might want to update.

Note that all TinyModia models can not be simulated directly with DifferentialEquations. The simulate! function of TinyModia is needed. Note that the workflow you indicated is now supported by an additional parameter merge in simulate!. It takes a nested Map modification for changing parameters.