Skip to main content

Nutils Units

The nutils.units module provides a way to track dimensions of numerical objects and their change as the objects pass through functions. Its purposes are twofold:

  1. Numerical type checking, safeguarding against such mistakes as adding two objects of different dimensions together.
  2. Unit consistency, ensuring that different metric systems can coexist without crashing into Mars.

Units offers three API levels: core, metric and typing, with each building on top of the former.

Core

The core API offers the Monomial class, which wraps an object to assign it physical dimensions. A dimension is identified by a string, such as "L" for length. By wrapping the unit float we define the reference length for our calculations to be one meter.

>>> from nutils.units.core import Monomial
>>> meter = Monomial(1., "L")

Once the initial unit is seeded, we can build on it to define derived units:

>>> inch = meter * 0.0254

This demonstrates that Monomial objects support numerical manipulation such as multiplication. These manipulations extend to (supported) external packages such as numpy:

>>> import numpy as np
>>> v1 = np.array([1, -2]) * meter
>>> v2 = np.array([3, 1]) * inch
>>> array = np.stack([v1, v2])
>>> np.linalg.det(array)
np.float64(0.17779999999999999)[L2]

The [L2] in the string representation indicates that the result has dimension length squared, i.e. area. The value before it is the representation of the wrapped object, but its value is shielded by the wrapper. The wrapper falls away when an operation yields a dimensionless result, for instance by dividing out a unit:

>>> array / meter
array([[ 1.    , -2.    ],
       [ 0.0762,  0.0254]])

Crucially, dimensionless results do not depend on the definition of our reference lengths, as any scaling cancels out by definition. We could have defined our meter to be Monomial(np.pi, "L") instead and still obtained the same result up to rounding errors. The numerical value of the reference length is merely a conduit for the internal manipulations.

Metric

The metric API adds support for units via the parse function. This returns a UMonomial object that has access to a predefined set of units, using the SI base units as internal reference measures.

>>> from nutils.units.metric import parse
>>> length = parse('2cm')
>>> width = parse('3.5in')
>>> force = parse('5N')

We can then manipulate the UMonomial objects as before.

>>> area = length * width
>>> pressure = force / area
>>> pressure / 'kPa'
2.8121484814398205

Note that in dividing out the unit we omitted parse, which is a convenience shorthand for this precise situation. For added convenience, the UMonomial class also supports direct string formatting of the wrapped value.

>>> f'pressure: {pressure:.1kPa}'
'pressure: 2.8kPa'

The units registry is an append-only state machine that is part of the metric module. Additional units can be added if necessary via the units.register function.

>>> from nutils.units.metric import units
>>> units.register("lbf", parse("4.448222N"), prefix="")
>>> units.register("psi", parse("lbf/in2"), prefix="")
>>> f'pressure: {pressure:.1psi}'
'pressure: 0.4psi'

Typing

The typing API adds specific types for scalar quantities.

>>> from nutils.units.typing import Length, Time, Velocity
>>> Velocity('.4km/h')
Quantity[L/T](.4km/h)

The Quantity types function similarly to parse, with two differences: 1. the object reduces back to its original string argument, with potential uses for object introspection, and 2. it protects against using wrong units.

>>> Velocity('.4km/g')
Traceback (most recent call last):
    ...
nutils.units.error.DimensionError: cannot parse .4km/g as L/T

Derived quantities can be formed by operating directly on the types:

>>> Velocity == Length / Time
True

The quantity types can be used as function annotations for general readability a for the potential aid external introspection tools.

>>> def distance(velocity: Velocity, time: Time):
...     return velocity * time

Note that the return value of this function is not a Length but a general UMonomial, as the result of a numerical operation does not have an inherent unit.

Release files for nutils-units 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nutils-units 0.2.1
File Size Uploaded
nutils_units-0.2.1.tar.gz 15.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nutils-units 0.2.1
File Interpreter ABI Platform
nutils_units-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 30.3 kB

Release files / nutils_units-0.2.1.tar.gz

Download URL nutils_units-0.2.1.tar.gz
Size 15.0 kB
Tags Source
SHA-256 checksum
How to use checksums
5063d27d5c6a290b500bef0e3904772f421100404dd0d178f72349e0d89f651e
BLAKE2b-256 checksum
How to use checksums
82e738c327824619c8a9c44dd26cd7804ac4c5669ff4db831ef4869f7e0645f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.20

Release files / nutils_units-0.2.1-py3-none-any.whl

Download URL nutils_units-0.2.1-py3-none-any.whl
Size 15.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7ddfebbb1308249497ca5f05b689feef62b5057b6866c2e170f0d3ff18756c23
BLAKE2b-256 checksum
How to use checksums
0182e64f147eab375a7c5b8d08a6c33f8802b8ce33bad80829bd9624ac289e8d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.20

Release history Release notifications | RSS feed

0.2.2

2 release files

This release

0.2.1 This release

2 release files

0.2

2 release files

0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page