Defining new equivalences

Each equivalence must be of a type that is a subtype of Equivalence. To define a new equivalence, one creates a new such type and extends the UnitfulEquivalences.edconvert function to enable conversion between the desired dimensions.

As an example, let us implement our own version of the MassEnergy() equivalence.

struct MyMassEnergy <: Equivalence end

For this equivalence, a singleton struct is sufficient. In general, Equivalence types may also have fields and/or type parameters. To enable our MassEnergy type to convert between Unitful.Mass (of dimension 𝐌) and Unitful.Energy (of dimension 𝐋^2*𝐌*𝐓^-2), we need to define two edconvert methods (one for the mass-to-energy and one for the energy-to-mass conversion). The edconvert function converts a quantity (its second argument) to an equivalent quantity of the dimension specified by its first argument (the ed in edconvert stands for “equivalent dimension”). The third argument is the MyMassEnergy equivalence.

using Unitful: 𝐋, 𝐌, 𝐓, Energy, Mass, c0

UnitfulEquivalences.edconvert(::typeof(𝐋^2*𝐌*𝐓^-2), x::Mass, ::MyMassEnergy) = x * c0^2
UnitfulEquivalences.edconvert(::typeof(𝐌), x::Energy, ::MyMassEnergy) = x / c0^2
Warning

This particular example implementation does not work correctly on 32-bit systems, since c0 is based on an Int and c0^2 therefore overflows on these systems ($299792458^2 > 2^{31}-1$).

Info

When defining edconvert methods for DimensionlessQuantity arguments, the equivalence will also work with plain numbers (like Float64s or Ints), even though those are not subtypes of DimensionlessQuantity. Furthermore, uconvert and ustrip convert affine quantities (like °C) to absolute quantities before calling edconvert, so edconvert only needs to work on ScalarQuantitys.

After defining the two edconvert methods, MyMassEnergy() can be used to convert between mass and energy:

julia> uconvert(u"J", 1u"kg", MyMassEnergy())
89875517873681764 J

An equivalence can have an arbitrary number of edconvert methods defined for it. For example, the Spectral equivalence can convert between energy, frequency, wavelength, and wavenumber. For each pair of these quantities, there is one pair of edconvert methods defined that handles the conversion between them.

Convenience functions

The definition of the edconvert methods above could be simplified in two ways:

  • The UnitfulEquivalences.dimtype function extracts the Dimensions type from a quantity type like Unitful.Length. It can be used to simplify the declaration of the first edconvert argument:

    using Unitful: Energy, Mass, c0
    using UnitfulEquivalences: dimtype
    
    UnitfulEquivalences.edconvert(::dimtype(Energy), x::Mass, ::MyMassEnergy) = x * c0^2
    UnitfulEquivalences.edconvert(::dimtype(Mass), x::Energy, ::MyMassEnergy) = x / c0^2
  • In many cases, including this one, equivalences are simple proportional or antiproportional relations where the quotient or the product of the two equivalent quantities is a constant value (like a physical constant). In these cases, the @eqrelation macro can be used to define both edconvert methods at once. In the case of the MyMassEnergy equivalence, it would be used as follows:

    using Unitful: Energy, Mass, c0
    
    @eqrelation MyMassEnergy Energy/Mass = c0^2

    This defines the two edconvert methods as shown above.

API

UnitfulEquivalences.dimtypeFunction
dimtype(x)

For a quantity type alias as created by Unitful.@dimension or Unitful.@derived_dimension (e.g., Unitful.Energy), return its Dimensions type. (not exported)

Example

julia> using UnitfulEquivalences: dimtype

julia> dimtype(Unitful.Length)
Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}
source
UnitfulEquivalences.edconvertFunction
edconvert(d::Dimensions, x::AbstractQuantity, e::Equivalence)

Convert x to the equivalent dimension d using the equivalence e. (not exported)

Example

julia> using UnitfulEquivalences: edconvert

julia> edconvert(dimension(u"J"), 1u"kg", MassEnergy()) # E = m*c^2
89875517873681764 kg m^2 s^-2
source
UnitfulEquivalences.@eqrelationMacro
@eqrelation Name a/b = c
@eqrelation Name a*b = c

Add a proportional or antiproportional relation between dimensions a and b to an existing equivalence type Name <: Equivalence. The dimensions a and b must be specified as quantity type aliases like Unitful.Energy.

Example

using Unitful: Energy, Mass, c0
struct MassEnergy <: Equivalence end
@eqrelation MassEnergy Energy/Mass = c0^2

In the rest frame of a particle, its energy is proportional to its mass. Defining the MassEnergy equivalence like above allows conversion between energies and masses via uconvert(massunit, energy, MassEnergy()) and uconvert(energyunit, massunit, MassEnergy()).

source