Unit Registry API

Unit handling makes use of the Pint library. This allows us to easily define units as well as contexts. Contexts allow us to perform conversions which would not normally be allowed e.g. in the ‘AR4GWP100’ context we can convert from CO2 to CH4 using the AR4GWP100 equivalence metric.

An illustration of how the unit_registry can be used is shown below:

>>> from openscm_units import unit_registry
>>> unit_registry("CO2")
<Quantity(1, 'CO2')>

>>> emissions_aus = 0.34 * unit_registry("Gt C / yr")
>>> emissions_aus
<Quantity(0.34, 'C * gigametric_ton / a')>

>>> emissions_aus.to("Mt CO2 / yr")
<Quantity(1246.666666666667, 'CO2 * megametric_ton / a')>

>>> with unit_registry.context("AR4GWP100"):
...     (100 * unit_registry("Mt CH4 / yr")).to("Mt CO2 / yr")
<Quantity(2500.0, 'CO2 * megametric_ton / a')>

More details on emissions units

Emissions are a flux composed of three parts: mass, the species being emitted and the time period e.g. “t CO2 / yr”. As mass and time are part of SI units, all we need to define here are emissions units i.e. the stuff. Here we include as many of the canonical emissions units, and their conversions, as possible.

For emissions units, there are a few cases to be considered:

  • fairly obvious ones e.g. carbon dioxide emissions can be provided in ‘C’ or ‘CO2’ and converting between the two is possible

  • less obvious ones e.g. NOx emissions can be provided in ‘N’ or ‘NOx’ (a short-hand which is assumed to be NO2), we provide conversions between these two

  • case-sensitivity. In order to provide a simplified interface, using all uppercase versions of any unit is also valid e.g. unit_registry("HFC4310mee") is the same as unit_registry("HFC4310MEE")

  • hyphens and underscores in units. In order to be Pint compatible and to simplify things, we strip all hyphens and underscores from units.

As a convenience, we allow users to combine the mass and the type of emissions to make a ‘joint unit’ e.g. “tCO2”. It should be recognised that this joint unit is a derived unit and not a base unit.

By defining these three separate components, it is much easier to track what conversions are valid and which are not. For example, as the emissions units are all defined as emissions units, and not as atomic masses, we are able to prevent invalid conversions. If emissions units were simply atomic masses, it would be possible to convert between e.g. C and N2O which would be a problem. Conventions such as allowing carbon dioxide emissions to be reported in C or CO2, despite the fact that they are fundamentally different chemical species, is a convention which is particular to emissions (as far as we can tell).

Pint’s contexts are particularly useful for emissions as they facilitate metric conversions. With a context, a conversion which wouldn’t normally be allowed (e.g. tCO2 –> tN2O) is allowed and will use whatever metric conversion is appropriate for that context (e.g. AR4GWP100).

Finally, we discuss namespace collisions.

CH4

Methane emissions are defined as ‘CH4’. In order to prevent inadvertent conversions of ‘CH4’ to e.g. ‘CO2’ via ‘C’, the conversion ‘CH4’ <–> ‘C’ is by default forbidden. However, it can be performed within the context ‘CH4_conversions’ as shown below:

>>> from openscm_units import unit_registry
>>> unit_registry("CH4").to("C")
pint.errors.DimensionalityError: Cannot convert from 'CH4' ([methane]) to 'C' ([carbon])

# with a context, the conversion becomes legal again
>>> with unit_registry.context("CH4_conversions"):
...     unit_registry("CH4").to("C")
<Quantity(0.75, 'C')>

# as an unavoidable side effect, this also becomes possible
>>> with unit_registry.context("CH4_conversions"):
...     unit_registry("CH4").to("CO2")
<Quantity(2.75, 'CO2')>

N2O

Nitrous oxide emissions are typically reported with units of ‘N2O’. However, they are also reported with units of ‘N2ON’ (a short-hand which indicates that only the mass of the nitrogen is being counted). Reporting nitrous oxide emissions with units of simply ‘N’ is ambiguous (do you mean the mass of nitrogen, so 1 N = 28 / 44 N2O or just the mass of a single N atom, so 1 N = 14 / 44 N2O). By default, converting ‘N2O’ <–> ‘N’ is forbidden to prevent this ambiguity. However, the conversion can be performed within the context ‘N2O_conversions’, in which case it is assumed that ‘N’ just means a single N atom i.e. 1 N = 14 / 44 N2O, as shown below:

>>> from openscm_units import unit_registry
>>> unit_registry("N2O").to("N")
pint.errors.DimensionalityError: Cannot convert from 'N2O' ([nitrous_oxide]) to 'N' ([nitrogen])

# with a context, the conversion becomes legal again
>>> with unit_registry.context("N2O_conversions"):
...     unit_registry("N2O").to("N")
<Quantity(0.318181818, 'N')>

NOx

Like for methane, NOx emissions also suffer from a namespace collision. In order to prevent inadvertent conversions from ‘NOx’ to e.g. ‘N2O’, the conversion ‘NOx’ <–> ‘N’ is by default forbidden. It can be performed within the ‘NOx_conversions’ context:

>>> from openscm_units import unit_registry
>>> unit_registry("NOx").to("N")
pint.errors.DimensionalityError: Cannot convert from 'NOx' ([NOx]) to 'N' ([nitrogen])

# with a context, the conversion becomes legal again
>>> with unit_registry.context("NOx_conversions"):
...     unit_registry("NOx").to("N")
<Quantity(0.30434782608695654, 'N')>

NH3

In order to prevent inadvertent conversions from ‘NH3’ to ‘CO2’, the conversion ‘NH3’ <–> ‘N’ is by default forbidden. It can be performed within the ‘NH3_conversions’ context analogous to the ‘NOx_conversions’ context:

>>> from openscm_units import unit_registry
>>> unit_registry("NH3").to("N")
pint.errors.DimensionalityError: Cannot convert from 'NH3' ([NH3]) to 'N' ([nitrogen])

# with a context, the conversion becomes legal again
>>> with unit_registry.context("NH3_conversions"):
...     unit_registry("NH3").to("N")
<Quantity(0.823529412, 'N')>
class openscm_units._unit_registry.ScmUnitRegistry(*args, **kwargs)

Bases: pint.registry.UnitRegistry

Unit registry class.

Provides some convenience methods to add standard units and contexts with lazy loading from disk.

UnitsContainer(*args, **kwargs)
add_context(context: pint.context.Context)None

Add a context object to the registry.

The context will be accessible by its name and aliases.

Notice that this method will NOT enable the context; see enable_contexts().

add_standards()

Add standard units.

Has to be done separately because of pint’s weird initializing.

auto_reduce_dimensions

Determines if dimensionality should be reduced on appropriate operations.

case_sensitive

Default unit case sensitivity

check(*args)

Decorator to for quantity type checking for function inputs.

Use it to ensure that the decorated function input parameters match the expected dimension of pint quantity.

The wrapper function raises:
  • pint.DimensionalityError if an argument doesn’t match the required dimensions.

uregUnitRegistry

a UnitRegistry instance.

argsstr or UnitContainer or None

Dimensions of each of the input arguments. Use None to skip argument conversion.

Returns

the wrapped function.

Return type

callable

Raises
  • TypeError – If the number of given dimensions does not match the number of function parameters.

  • ValueError – If the any of the provided dimensions cannot be parsed as a dimension.

context(*names, **kwargs)

Used as a context manager, this function enables to activate a context which is removed after usage.

Parameters
  • *names – name(s) of the context(s).

  • **kwargs – keyword arguments for the contexts.

Examples

Context can be called by their name:

>>> import pint
>>> ureg = pint.UnitRegistry()
>>> ureg.add_context(pint.Context('one'))
>>> ureg.add_context(pint.Context('two'))
>>> with ureg.context('one'):
...     pass

If a context has an argument, you can specify its value as a keyword argument:

>>> with ureg.context('one', n=1):
...     pass

Multiple contexts can be entered in single call:

>>> with ureg.context('one', 'two', n=1):
...     pass

Or nested allowing you to give different values to the same keyword argument:

>>> with ureg.context('one', n=1):
...     with ureg.context('two', n=2):
...         pass

A nested context inherits the defaults from the containing context:

>>> with ureg.context('one', n=1):
...     # Here n takes the value of the outer context
...     with ureg.context('two'):
...         pass
convert(value, src, dst, inplace=False)

Convert value from some source to destination units.

Parameters
  • value – value

  • src (pint.Quantity or str) – source units.

  • dst (pint.Quantity or str) – destination units.

  • inplace – (Default value = False)

Returns

converted value

Return type

type

default_as_delta

When performing a multiplication of units, interpret non-multiplicative units as their delta counterparts.

property default_format

Default formatting string for quantities.

property default_system
define(definition)

Add unit to the registry.

Parameters

definition (str or Definition) – a dimension, unit or prefix definition.

disable_contexts(n: Optional[int] = None)None

Disable the last n enabled contexts.

Parameters

n (int) – Number of contexts to disable. Default: disable all contexts.

enable_contexts(*names_or_contexts, **kwargs)

Overload pint’s enable_contexts() to load contexts once (the first time they are used) to avoid (unnecessary) file operations on import.

fmt_locale = None

Babel.Locale instance or None

get_base_units(input_units, check_nonmult=True, system=None)

Convert unit or dict of units to the base units.

If any unit is non multiplicative and check_converter is True, then None is returned as the multiplicative factor.

Unlike BaseRegistry, in this registry root_units might be different from base_units

Parameters
  • input_units (UnitsContainer or str) – units

  • check_nonmult (bool) – if True, None will be returned as the multiplicative factor if a non-multiplicative units is found in the final Units. (Default value = True)

  • system – (Default value = None)

Returns

multiplicative factor, base units

Return type

type

get_compatible_units(input_units, group_or_system=None)
get_dimensionality(input_units)

Convert unit or dict of units or dimensions to a dict of base dimensions dimensions

get_group(name, create_if_needed=True)

Return a Group.

Parameters
  • name (str) – Name of the group to be

  • create_if_needed (bool) – If True, create a group if not found. If False, raise an Exception. (Default value = True)

Returns

Group

Return type

type

get_name(name_or_alias, case_sensitive=None)

Return the canonical name of a unit.

get_root_units(input_units, check_nonmult=True)

Convert unit or dict of units to the root units.

If any unit is non multiplicative and check_converter is True, then None is returned as the multiplicative factor.

Parameters
  • input_units (UnitsContainer or str) – units

  • check_nonmult (bool) – if True, None will be returned as the multiplicative factor if a non-multiplicative units is found in the final Units. (Default value = True)

Returns

multiplicative factor, base units

Return type

Number, pint.Unit

get_symbol(name_or_alias, case_sensitive=None)

Return the preferred alias for a unit.

get_system(name, create_if_needed=True)

Return a Group.

Parameters
  • name (str) – Name of the group to be

  • create_if_needed (bool) – If True, create a group if not found. If False, raise an Exception. (Default value = True)

Returns

System

Return type

type

is_compatible_with(obj1, obj2, *contexts, **ctx_kwargs)

check if the other object is compatible

Parameters
  • obj1 – The objects to check against each other. Treated as dimensionless if not a Quantity, Unit or str.

  • obj2 – The objects to check against each other. Treated as dimensionless if not a Quantity, Unit or str.

  • *contexts (str or pint.Context) – Contexts to use in the transformation.

  • **ctx_kwargs – Values for the Context/s

Returns

Return type

bool

load_definitions(file, is_resource=False)

Add units and prefixes defined in a definition text file.

Parameters
  • file – can be a filename or a line iterable.

  • is_resource – used to indicate that the file is a resource file and therefore should be loaded from the package. (Default value = False)

non_int_type

Numerical type used for non integer values.

parse_expression(input_string, case_sensitive=None, use_decimal=False, **values)

Parse a mathematical expression including units and return a quantity object.

Numerical constants can be specified as keyword arguments and will take precedence over the names defined in the registry.

Parameters
  • input_string

  • case_sensitive – (Default value = None, which uses registry setting)

  • use_decimal – (Default value = False)

  • **values

parse_pattern(input_string, pattern, case_sensitive=None, use_decimal=False, many=False)

Parse a string with a given regex pattern and returns result.

Parameters
  • input_string

  • pattern_string – The regex parse string

  • case_sensitive – (Default value = None, which uses registry setting)

  • use_decimal – (Default value = False)

  • many – Match many results (Default value = False)

parse_unit_name(unit_name, case_sensitive=None)

Parse a unit to identify prefix, unit name and suffix by walking the list of prefix and suffix. In case of equivalent combinations (e.g. (‘kilo’, ‘gram’, ‘’) and (‘’, ‘kilogram’, ‘’), prefer those with prefix.

Parameters
  • unit_name

  • case_sensitive (bool or None) – Control if unit lookup is case sensitive. Defaults to None, which uses the registry’s case_sensitive setting

Returns

all non-equivalent combinations of (prefix, unit name, suffix)

Return type

tuple of tuples (str, str, str)

parse_units(input_string, as_delta=None, case_sensitive=None)

Parse a units expression and returns a UnitContainer with the canonical names.

The expression can only contain products, ratios and powers of units.

Parameters
  • input_string (str) –

  • as_delta (bool or None) – if the expression has multiple units, the parser will interpret non multiplicative units as their delta_ counterparts. (Default value = None)

  • case_sensitive (bool or None) – Control if unit parsing is case sensitive. Defaults to None, which uses the registry’s setting.

pi_theorem(quantities)

Builds dimensionless quantities using the Buckingham π theorem

Parameters

quantities (dict) – mapping between variable name and units

Returns

a list of dimensionless quantities expressed as dicts

Return type

list

remove_context(name_or_alias: str)pint.context.Context

Remove a context from the registry and return it.

Notice that this methods will not disable the context; see disable_contexts().

set_fmt_locale(loc)

Change the locale used by default by format_babel.

Parameters

loc (str or None) – None` (do not translate), ‘sys’ (detect the system locale) or a locale id string.

setup_matplotlib(enable=True)

Set up handlers for matplotlib’s unit support.

Parameters

enable (bool) – whether support should be enabled or disabled (Default value = True)

split_gas_mixture(quantity: pint.quantity.Quantity)list

Split a gas mixture into constituent gases.

Given a pint quantity with the units containing a gas mixture, returns a list of the constituents as pint quantities.

property sys
with_context(name, **kwargs)

Decorator to wrap a function call in a Pint context.

Use it to ensure that a certain context is active when calling a function:

:param name: name of the context.
:param \*\*kwargs: keyword arguments for the context
Returns

the wrapped function.

Return type

callable

Example

>>> @ureg.with_context('sp')
... def my_cool_fun(wavelength):
...     print('This wavelength is equivalent to: %s', wavelength.to('terahertz'))
wraps(ret, args, strict=True)

Wraps a function to become pint-aware.

Use it when a function requires a numerical value but in some specific units. The wrapper function will take a pint quantity, convert to the units specified in args and then call the wrapped function with the resulting magnitude.

The value returned by the wrapped function will be converted to the units specified in ret.

Parameters
  • ureg (pint.UnitRegistry) – a UnitRegistry instance.

  • ret (str, pint.Unit, iterable of str, or iterable of pint.Unit) – Units of each of the return values. Use None to skip argument conversion.

  • args (str, pint.Unit, iterable of str, or iterable of pint.Unit) – Units of each of the input arguments. Use None to skip argument conversion.

  • strict (bool) – Indicates that only quantities are accepted. (Default value = True)

Returns

the wrapper function.

Return type

callable

Raises

TypeError – if the number of given arguments does not match the number of function parameters. if the any of the provided arguments is not a unit a string or Quantity

openscm_units._unit_registry.unit_registry = <openscm_units._unit_registry.ScmUnitRegistry object>

Standard unit registry

The unit registry contains all of the recognised units. Be careful, if you edit this registry in one place then it will also be edited in any other places that use openscm_units. If you want multiple, separate registries, create multiple instances of ScmUnitRegistry.