# Physical quantities

Physical quantities, that is numbers accompanied by a physical unit, are represented by the `PhysicalQuantity` parameter type. One main feature of that parameter type is that it handles any necessary unit conversion from specified unit to declared unit automatically.

```python
from hanna import Configurable, PhysicalQuantity

class Diode(Configurable):
    threshold = PhysicalQuantity(unit='V')
    
diode = Diode({'threshold': '10 [mV]'})
diode.threshold  # 0.01
```

As can be seen from the example above physical quantities are specified using the following syntax: `"<magnitude> [<unit>]"`. The specified value is then loaded and converted to the declared unit. Note that the unit is only used for loading the parameter and for applying the appropriate conversions while the parameter's resulting value is represented by a `float` with the declared unit assumed implicitly.

### Alternative ways to declare units

Using a string for the unit declaration is in fact a shorthand. Behind the scenes runs a unit engine which is based on a specific python package. Different engines are backed by different packages and are intended to support a different range of features. The user can choose the unit engine they want to use. The default engine is backed by [Pint](https://pypi.org/project/Pint/).

{% hint style="info" %}
In order to use a specific unit engine (also the default engine!) you need to manually install the corresponding package. This behavior intends to keep the dependencies of the framework at a minimum (since not necessarily every user wants to use physical quantities). You can check the backend of each engine by looking at the `Engine.backend_url` attribute.
{% endhint %}

So suppose you have the Pint package installed then you can use Pint's native units for declaration of physical quantities:

```python
# `units` is a wrapper around a pint.UnitRegistry instance.
from hanna.physics import units
import pint

ur = pint.UnitRegistry()

class Diode(Configurable):
    threshold = PhysicalQuantity(unit=units.V)
    threshold = PhysicalQuantity(unit=ur.V)  # This works similarly.
```

The unit of a `PhysicalQuantity` can be changed later on via `Diode.threshold.unit = 'mV'` (instead of `str` you can also use one the above alternatives).

### Selecting the unit engine

Three different engines are available (in the module `hanna.physics.units`), each backed by a different Python package:

* `Pint` (backed by [Pint](https://pypi.org/project/Pint/); default)
* `NumericalUnits` (backed by [numericalunits](https://pypi.org/project/numericalunits/))
* `Units` (backed by [units](https://pypi.org/project/units/))

We can change the active engine in the following way:

```python
from hanna.physics import units
from hanna.physics.units import NumericalUnits

units.engine = NumericalUnits  # Selects the `NumericalUnits` engine.

# Again we can use the native units for declaring parameters.
import numericalunits as nu

class Diode(Configurable):
    threshold = PhysicalQuantity(unit=units.V)
    threshold = PhysicalQuantity(unit=nu.V)
```
