This tutorial shows how to use the natu module to work with physical quantities in Python.

**Table of contents:**

Before we get started, we'll set the display precision for this IPython notebook.

In [1]:

```
%precision 4
```

Out[1]:

First, we'll import the metre (m):

In [2]:

```
from natu.units import m
m
```

Out[2]:

It's a scalar unit that displays as "m". Its dimension is length (L) and it can be used with SI prefixes.

To enter a quantity, we multiply a number by a unit:

In [3]:

```
length = 0.0254*m
length
```

Out[3]:

We can change the display unit by setting the quantity's `display`

property:

In [4]:

```
length.display_unit = 'inch'
length
```

Out[4]:

We can also express the length as a number of inches by dividing it by the inch:

In [5]:

```
from natu.units import inch
length/inch
```

Out[5]:

In [6]:

```
from natu.units import km
km
```

Out[6]:

It can't be prefixed any further. As expected, it's 1000 times larger than the metre:

In [7]:

```
km/m
```

Out[7]:

We can access units directly from the units module, with or without prefixes:

In [8]:

```
from natu import units as U
U.km/U.m
```

Out[8]:

However, if we use a wildcard import (`from natu.units import *`

), we only get the units which are explicitly given in the the definition files. Typically this doesn't include prefixed units.

Nonscalar units such as the degree Celsius, degree Fahrenheit, and decibel are available:

In [9]:

```
from natu.units import degC, degF, dB
```

These units are called lambda units because they involve invertible functions that are not limited to multiplication and division. For convenience, however, lambda units are overloaded to use the multiplication and division operators (`*`

and `/`

). The unit must always be on the right side of the operator:

In [10]:

```
temperature = 25*degC
```

We can display this temperature in kelvin (a scalar unit):

In [11]:

```
from natu.units import K
temperature/K
```

Out[11]:

or in Fahrenheit (another lambda unit):

In [12]:

```
temperature/degF
```

Out[12]:

We can add temperatures that have been created from different units:

In [13]:

```
0*degC + 100*K
```

Out[13]:

The display unit of the first quantity takes precedence. natu checks that the dimensions are compatible when performing arithmetic, so a temperature can only be added to another temperature. Temperatures are absolute quantities, so the sum of 25 ℃ and 25 ℃ is 323.15 ℃ (or 596.3 K, but not 50 ℃):

In [14]:

```
25*degC + 25*degC
```

Out[14]:

We can use the decibel to multiply two numbers by adding their logarithms:

In [15]:

```
(10/dB + 10/dB)*dB
```

Out[15]:

In [16]:

```
from natu.units import mdegC
100*mdegC/K
```

Out[16]:

Quantities can be used in numpy arrays:

In [17]:

```
import numpy as np
np.array([1, 2, 3])*m
```

Out[17]:

Notice that the result is an array of quantities. To get a quantity with a value that is an array, put the unit before the array:

In [18]:

```
m*np.array([1, 2, 3])
```

Out[18]:

The previous two lines of code are mathematically equivalent. However, when working with large arrays of quanties with the same physical dimension, the second form will generally save memory and processing time. It's also possible to create arrays of quantities with mixed dimensions, for example:

In [19]:

```
np.array([1*m, 100*degC])
```

Out[19]:

Note that a quantity with a value that is an array can be indexed like an array. For example:

In [20]:

```
x = m*np.array([1, 2, 3])
x[:2]
```

Out[20]:

Also, properties and methods of the array are available from the quantity. For example:

In [21]:

```
x.clip(0, 2)
```

Out[21]:

The value of a quantity can be complex:

In [22]:

```
(1 + 1j)*m
```

Out[22]:

For convenience, the contents of natu.units are sorted into submodules of natu.groups. There are submodules for physical constants (constants), SI units (si), and units of various dimensions (length, time, pressure, etc.). We can access units from these submodules in several ways, just like those from natu.units:

In [23]:

```
# Individually:
from natu.groups.length import m
# By access:
from natu.groups import length
m = length.m
# By wildcard:
from natu.groups.length import *
```

By default, units are simplified using coherent relations. For example,

In [24]:

```
from natu.units import m, kg, s
1*kg*m**2/s**2
```

Out[24]:

The extent of simplification can be adjusted using `simplification_level`

in natu.config.

We can derive a new coherent unit from existing units since the product or quotient of two units is generally another unit (as discussed here). For example, we can represent the cubic inch as a stand-alone unit:

In [25]:

```
cinch = inch**3
cinch
```

Out[25]:

However, notice that the display unit is not the new unit but rather inch^{3}:

In [26]:

```
10*cinch
```

Out[26]:

We can update the display unit, but we must insert the new unit into the unit space to make it available:

In [27]:

```
cinch.display_unit = 'cinch'
from natu import units
units.cinch = cinch
```

Now we get the desired result:

In [28]:

```
10*cinch
```

Out[28]:

If the expression of the new unit requires a numeric factor (not coherently derived), then the result is a quantity that we need to explicitly cast as a unit:

In [29]:

```
from natu.core import ScalarUnit
from natu.units import ns
shake = ScalarUnit.from_quantity(10*ns, 'shake')
```

As before, we need to insert the unit into the unit space:

In [30]:

```
units.shake = shake
```

Now it's ready for use:

In [31]:

```
time = 500*ns
time.display_unit = 'shake'
time
```

Out[31]:

We can also introduce new units by swapping or adding definition files. That way we don't need to re-enter the units during each Python session as with the methods in the previous section. Also, coherent units are automatically added to the list of coherent relations for use in simplifying units. **However, it's important to be sure that the definition files are from a trusted source since natu uses eval() to process them.**

The config submodule contains a list of definition files:

In [32]:

```
from natu import config
config.definitions
```

Out[32]:

These files are loaded and processed the first time any units are imported. Before that, we can change the list of files. For example:

In [33]:

```
config.definitions.append("custom.ini")
```

where custom.ini is in the current directory. Since units were imported before this section, it's necessary to restart the IPython notebook's kernel just before running this section so that the new file will be loaded and processed. Only then will the new units be available for import from natu.units or the appropriate submodules of natu.groups.

In [34]:

```
from natu.units import shake
shake
```

Out[34]:

By default, units and dimensions are formatted with "*" as the multiplication operator. Exponents directly follow the units and dimensions (without "**" or "^"). If necessary, a division sign is used (instead of negative exponents) and the denominator is placed in parentheses if it has more than one factor. Let's see how this looks for the Ampere constant (*k*_{A}):

In [35]:

```
from natu.units import k_A
k_A.display_unit = 'N/A2'
print('{0} (dimension {0.dimension})'.format(k_A))
```

We can change the format using string format syntax. For example, the multiplication is shown by periods in Modelica format:

In [36]:

```
print('{0:M} (dimension {0.dimension:M})'.format(k_A))
```

In verbose format, the exponents are written as Python code:

In [37]:

```
print('{0:V} (dimension {0.dimension:V})'.format(k_A))
```

In Unicode format, the exponents are written as superscripts:

In [38]:

```
print(u'{0:U} (dimension {0.dimension:U})'.format(k_A))
```

This format can only be used with integer exponents. In HTML format:

In [39]:

```
print('{0:H} (dimension {0.dimension:H})'.format(k_A))
```

This renders as 1×10^{-7} N A^{-2} (dimension L M I^{-2} T^{-2}).

Finally, in LaTeX math format:

In [40]:

```
print('{0:L} (dimension ${0.dimension:L}$)'.format(k_A))
```

This renders as $1 \times 10^{-7}\,\mathrm{N}\,\mathrm{A}^{-2}$ (dimension $\mathrm{L}\,\mathrm{M}\,\mathrm{I}^{-2}\,\mathrm{T}^{-2}$).

We can also change the format of the number using Python's built-in formatting. For example, to use Unicode format with seven decimal places:

In [41]:

```
print(u'{0:.7fU}'.format(k_A))
```

Each unit has display unit. It defaults to the unit itself, but it can be changed. We can use this feature to automatically convert units. For example, to enter a length in yards but display it in meters:

In [42]:

```
from natu.units import yd
yd.display_unit = 'm'
1*yd
```

Out[42]:

Besides the display unit, a unit is essentially immutable. Its value is a protected property (`_value`

) and its `dimension`

and `prefixable`

properties can't be changed.

natu doesn't use conversion factors directly, but can divide units to determine them:

In [43]:

```
%precision 4
from natu.units import inch, m
inch/m
```

Out[43]:

The result may seem counterintuitive at first. We divided the inch by the metre, but we got the conversion factor from inches to metres. The conversion factor from unit A to unit B is the number of units B in one unit A. Mathematically, this is *x**B = 1*A, where *x* is the conversion factor. The solution is *x* = A/B. In this case A is the inch and B is the metre, so we have the conversion factor from inches to metres (which happens to be the number we used in the first section).

In natu we deal with quantities, not numbers. Numbers are unit-dependent, but quantities are not. A quantity is expressed as the product of a number and a unit (*q* = *n**U). When we say "in unit," we generally mean "divided by unit." So "quantity in unit" is *q*/U or *n*, the number.

Mathematical operations on natu's quantities are slower than those on floats because the quantities track dimension and display unit in addition to the value. However, quantities may only be needed to check dimensions during code development and to display values as the product of a number and a unit for debugging. Later, one can speed up the code by disabling quantities and using their values directly.

First, let's see how long it takes to express a simple quantity:

In [44]:

```
%timeit 1*m
```

We'll disable quantities and check again. Restart the IPython kernel now, since it's only possible to disable quantities before any units are imported. Then,

In [1]:

```
%precision 4
from natu import config
config.use_quantities = False
```

Now, import the desired units:

In [2]:

```
from natu.units import m
%timeit 1*m
```

The operation is about 300 times faster because it's just floating point multiplication. The metre is now a float:

In [3]:

```
type(m)
```

Out[3]:

However, the core functionality is still available. As in the first section of the tutorial, where quantities were enabled, we can express a length as a number of inches by dividing it by the inch:

In [4]:

```
from natu.units import inch
length = 0.0254*m
length/inch
```

Out[4]:

If we inspect the length directly, we find that it's only a number:

In [5]:

```
length
```

Out[5]:

In [6]:

```
m
```

Out[6]:

The metre is normalized because the units were based on SI using base-SI.ini (the first definition file, by default). This can be changed (see the documentation and the earlier section on units via definition files), and code generally shouldn't be written so that it requires a particular unit system.

Although scalar units are now floats, lambda units remain. Let's look at the degree Celsius:

In [7]:

```
from natu.units import degC
degC
```

Out[7]:

It's considered dimensionless because dimensions are no longer tracked; it yields a float instead of a quantity. The usage is the same though:

In [8]:

```
from natu.units import K
temperature = 0*degC + 100*K
temperature/degC
```

Out[8]: