Using units

All physical quantities within MDMC should possess units.

Everything related to units in MDMC is defined in MDMC.common.units. This includes:

  • the system of units (in the SYSTEM dictionary)

  • A Unit class, which derives from str to add additional arithmetic methods (__mul__, __div__, and __pow__) so that strings representing units (e.g. 'Ang', 's') can be combined by these operations: Unit('Ang') * Unit('s') == Unit('Ang s')

  • UnitFloat and UnitNDArray classes, which derive from float and numpy.ndArray to add additional a Unit object to the representation, by means of a unit attribute.

So all physical quantities must be a UnitFloat or a UnitNDArray, and have the correct Unit object as an attribute. This can be achieved by having the unit as a property, rather than an attribute, and using one of the following decorators (in MDMC.common.decorators):

  • unit_decorator: This should typically be the decorator that is used as it sets the property to be either a UnitFloat or UnitNDArray. It should be added to the property setter:

@property
def velocity(self):

    return self._velocity

@velocity.setter
@unit_decorator(unit=units.LENGTH / units.TIME)
def velocity(self, velocity):

    self._velocity = velocity
  • unit_decorator_getter: This only be used either where the property has no setter method or where the getter method performs a calculation before setting the value (which may result in the UnitFloat/UnitNDArray being cast to a float/ndArray). It should only be used in these cases as it is more expensive than unit_decorator, as it initialises a UnitFloat/UnitNDArray object every time the getter is called. It should be added to the property getter:

@property
@unit_decorator_getter(unit=units.LENGTH)
def dims(self):

    return self._dims

In both of the above examples the unit passed to the decorator is a constant from the SYSTEM of units defined in the MDMC.common.units; however it would be equally valid to define a unit in this argument:

from MDMC.common.units import Unit
@property
@unit_decorator_getter(unit=Unit('nm'))
def dims(self):

    return self._dims

It is then obviously important that all functions and methods that use these properties have the correct factors to ensure the unit conversions are correct.