Skip to main content

SI units and quantities library

Project description

siquant

PyPI version Build Status Coverage Status

A library to provide dimensional and quantitative analysis within the SI units system.

Description

This library provides a reasonably efficient set of tools to easily track units through abitrary calculations. All types are designed to be immutable, and as such can be shared relatively freely.

There are two primary data types:

  • SIUnit - provide some scaling factor of a specific dimensionality of the 7 fundamental SI units.
  • ScalarQuantity - support arithmetic of a quantity of units

Some predefined units are provided in modules in the siquant.systems package.

Getting Started

>>>from siquant.systems import si
>>>force = 100 * si.kilonewtons
>>>moment_arm = 50 * si.meters
>>>torque = force * moment_arm
>>>torque.get()
5000
>>>str(torque.units)
'1000*kg**1*m**2*s**-2'
>>>torque.get_as(si.newtons * si.meters)
5000000.0
>>>torque.get_as(si.newtons)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/siquant/siquant/quantities.py", line 19, in get_as
      assert(self._units.compatible(units))
AssertionError
>>>torque = torque.normalized()
>>>torget.get()
5000000.0
>>>str(torque.units)
'1*kg**1*m**2*s**-2'

Defining New Units

New unit types can be created:

  • implicitly derived through combination of existing units.
  • explicitly via the Unit.Unit() factory method.

Derived Units

from siquant.systems import si
pounds = si.kilograms * si.SIUnit.Unit(0.445)
inches = si.millimeters * si.SIUnit.Unit(25.4)
ksi = si.kilo * pounds / inches ** 2

Explicit Units

from siquant.systems import si
from siquant.units import SIUnit
wonky_pi_unit = SIUnit.Unit(3.14, m=1)
circle = 100 * wonky_pi_unit
diameter = circle.get()
circumeference = circle.get_as(si.meters)

Converters: Quantities at the DMZ

The Quantity type provides a class method As(units: SIUnit) which returns a converter function which can be used to normalize an argument in specific units, raise an error if their dimensionality does not match, and promote a raw value to a quantity with the expected units.

distance_t = ScalarQuantity.As(si.millimeters)
def area(value):
    return distance_t(value) ** 2

>>>str(area(10.0))
'100.0 1e-6*m**2'
>>>str(area(10 * si.millimeters))
'100.0 1e-6*m**2'
>>>str(area(10 * si.meters))
'100000000.0 1e-06*m**2'
>>>str(area(10 * si.kilograms))
...
AssertionError

Integration with attrs

These converters integrate readily with the attrs library to reduce boilerplate while gaining the benefits of unit tracking and validation.

import attr

from siquant.quantities import ScalarQuantity
from siquant.systems import si 

@attr.s
class IsotropicMaterial:
    elastic_modulus = attr.ib(converter=ScalarQuantity.As(si.gigapascals))
    shear_modulus = attr.ib(converter=ScalarQuantity.As(si.gigapascals))
    poissons_ratio = attr.ib(converter=ScalarQuantity.As(si.unity))

Supporting Vector Quantities

There are a number of vector libraries available, all with different interfaces. As such, a VectorQuantity is not provided. However, integration of existing vector libraries should be possible with relative ease.

Provide a VectorQuantity interface:

import numbers
from siquant.quantities import Quantity, ScalarQuantity

class VectorQuantity(Quantity):

    def cross(self, other):
        if not isinstance(other, VectorQuantity):
            raise TypeError()
        return VectorQuantity(self.quantity.cross(other.quantity), self.units * other.units)

    def dot(self, other):
        if not isinstance(other, VectorQuantity):
            raise TypeError()
        return ScalarQuantity(self.quantity.dot(other.quantity), self.units * other.units)

    def __mul__(self, other):
        if isinstance(other, numbers.Real):
            return VectorQuantity(self.quantity * other, self.units)
        if isinstance(other, ScalarQuantity):
            return VectorQuantity(self.quantity * other.quantity, self.units * other.units)
        if isinstance(other, VectorQuantity):
            return self.dot(other)
        return NotImplemented

    def __rmul__(self, other):
        # Real, ScalarQuantity
        ...

    # etc ...

force_vector = VectorQuantity(my_vector, si.newtons)

Provide a hook for SIUnit (optional)

The arithmetic methods of SIUnit only support operands of type numbers.Real and SIUnit. In all other cases NotImplemented is returned. The interpretter will then attempt to delegate that operation to the other operand type.

In order to support the behavior Vector * SIUnit -> VectorQuantity the special methods __mul__ and __rmul__ should be augmented. The exact implementation will depend heavily upon the library being integrated, in order to make sure that the new child type is always propagated correctly.

Composition

from siquant.units import SIUnit
from your.vec.lib import Vector

class VectorWrapper:

    @classmethod
    def Make(cls, *args, **kwargs):
        return cls(Vector(*args, **kwargs))

    def __init__(self, vector):
        self._vector = vector

    def unwrap(self):
        return self._vector

    def __mul__(self, other):
        if isinstance(other, SIUnit):
            return VectorQuantity(self, other)
        return VectorWrapper(self._vector * other)

    def __rmul__(self, other):
        if isinstance(other, SIUnit):
            return VectorQuantity(self, other)
        return VectorWrapper(other * self._vector)

    # any other operations to support

Inheritance

from siquant.units import SIUnit
from your.vec.lib import Vector

class QVector(Vector):

    def __mul__(self, other):
        if isinstance(other, SIUnit):
            return VectorQuantity(self, other)
        return super().__mul__(other)

    __rmul__ = __imul__ = __mul__

Including siquant as a dependency

This is probably the simplest, and the least practical.

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

siquant-3.0.2.tar.gz (12.0 kB view hashes)

Uploaded Source

Built Distribution

siquant-3.0.2-py3-none-any.whl (14.3 kB view hashes)

Uploaded Python 3

Supported by

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