Open mtiller-jh opened 1 year ago
@AayushSabharwal this seems like it was a SII thing. Can you check if this is fixed?
It's not an SII thing. The problem is that sampling f
(a LinearInterpolation
) with a unit throws an error:
using ModelingToolkit: t
time_points = [0, 0.5, 0.8, 100.0]
voltage_levels = [0, 0, 20, 20]
f = LinearInterpolation(voltage_levels, time_points)
f(t)
# works, traces symbolically
f(1u"s")
# errors
I meant the cleansyms one. That should be fixed?
Yep that's fixed
I think I'm getting essentially the same problem, MWE...
using ModelingToolkit
using ModelingToolkit: t, D
using DynamicQuantities
vars = @variables begin
ẋ(t), [unit=u"m/s"]
end
eqs = [
D(ẋ) ~ 1u"m/s^2"
]
ModelingToolkit.validate(eqs) #true
@mtkbuild sys = ODESystem(eqs, t, vars, []) #ERROR: DimensionError: 0 and 1.0 m s⁻² have incompatible dimensions
I would expect if ModelingToolkit.validate(eqs)
passes then the system should build.
That's https://github.com/SciML/ModelingToolkit.jl/issues/2340 which would take a bit more work. Unit literals actually have a lot more quirks to get them right and will take quite lot more work.
OK, so I need to do the following for now...
using ModelingToolkit
using ModelingToolkit: t, D
using DynamicQuantities
vars = @variables begin
ẋ(t), [unit=u"m/s"]
end
pars = @parameters begin
force=1, [unit=u"m*s^-2"]
end
eqs = [
D(ẋ) ~ force
]
@mtkbuild sys = ODESystem(eqs, t, vars, pars) # OK
OK, making progress. But, now how do I actually solve the problem?
julia> prob = ODEProblem(sys, [10], (0,1), [])
┌ Warning: in eq. #1right, in sum 10 - ẋ(t), units [1.0 , 1.0 m s⁻¹] do not match.
└ @ ModelingToolkit C:\Users\bradl\.julia\packages\ModelingToolkit\kByuD\src\systems\unit_check.jl:176
ERROR: ModelingToolkit.ValidationError("Some equations had invalid units. See warnings for details.")
And if I try with units I get...
julia> prob = ODEProblem(sys, [10u"m/s"], (0,1), [])
ERROR: DimensionError: 0 and 10.0 m s⁻¹ have incompatible dimensions
OK, I see, the unit literals issue pops up with initialization...
julia> initsys = ModelingToolkit.generate_initializesystem(sys; u0map=[ẋ=>10u"m/s"])
equations(initsys)
1-element Vector{Equation}:
0 ~ 10.0 m s⁻¹ - ẋ(t)
There are many other issues with unit literals that would not be documented yet. There's a fundamental issue with it so it's easy to construct such edge cases.
OK, making progress. But, now how do I actually solve the problem?
For now it's assumed that you build the numerical problem with just numbers. The numerical constructors cannot handle re-validating and converting. The validation is currently too early in the process and it's not reused in the later stages yet.
OK, I see now I was defining the problem incorrectly, I needed to use a map like...
prob = ODEProblem(sys, [sys.ẋ => 10], (0, 10))
That's #2340 which would take a bit more work. Unit literals actually have a lot more quirks to get them right and will take quite lot more work.
The unit is useful. I am currently trying the following solution
using ModelingToolkit: t, D # with DynamicQuantities Unit
step 1:construct a standard unit dictionary SI like the type class of Modelica (ctr+F to search the words: package SI)
SI = Dict(
"Length" => Dict("quantity"=>"Length", "unit"=>"m", "u"=>"u\"m\"",
"prefixes" => Dict("quantity"=>["final"], "unit"=>["final"], )),
"Area" => Dict("quantity"=>"Area", "unit"=>"m2", "u"=>"u\"m^2\"",
"prefixes" => Dict("quantity"=>["final"], "unit"=>["final"], ))
)
The type class of Modelica is similar with Julia Struct, I think, but the Metadata style in ModelingToolkit is also very good.
Step2: function u as following
u(u_name) = SI[u_name]["u"]
, then
u("Area")
returns the u\"m^2\"
which can be recognized by DynamicQuantities.jl
Step3: using as following
@mtkmodel VoltageSource begin
@extend i,v,p,n = onePort = OnePort()
@components begin
ramp = Ramp()
end
@constants begin
unit_balance = 1.0, [unit = u("ElectricPotential"), description = "Balance out the units of the equation"]
end
@equations begin
v ~ ramp.output.u * unit_balance # v is a ElectricPotential quantity
end
end
However, some models have many equations, many of which have the unitless variables from Blocks. It is very troublesome to balance the units, So I commented out the body of function check_units
, because the param checks can not be assigned during @mtkbuild sys = Model()
like ODESystem(eqs, t, checks=MT.CheckComponents)
In addition, standard unit must be used at present. In future, it would be considered that customizing units of different scales, such as nm for microscopic, like Unitful.preferunits(u"nm,s,A,K,cd,mg,mol"...), also like MTK docs say "In the future, the validation stage may be upgraded to support the insertion of conversion factors into the equations"
Unit is only auxiliary to modeling and solving, and could be improved in future. I am a new user of Julia and MTK, and what I said above may not be correct. Thanks a lot for your great work. @ChrisRackauckas @YingboMa
That was all pretty correct. Yeah we need to improve a few things. We don't have the modelica wildcard units, which seem to be under-defined, but the bigger difficulty is we will need to build a new unit system or modify DynamicQuantities.jl if we want to add that. So it'll take a bit to get this right.
This model has a legitimate issue which is that the voltage (which has units of
V
) is being assigned to a constant value. So let's start there:This leads to the predictable:
So far this makes sense and one fix would be to change the
TimeVaryingVoltage
model as follows:This would seem to give the system of equations the correct units. But this then leads to:
However, what I really want is to be able to use the function,
f
, being passed in as a@structural_parameters
. But that also leads to odd results. One might expect that changing5.0
in the original model tof(t)
should lead to the same units issue (sincef
is just a function with no particular units associated with it), but this leads to an entirely different error:The issue must be in
TimeVaryingVoltage
, but how is time coming into this?