Skip to main content

Nutils Units: object wrappers for dimensional computations

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nutils_units-0.1.tar.gz (14.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nutils_units-0.1-py3-none-any.whl (14.9 kB view details)

Uploaded Python 3

File details

Details for the file nutils_units-0.1.tar.gz.

File metadata

  • Download URL: nutils_units-0.1.tar.gz
  • Upload date:
  • Size: 14.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.20

File hashes

Hashes for nutils_units-0.1.tar.gz
Algorithm Hash digest
SHA256 1275ab1780fad5ee9d9084438a038d0233a0e1f04d8477950b0c71db9ccb9055
MD5 3a13ecf57ff7b8bd57f5e641405b0b4e
BLAKE2b-256 2423a5b960b00ecfba8314575217a3c00588670691fc2bf1484617652ee19a20

See more details on using hashes here.

File details

Details for the file nutils_units-0.1-py3-none-any.whl.

File metadata

  • Download URL: nutils_units-0.1-py3-none-any.whl
  • Upload date:
  • Size: 14.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.20

File hashes

Hashes for nutils_units-0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1d9f2f4c332dfdd00cae0289a760f521aea6063b3a79657bedd211316b6c5e66
MD5 2068eaa884f441bc314f7aa46dc87fd1
BLAKE2b-256 764f35e217bb2fff7610ea469c838509034934af874020a1c86d474a1097beb6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page