Source code for xconf.misc.units

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""This module provides basic support for calculations with units."""

import math
import operator


def check_parameter(name, parameter):
    if not isinstance(parameter, Quantity):
        fmt = 'Parameter "{}" must be of type unit.Quantity.'
        raise ValueError(fmt.format(name))


[docs]class Quantity(object): """ Quantity base class. A quantity is made up of *magnitude* and *dimension*. """ def __init__(self, magnitude, dimension): self.magnitude = magnitude self.dimension = dimension
[docs] def convert(self, new_dimension): """ Convert this quantity to a another dimension *new_dimension* (e.g. to do a common mathematical operation on them). Will raise an error if the new dimension is not allowd. """ if not new_dimension in self.dims.keys(): fmt = 'Unit "{}" can not be converted to unit "{}".' raise ValueError(fmt.format(self.dimension, new_dimension)) else: u = self.__class__(self.magnitude, self.dimension) conv_fac = self.dims[self.dimension] / self.dims[new_dimension] u.magnitude *= conv_fac u.dimension = new_dimension return u
[docs] def free(self): """Drop all unit support and just return the quantities magnitude.""" return self.magnitude
[docs] def operate(self, other, op): """ Common method to check on the nature of operands. """ if isinstance(other, Quantity): c = self.convert(other.dimension) operator = op(c.magnitude, other.magnitude) dimension = other.dimension else: operator = op(self.magnitude, other) dimension = self.dimension return self.__class__(operator, dimension)
[docs] def compare(self, other, op): """ Common method to check on the nature of operands. """ if isinstance(other, Quantity): c = self.convert(other.dimension) operator = op(c.magnitude, other.magnitude) else: operator = op(self.magnitude, other) return operator
def __add__(self, other): return self.operate(other, operator.add) def __radd__(self, other): return self.operate(other, operator.add) def __sub__(self, other): return self.operate(other, operator.sub) def __mul__(self, other): return self.operate(other, operator.mul) def __rmul__(self, other): return self.operate(other, operator.mul) def __div__(self, other): return self.operate(other, operator.div) def __truediv__(self, other): return self.operate(other, operator.truediv) def __lt__(self, other): return self.compare(other, operator.lt) def __le__(self, other): return self.compare(other, operator.le) def __eq__(self, other): return self.compare(other, operator.eq) def __ne__(self, other): return self.compare(other, operator.ne) def __ge__(self, other): return self.compare(other, operator.ge) def __gt__(self, other): return self.compare(other, operator.gt) def __abs__(self): return abs(self.magnitude) def __str__(self): return "{} {}".format(self.magnitude, self.dimension)
[docs]class Angle(Quantity): """ Define an angle with unit. Allowed units are 'mdeg', 'deg', 'urad', 'mrad' and 'rad'. """ dims = dict( mdeg = math.pi / 180 * 1e-3, deg = math.pi / 180, urad = 1e-6, mrad = 1e-3, rad = 1 )
[docs]class SolidAngle(Quantity): """ Define an solid angle with unit. Allowed units are 'sr' and 'msr'. """ dims = dict( msr = 1e-3, sr = 1 )
[docs]class Length(Quantity): """ Define a length with unit. Allowed units are 'pm', 'angstrom', 'nm', 'um', 'mm', 'm' and 'km'. """ dims = dict( pm = 1e-12, angstrom = 1e-10, nm = 1e-9, um = 1e-6, mm = 1e-3, m = 1, km = 1e3 )
[docs]class Energy(Quantity): """ Define an energy with unit. Allowed units are 'meV', 'eV', 'KeV', 'MeV', 'GeV', 'mJ', 'J', 'KJ', 'MJ' and 'GJ'. """ dims = dict( meV = 1.6021766208e-19 * 1e-3, eV = 1.6021766208e-19 * 1, KeV = 1.6021766208e-19 * 1e3, MeV = 1.6021766208e-19 * 1e6, GeV = 1.6021766208e-19 * 1e9, mJ = 1e-3, J = 1, KJ = 1e3, MJ = 1e6, GJ = 1e9 )