Skip to content

Data units

XTensor's physical-unit annotation on a tensor's values — assigning/reading .units, converting with to_units, and the pint.Quantity-shaped simplification/conversion helpers. See also the Data units guide, and Proposal 0003 / Proposal 0006.

Bases: ExtendedTensor

A tensor with named dimensions and, optionally, per-dimension coordinate labels -- an xarray-like DataArray over a live torch.Tensor.

  • Dimensions are named through names (self-managed in _axis_names, independent of PyTorch's experimental builtin named-tensor feature, so the class works even where that API has been removed).
  • Coordinates label the positions along a named dimension. They live in coords -- a mapping dim name -> labels -- keyed by dimension name, so they follow their dimension through reshaping/reordering with no positional bookkeeping. A labelled dimension must be named.
  • Axis descriptors may enrich a name with extra fields -- any custom key you like (type is the OME-NGFF convention shown in examples; orientation is the one field with built-in behaviour) -- passed as a dict in place of a bare name ({"name": "x", "type": "space"}). names stays the ergonomic view (bare names); axes returns the full descriptors. The extra fields live in _axis_meta, keyed by dimension name, so they follow the dimension like coordinates do.

Select by label with sel, by integer position with isel, or reach a single label by attribute (x.red).

Attributes

units property writable

units: Optional[str]

The physical unit of the tensor's values (the data unit), or None. Assigning annotates (it never changes the data); to_units converts. Under unit_backend="pint" the unit is validated and normalised on set; with the default unit_backend=None it is an opaque string that is simply carried through operations.

dimensionality property

dimensionality: str

The physical dimensionality of this tensor's unit (e.g. "[length]", "[mass] * [length] ** 2 / [time] ** 3"), or "" if there's no unit at all. An explicitly dimensionless unit (.units == "") has its own non-empty dimensionality string ("dimensionless") -- see .dimensionless/.unitless for the boolean questions. Requires unit_backend="pint".

dimensionless property

dimensionless: bool

Whether this tensor's unit is dimensionless (or unset). With no unit backend this is not bool(self.units) -- True for no unit or an explicitly empty one, False for any opaque unit string, since there's no dimensionality system to consult otherwise.

unitless property

unitless: bool

Whether this tensor has literally no unit at all -- a stricter check than dimensionless. Angle units are the case that splits them: xtensor(x, units="rad").dimensionless is True (an angle is dimensionally trivial) but unitless is False (it still names a unit). With no backend the two coincide exactly (not bool(self.units) for both), since there's no dimensionality system to tell them apart. Requires unit_backend="pint" for the two to actually differ.

magnitude property

magnitude: Self

The tensor with its data unit dropped -- the bare values, still an XTensor with the same names and coordinates. A view (no data copy); the original is unchanged. x.magnitude.units is always None. (To get a plain torch.Tensor, use x.as_subclass(torch.Tensor).)

This drops the unit annotation -- it is not the mathematical modulus. For the absolute value of a (possibly complex) tensor, use x.abs() / torch.abs(x).

Methods:

is_compatible_with

is_compatible_with(unit: str) -> bool

Whether this tensor's unit shares a dimensionality with unit (so to_units(unit) would succeed). False if this tensor has no unit. Requires unit_backend="pint".

to_units

to_units(unit: str) -> Self

Convert the data to unit, rescaling the values by the conversion factor (requires a unit already set and unit_backend="pint").

to_units_

to_units_(unit: str) -> Self

Convert to unit in place -- rescales the data and updates the unit annotation on self, returning self. Same restrictions as any other in-place op (mul_, add_, ...): raises on a leaf tensor that requires grad, and raises if the scale factor can't be applied without changing dtype. Requires a unit already set and unit_backend="pint".

m_as

m_as(unit: str) -> Self

Convert to unit and drop the annotation in one step -- sugar for x.to_units(unit).magnitude. Still an XTensor (see magnitude's own note on getting a plain torch.Tensor).

to_base_units

to_base_units() -> Self

Convert to the backend's base units (SI base units under pint). Requires a unit already set and unit_backend="pint".

to_base_units_

to_base_units_() -> Self

In-place variant of to_base_units.

to_reduced_units

to_reduced_units() -> Self

Convert to the backend's reduced (simplified) form of this unit. Requires a unit already set and unit_backend="pint".

to_reduced_units_

to_reduced_units_() -> Self

In-place variant of to_reduced_units.

to_compact

to_compact() -> Self

Convert to the unit these values read most compactly in -- the prefix that keeps them near 1 (200e-9 s becomes 200 ns), picked from the largest magnitude present. Requires a unit already set and unit_backend="pint". Unlike the other three simplifications, this one has to look at the data itself (not just the unit), which costs an extra full pass over the tensor -- worth knowing before calling it in a hot loop over a large tensor.

to_compact_

to_compact_() -> Self

In-place variant of to_compact.

to_preferred

to_preferred(preferred_units: Optional[List[str]] = None) -> Self

Convert to whichever unit the backend's preferred-units logic picks. preferred_units is a list of unit strings to guide it; omit it to use the backend registry's own default, which raises if none is configured. Requires a unit already set and unit_backend="pint".

force.to_preferred(["N"])          # 5000 g·mm/s² -> 0.005 N

to_preferred_

to_preferred_(preferred_units: Optional[List[str]] = None) -> Self

In-place variant of to_preferred.