SciML / ModelingToolkit.jl

An acausal modeling framework for automatically parallelized scientific machine learning (SciML) in Julia. A computer algebra system for integrated symbolics for physics-informed machine learning and automated transformations of differential equations
https://mtk.sciml.ai/dev/
Other
1.43k stars 209 forks source link

Unitful/Units in Systems for model validation #1031

Closed anandijain closed 3 years ago

anandijain commented 3 years ago

I would like to provide units metadata for my odesystems and have MTK validate that the model's units all work out

ChrisRackauckas commented 3 years ago

Why not use the current units system?

anandijain commented 3 years ago

is MTK "aware" though? it might be good to get usage into a tutorial i believe units are in other modeling systems like modelica/simulink

anandijain commented 3 years ago

oh the docs are just not written https://mtk.sciml.ai/stable/basics/Validation/#Model-Validation-and-Units-1

ChrisRackauckas commented 3 years ago

@YingboMa should this be updated to use variable metadata?

https://github.com/SciML/ModelingToolkit.jl/blob/master/test/units.jl

I think once that's done, it's ready for docs.

lamorton commented 3 years ago

It looks like it needs a bit more work to finish validate. Here validate errors b/c instantiate calls vartype which has no methods, so that needs to be implemented. Also validate should not use try/catch, so that errors like this would propagate out.

using ModelingToolkit, Unitful,Symbolics
MT = ModelingToolkit
@parameters τ
@variables t E(t) P(t)
E = setmetadata(E, Symbolics.option_to_metadata_type(Val(:unit)), u"kJ")
P = setmetadata(P, Symbolics.option_to_metadata_type(Val(:unit)), u"MW")
τ = setmetadata(τ, Symbolics.option_to_metadata_type(Val(:unit)), u"ms")
t = setmetadata(t, Symbolics.option_to_metadata_type(Val(:unit)), u"ms")
D = Differential(t)

eqs = [D(P) ~ P-E/τ ]

sys = ODESystem(eqs)

MT.validate(sys)
MT.instantiate(P)
MT.vartype(P)
methods(MT.vartype)
ChrisRackauckas commented 3 years ago

It should be:

@parameters τ [unit=u"ms"]
@variables t [unit=u"ms"] E(t) [unit=u"kJ"] P(t) [unit=u"MW"]
D = Differential(t)

eqs = [D(P) ~ P-E/τ ]
sys = ODESystem(eqs)

and we should auto-validate inside of the system.

Also validate should not use try/catch, so that errors like this would propagate out.

Well we should catch them and interpret them, i.e. "units in equation X are invalid".

lamorton commented 3 years ago

and we should auto-validate inside of the system.

Yup.

Well we should catch them and interpret them, i.e. "units in equation X are invalid".

Right, I meant the blanket try/catch as part of the logic. (Is it possible to catch only certain types of errors in Julia? A quick look at the docs doesn't indicate that it is.)

[Edit: Looks like we could just catch all & rethrow everything else.]

lamorton commented 3 years ago

I need a way to tell if a symbolic expression can be evaluated to a numerical constant, during system construction. If we have dimensional quantities taken to a variable exponent, there's no way to assign a meaningful unit to the expression. OTOH, we can't just give up on having symbolic expressions for exponents of unitful quantities (eg, what if we're doing thermodynamics with γ=5/3 and we really want to put γ in the symbolic equation instead of 5/3 because it prints to nice LaTeX equations that way.

Edit: I think it's not possible, b/c we have to wait until problem-construction time to get the parameter values. Edit2: If we just leave the exponents symbolic & use isequal, it'll work as long as we're not trying to test whether a constant exponent on one side is equal to a symbolic exponent on the other. That probably covers any realistic use.

ChrisRackauckas commented 3 years ago

Yeah, I don't think that situation would show up? If we error there then maybe we will find who hits it haha.

lamorton commented 3 years ago

We can close this.