%load_ext autoreload
%autoreload 2

Quick Guide

-Brief tutorial for those in a hurry-

There are several python libraries to work with physical quantities such as pint, unyt or openmm.unit. Now imagine that your project requires the interaction with different tools, and those tools don’t operate with the same physical quantities objects. Wouldn’t having a library with a unique API to work with different forms of physical quantities be a relief?

PyUnitWizard allows you to work with more than a physical units library in python -such as pint, unyt or openmm.unit- with a unique API. PyUnitWizard works as the man in the middle between your code

Import PyUnitWizard and choose the libraries you are going to work with.

import pyunitwizard as puw
puw.configure.load_library(['pint', 'openmm.unit'])
puw.configure.get_default_form()
'pint'
puw.configure.get_default_parser()
'pint'

Let’s play a bit with quantities and units

Let’s make a quantity from its value and unit name:

q = puw.quantity(2.5, 'nanometers/picoseconds')
q
2.5 nanometer/picosecond

We can check that q is in deed a Pint quantity:

puw.is_quantity(q)
True
puw.get_form(q)
'pint'

Let’s extract now its value and units:

puw.get_value(q)
2.5
puw.get_unit(q)
nanometer/picosecond

And let’s also check the dimensionality:

puw.get_dimensionality(q)
{'[L]': 1, '[M]': 0, '[T]': -1, '[K]': 0, '[mol]': 0, '[A]': 0, '[Cd]': 0}

We can now translate q from Pint to openmm.unit:

q2 = puw.convert(q, to_form='openmm.unit')
puw.get_form(q2)
'openmm.unit'
q2
Quantity(value=2.5, unit=nanometer/picosecond)

Finally, lets convert q2 into other units:

q3 = puw.convert(q2, to_unit='angstroms/picoseconds')
print('{} was converted to angstroms/picoseconds as {}'.format(q2, q3))
2.5 nm/ps was converted to angstroms/picoseconds as 25.0 A/ps

The dimensionality of q3 did not change:

puw.get_dimensionality(q3)
{'[L]': 1.0, '[M]': 0, '[T]': -1.0, '[K]': 0, '[mol]': 0, '[A]': 0, '[Cd]': 0}

Actually, q and q3 are compatible quantities (they have the same dimensionality):

puw.compatibility(q, q3)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[18], line 1
----> 1 puw.compatibility(q, q3)

AttributeError: module 'pyunitwizard' has no attribute 'compatibility'

Let’s make now a unit from its name or symbol:

u = puw.unit('kJ/mol', form='openmm.unit')
u
Unit({BaseUnit(base_dim=BaseDimension("amount"), name="mole", symbol="mol"): -1.0, ScaledUnit(factor=1000.0, master=meter*newton, name='kilojoule', symbol='kJ'): 1.0})

We can check that u is in deed a openmm.unit unit.

puw.get_form(u)
'openmm.unit'
puw.is_unit(u)
True

And as it was done already with a quantity, we can check the dimensionality:

puw.get_dimensionality(u)
{'[L]': 2.0,
 '[M]': 1.0,
 '[T]': -2.0,
 '[K]': 0,
 '[mol]': -1.0,
 '[A]': 0,
 '[Cd]': 0}

Units and quantities can be turned into strings:

puw.convert(u, to_form='string')
'kilojoule/mole'

Quantities and units can also be created from algebraical expressions mixing values and units:

q = puw.convert('3.5N/(2.0nm**2)', to_form='openmm.unit')
q
Quantity(value=1.75, unit=newton/(nanometer**2))

Involving also lists:

q = puw.convert('[0.0, 0.0, 0.0] nm', to_form='pint')
q
Magnitude
[0.0 0.0 0.0]
Unitsnanometer

And quantities can be converted to strings:

puw.convert(q, to_form='string')
'[0.0 0.0 0.0] nanometer'

As well as units:

u = puw.convert('K', to_form='pint', to_type='unit')
u
kelvin
puw.convert(u, to_form='string')
'kelvin'

The default quantity form

PyUnitWizard takes the first unit library loaded as the default quantity form:

puw.configure.get_libraries_loaded()
['pint', 'openmm.unit']
puw.configure.get_default_form()
'pint'

The default form is taken when a method is invoked with out specifying the quantity or unit form:

q1 = puw.convert('3.5N/(2.0nm**2)')
q2 = puw.quantity(300.0, 'kelvin')

print('q1 is a {} quantity'.format(puw.get_form(q1)))
print('q2 is a {} quantity'.format(puw.get_form(q2)))
q1 is a pint quantity
q2 is a pint quantity

The default form can be changed with the following method:

puw.configure.set_default_form('openmm.unit')
q1 = puw.convert('3.5N/(2.0nm**2)')
q2 = puw.quantity(300.0, 'kelvin')

print('q1 is a {} quantity'.format(puw.get_form(q1)))
print('q2 is a {} quantity'.format(puw.get_form(q2)))
q1 is a openmm.unit quantity
q2 is a openmm.unit quantity

The standards

PyUnitWizard includes the possibility to define standard units for you library or python script. Let’s suppose your quantities will be always expressed in ‘nm’, ‘ps’ and ‘kcal/mol’ as Pint quantities. This two next lines sets this election as the default standards and form:

puw.configure.set_standard_units(['nm', 'ps', 'kcal', 'mole'])
puw.configure.set_default_form('pint')

We can check that these values were indeed stored:

puw.configure.get_standard_units()
{'nm': {'[L]': 1.0,
  '[M]': 0,
  '[T]': 0,
  '[K]': 0,
  '[mol]': 0,
  '[A]': 0,
  '[Cd]': 0},
 'ps': {'[L]': 0,
  '[M]': 0,
  '[T]': 1.0,
  '[K]': 0,
  '[mol]': 0,
  '[A]': 0,
  '[Cd]': 0},
 'kcal': {'[L]': 2.0,
  '[M]': 1.0,
  '[T]': -2.0,
  '[K]': 0,
  '[mol]': 0,
  '[A]': 0,
  '[Cd]': 0},
 'mole': {'[L]': 0,
  '[M]': 0,
  '[T]': 0,
  '[K]': 0,
  '[mol]': 1.0,
  '[A]': 0,
  '[Cd]': 0}}
puw.configure.get_default_form()
'pint'

The method pyunitwizard.get_standard() shows the standardized compatible units of a quantity:

q = puw.quantity('2.0 pm', form='openmm.unit')
puw.get_standard_units(q)
print('The standard of q is:', puw.get_standard_units(q))
The standard of q is: nm

And the method pyunitwizard.standardize() converts and translates the input quantity into the defined defined default standard compatible units and form:

q2 = puw.standardize(q)
print('q2 is now a {} quantity expressed in {}.'.format(puw.get_form(q2), puw.get_unit(q2)))
q2 is now a pint quantity expressed in nanometer.

Other output forms can be specified with the input argument to_form

q2 = puw.standardize(q, to_form='openmm.unit')
print('q2 is now a {} quantity expressed in {}.'.format(puw.get_form(q2), puw.get_unit(q2)))
q2 is now a openmm.unit quantity expressed in nanometer.

As you noticed, we have mention that pyunitwizard.get_standard and pyunitwizard.standardize results with the compatible default standard units. This is combination of standard units are also considered:

q = puw.quantity('100 angstroms**3')
print('The standard of q is:', puw.get_standard_units(q))
The standard of q is: nanometer ** 3
q = puw.quantity('3000.0 pm/ns')
print('The standard of q is:', puw.get_standard_units(q))
The standard of q is: nanometer / picosecond
q = puw.quantity('1.4 kJ/mol')
print('The standard of q is:', puw.get_standard_units(q))
The standard of q is: kilocalorie / mole

Again, and finnally, pyunitwizard.standardize can help you to have homogeneous outputs in you library:

q = puw.quantity(1.4, 'kJ/mol', form='openmm.unit')
output = puw.standardize(q)
print('{} as {} quantity'.format(output, puw.get_form(output)))
0.3346080305927342 kilocalorie / mole as pint quantity

Integrate PyUnitWizard in your library

Finnally, and although its is out of the scope of this tutorial, let’s mention that PyUnitWizard can be integrated in your library with your local definition of default quantities library and standards. See the section xxx in this documentation for further details.