ModiaSim / TinyModia.jl

Deprecated package (use instead Modia.jl)
MIT License
20 stars 4 forks source link

support for parameter vectors in Model #4

Open dafred94 opened 3 years ago

dafred94 commented 3 years ago

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?

HildingElmqvist commented 3 years ago

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).

dafred94 commented 3 years ago

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` )

HildingElmqvist commented 3 years ago

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 .

dafred94 commented 3 years ago

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)
HildingElmqvist commented 3 years ago

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.