New State & Parameter Vector Types
I’m hoping for others’ thoughts on this idea, including suggestions, alternatives, rotten fruit, etc. All input is welcome.
The “Problem”
Users have tried to add unit handling to their numerical integration functions. It’s usually a bit tricky. I haven’t seen a perfect solution yet.
Motivation
Many users describe physical systems with ModelingToolkit
or self-written ODEFunction
s. Some try to add unit handling, and initialize the dynamics with Unitful
quantities; at this point, they usually see some error. Several Discourse posts and GitHub issues have been created for this over the years. including the two linked below.
- DifferentialEquations.jl and systems with heterogenous units - #4 by ChrisRackauckas
- https://github.com/SciML/DifferentialEquations.jl/issues/352
There are a few issues with Unitful
quantities in ODEFunction
s today. Some math operators aren’t defined for Unitful.Unitlike
or similar types. As an anecdotal example, I have encountered an error like “no method defined for one(::Unitlike)
”. Generally, math with Unitful
quantities is very good. That’s a testament to the Unitful
developers, and Julia’s composability. Still, I know there’s lots of numerics magic going on in numerical integrators these days, so defining every possible required method for Unitful
types seems like a game of whack-a-mole.
Current Solutions
I’ve seen the following solutions so far.
Stripping Units
If we strip units before integrating, then all’s fine! This can be a bit clunky, though.
Defining all Methods for Unitful
Types
We could play that game of whack-a-mole, and define missing methods for Unitful
types as we find them. That’s all fine, and Unitful
vectors may even work with DifferentialEquations
out of the box today (they did a few months ago). Still, then you run into an issue where your state vector has non-concrete eltype
s.
If you pass a ComponentArray
or a LabelledArray
with Unitful
element types, then you could make sure the formal eltype
is Union{<:Unitful.LengthUnit, <:Unitful.VelocityUnit}
(as an example for a system with position and velocity states), but this is still less efficient than simply passing a Vector{Float64}
or similar.
Proposed Solution
What if we parameterized our state vectors and parameter vectors by their units. I’ve been using this for some time with GeneralAstrodynamics
. The relevant source code is here. Right now, that functionality is pulling a lot of code from LabelledArrays
, hence the ParameterizedLabelledArrays
filename linked there.
As an example, we could define the following types.
"""
A vector with physical elements (aka `Unitful`)
"""
abstract type PhysicalVector{F, MU, LU, TU, AU,L} <: AbstractVector{F} end
"""
A representation for all state vectors for physical systems.
The parameters are...
- F => Floating-point type
- MU => Mass unit
- LU => Length unit
- TU => Time unit
- AU => Angular unit
- L => Labels
"""
abstract type StateVector{F, MU, LU, TU, AU,L} <: PhysicalVector{F, MU, LU, TU, AU,L} end
"""
A representation for all parameter vectors for physical systems.
The parameters are...
- F => Floating-point type
- MU => Mass unit
- LU => Length unit
- TU => Time unit
- AU => Angular unit
- L => Labels
"""
abstract type ParameterVector{F, MU, LU, TU, AU,L} <: PhysicalVector{F, MU, LU, TU, AU,L} end
Then, we could define a CartesianState
like so…
struct CartesianState{F, MU, LU, TU, AU} <: StateVector{F, MU, LU, TU, AU,(x = 1, y = 2, z = 3, ẋ = 4, ẏ = 5, ż = 6, r = 1:3, v = 4:6)}
data::MVector{6,F}
end
And we could dispatch on functions like…
Base.@pure lengthunit(::CartesianState{F,MU,LU}) = LU
position(state::CartesianState) = state[1:3] * LU
Conclusion
Anyone have any thoughts on this? I think the struct definition is rough, but I do think there’s promise in parameterizing our state and parameter vectors by Unitful
units. Maybe instead of carrying around units for all dimensions (like in the MU, LU, TU, AU
above), we have a NamedTuple
struct parameter which tracks units in the same way that LabelledArrays
(and the copycat examples above) track labels.