3. Using dimensional angles
Say that we wish to track angles as a unit, rather than assume the SI convention that 1 rad = 1
. We can do this by creating a new struct to track dimensions:
using DynamicQuantities
struct AngleDimensions{R} <: AbstractDimensions{R}
length::R
mass::R
time::R
current::R
temperature::R
luminosity::R
amount::R
angle::R
end
Simply by inheriting from AbstractDimensions
, we get all the constructors and operations as defined on Dimensions
:
julia> x = Quantity(1.0, AngleDimensions(length=1, angle=-1))
1.0 m angle⁻¹
However, perhaps we want to set the default angle
dimension as rad
. We can do this by defining a method for dimension_name
:
import DynamicQuantities: DynamicQuantities as DQ
function DQ.dimension_name(::AngleDimensions, k::Symbol)
default_dimensions = (
length = "m",
mass = "kg",
time = "s",
current = "A",
temperature = "K",
luminosity = "cd",
amount = "mol",
angle = "rad",
)
return get(default_dimensions, k, string(k))
end
This gives us the following behavior:
julia> x = Quantity(1.0, AngleDimensions(length=1, angle=-1))
1.0 m rad⁻¹
Next, say that we are working with existing quantities defined using standard Dimensions
. We want to promote these to our new AngleDimensions
type.
For this, we define two functions: promote_rule
and a constructor for AngleDimensions
from regular Dimensions
:
function Base.promote_rule(::Type{AngleDimensions{R1}}, ::Type{Dimensions{R2}}) where {R1,R2}
return AngleDimensions{promote_type(R1, R2)}
end
function Base.convert(::Type{Quantity{T,AngleDimensions{R}}}, q::Quantity{<:Any,<:Dimensions}) where {T,Din,R}
val = ustrip(q)
d = dimension(q)
return Quantity(
T(val),
AngleDimensions{R}(;
d.length, d.mass, d.time, d.current, d.temperature, d.luminosity, d.amount, angle=zero(R)
)
)
end
This means that whenever a Quantity{<:Any,<:Dimensions}
interacts with a Quantity{<:Any,<:AngleDimensions}
, the result will be a Quantity{<:Any,<:AngleDimensions}
, and we will initialize the angle dimension to 0. (Code not given for SymbolicDimensions
; you will probably want to treat the angles in symbolic units explicitly, so that us"rad"
is correctly tracked.)
Let’s define a constant for rad
:
julia> const rad = Quantity(1.0, AngleDimensions(angle = 1))
1.0 rad
and use it in a calculation:
julia> x = 2rad
2.0 rad
julia> y = 10u"min"
600.0 s
julia> angular_velocity = x / y
0.0033333333333333335 s⁻¹ rad
which as we can see, automatically promotes to AngleDimensions
.
However, note the following: If existing code uses rad
as a unit without tracking
it with AngleDimensions
, you will need to explicitly add the missing dimensions. For this reason, if you decide to take this approach to tracking units, you probably want to use AngleDimensions
throughout your codebase, rather than mixing them.