How to convert between units

How to convert between units#

unxt offers three levels of conversion, and which one you want depends on what you are holding and what you want back.

You have

You want back

Use

a Quantity

a Quantity in new units

uconvert

a Quantity

the bare array in new units

ustrip

a raw value

a raw value in new units

uconvert_value

Each has both a function form and, where it applies, a method form. See About unxtโ€™s API conventions for why both exist.

>>> import unxt as u
>>> q = u.Q(5, "m")

Convert a quantity#

To keep the units attached, use uconvert. If you prefer an object-oriented style, call the method:

>>> q.uconvert("cm")
Quantity(Array(500., dtype=float32, ...), unit='cm')

To write it functionally โ€” operator first, operand last โ€” call the function:

>>> u.uconvert("cm", q)
Quantity(Array(500., dtype=float32, ...), unit='cm')

If you are porting code from astropy, the .to method is available and does the same thing:

>>> q.to("cm")
Quantity(Array(500., dtype=float32, ...), unit='cm')

Converting between incompatible dimensions raises:

>>> try: q.uconvert("s")
... except Exception as e: print(e)
'm' (length) and 's' (time) are not convertible

Strip the units off#

To drop out of unxt and back into plain JAX โ€” at an I/O boundary, or before handing an array to a library that does not understand quantities โ€” use ustrip. It converts and unwraps in one step, so the unit you name is the unit the numbers are in:

>>> u.ustrip("cm", q)
Array(500., dtype=float32, ...)

or as a method:

>>> q.ustrip("cm")
Array(500., dtype=float32, ...)

The astropy spelling .to_value also works:

>>> q.to_value("cm")
Array(500., dtype=float32, ...)

ustrip is also how you hand a quantity to code that does not understand units at all. A dimensionful Quantity refuses to become a bare array on its own โ€” np.asarray(q) raises rather than guess which unit you meant โ€” so name the unit and the refusal goes away:

>>> import numpy as np
>>> np.asarray(u.ustrip("cm", q))
array(500., dtype=float32)

See The sharp bits for why it refuses.

If your input may be either a quantity or a bare array โ€” a common signature in library code โ€” pass the AllowValue flag. A bare array is then taken to be already in the output units and passed through untouched, instead of raising:

>>> u.ustrip(u.quantity.AllowValue, "cm", 500)
500

Convert raw values#

When you never wanted the wrapper in the first place โ€” inside a jitted kernel, or converting a large batch โ€” uconvert_value takes from and to units explicitly and works on raw numbers:

>>> u.uconvert_value("km", "m", 1000)
1.0

>>> import jax.numpy as jnp
>>> u.uconvert_value("km", "m", jnp.array([1000, 2000, 5000]))
Array([1., 2., 5.], dtype=float32, ...)

Unit objects work in place of strings:

>>> u.uconvert_value(u.unit("km"), u.unit("m"), 5000)
5.0

Reach for it when you are performing batch conversions, working inside jit, vmap or grad, or want to avoid constructing Quantity objects on a hot path. uconvert delegates to it internally for the numerical step.

For convenience the same function also accepts a Quantity, in which case it just calls uconvert โ€” so you can migrate a call site to the lower-level function without first rewriting its inputs:

>>> u.uconvert_value("km", "m", q)
Quantity(Array(0.005, dtype=float32, ...), unit='km')

Inside a jitted function it composes as you would expect:

>>> import jax
>>> @jax.jit
... def batch_convert_to_km(values_in_m):
...     return u.uconvert_value("km", "m", values_in_m)

>>> batch_convert_to_km(jnp.array([1000., 5000., 10000.]))
Array([ 1.,  5., 10.], dtype=float32)

See also#