Units

Unit handling.

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.

In general, you should not use Pint with OpenSCM explicitly. As illustration of how units are used internally, we provide the following example:

>>> 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 C / week")
<Quantity(6.516224050620789, 'C * megametric_ton / week')>

A note 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. nitrous oxide emissions can be provided in ‘N’, ‘N2O’ or ‘N2ON’, we provide conversions

  • 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” but 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).

Finally, contexts are particularly useful for emissions as they facilitate much easier 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 UnitConverter
>>> uc = UnitConverter("CH4", "C")
pint.errors.DimensionalityError: Cannot convert from 'CH4' ([methane]) to 'C' ([carbon])

# with a context, the conversion becomes legal again
>>> uc = UnitConverter("CH4", "C", context="CH4_conversions")
>>> uc.convert_from(1)
0.75

# as an unavoidable side effect, this also becomes possible
>>> uc = UnitConverter("CH4", "CO2", context="CH4_conversions")
>>> uc.convert_from(1)
2.75

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
>>> uc = UnitConverter("NOx", "N")
pint.errors.DimensionalityError: Cannot convert from 'NOx' ([NOx]) to 'N' ([nitrogen])

# with a context, the conversion becomes legal again
>>> uc = UnitConverter("NOx", "N", context="NOx_conversions")
>>> uc.convert_from(1)
0.30434782608695654

# as an unavoidable side effect, this also becomes possible
>>> uc = UnitConverter("NOx", "N2O", context="NOx_conversions")
>>> uc.convert_from(1)
0.9565217391304348
class openscm.core.units.ScmUnitRegistry(filename='', force_ndarray=False, default_as_delta=True, autoconvert_offset_to_baseunit=False, on_redefinition='warn', system=None, auto_reduce_dimensions=False)

Bases: pint.registry.UnitRegistry

Unit registry class for OpenSCM. Provides some convenience methods to add standard unit and contexts.

__init__(filename='', force_ndarray=False, default_as_delta=True, autoconvert_offset_to_baseunit=False, on_redefinition='warn', system=None, auto_reduce_dimensions=False)

Initialize self. See help(type(self)) for accurate signature.

_add_gases(gases)
Return type

None

_add_mass_emissions_joint_version(symbol)

Add a unit which is the combination of mass and emissions.

This allows users to units like e.g. "tC" rather than requiring a space between the mass and the emissions i.e. "t C"

Parameters

symbol (str) – The unit to add a joint version for

Return type

None

_after_init()

This should be called after all __init__

_build_cache()

Build a cache of dimensionality and base units.

_contexts_loaded = False
_convert(value, src, dst, inplace=False)

Convert value from some source to destination units.

In addition to what is done by the BaseRegistry, converts between units with different dimensions by following transformation rules defined in the context.

Parameters
  • value – value

  • src (UnitsContainer) – source units.

  • dst (UnitsContainer) – destination units.

Returns

converted value

_dedup_candidates(candidates)

Given a list of unit triplets (prefix, name, suffix), remove those with different names but equal value.

e.g. (‘kilo’, ‘gram’, ‘’) and (‘’, ‘kilogram’, ‘’)

_define(definition)

Add unit to the registry.

This method defines only multiplicative units, converting any other type to delta_ units.

Parameters

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

Returns

Definition instance, case sensitive unit dict, case insensitive unit dict.

Return type

Definition, dict, dict

_define_adder(definition, unit_dict, casei_unit_dict)

Helper function to store a definition in the internal dictionaries. It stores the definition under its name, symbol and aliases.

_define_single_adder(key, value, unit_dict, casei_unit_dict)

Helper function to store a definition in the internal dictionaries.

It warns or raise error on redefinition.

_dir = ['Quantity', 'Unit', 'Measurement', 'define', 'load_definitions', 'get_name', 'get_symbol', 'get_dimensionality', 'get_base_units', 'get_root_units', 'parse_unit_name', 'parse_units', 'parse_expression', 'convert']
_eval_token(token, case_sensitive=True, **values)
_get_base_units(input_units, check_nonmult=True, system=None)
_get_compatible_units(input_units, group_or_system)
_get_dimensionality(input_units)

Convert a UnitsContainer to base dimensions.

Parameters

input_units

Returns

dimensionality

_get_dimensionality_ratio(unit1, unit2)

Get the exponential ratio between two units, i.e. solve unit2 = unit1**x for x. :param unit1: first unit :type unit1: UnitsContainer compatible (str, Unit, UnitsContainer, dict) :param unit2: second unit :type unit2: UnitsContainer compatible (str, Unit, UnitsContainer, dict) :returns: exponential proportionality or None if the units cannot be converted

_get_dimensionality_recurse(ref, exp, accumulator)
_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 dict) – units

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

Returns

multiplicative factor, base units

_get_root_units_recurse(ref, exp, accumulators)
_get_symbol(name)
_is_multiplicative(u)
_load_contexts()

Load contexts.

Return type

None

_load_metric_conversions()

Load metric conversion contexts from file.

This is done only when contexts are needed to avoid reading files on import.

Return type

None

_parse_context(ifile)
_parse_defaults(ifile)

Loader for a @default section.

_parse_group(ifile)
_parse_system(ifile)
_parse_units(input_string, as_delta=None)
_parsers = None
_register_parser(prefix, parserfunc)

Register a loader for a given @ directive..

Parameters
  • prefix – string identifying the section (e.g. @context)

  • parserfunc (SourceIterator -> None) – A function that is able to parse a Definition section.

_register_parsers()
_validate_and_extract(units)
add_context(context)

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. Use enable_contexts.

add_standards()

Add standard units.

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

check(*args)

Decorator to for quantity type checking for function inputs.

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

Use None to skip argument checking.

Parameters
  • ureg – a UnitRegistry instance.

  • args – iterable of input units.

Returns

the wrapped function.

Raises

DimensionalityError if the parameters don’t match dimensions

context(*names, **kwargs)

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

Parameters
  • names – name of the context.

  • kwargs – keyword arguments for the contexts.

Context are called by their name:

>>> with ureg.context('one'):
...     pass

If the 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):
...     with ureg.context('two'): # Here n takes the value of the upper context
...         pass
convert(value, src, dst, inplace=False)

Convert value from some source to destination units.

Parameters
  • value – value

  • src (Quantity or str) – source units.

  • dst (Quantity or str) – destination units.

Returns

converted value

property default_format

Default formatting string for quantities.

property default_system
define(definition)

Add unit to the registry.

Parameters

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

disable_contexts(n=None)

Disable the last n enabled 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.

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 – if True, None will be returned as the multiplicative factor if a non-multiplicative units is found in the final Units.

Returns

multiplicative factor, base units

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

Parameters

input_units

Returns

dimensionality

get_group(name, create_if_needed=True)

Return a Group.

Parameters
  • name – Name of the group to be

  • create_if_needed – Create a group if not Found. If False, raise an Exception.

Returns

Group

get_name(name_or_alias, case_sensitive=True)

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 – if True, None will be returned as the multiplicative factor if a non-multiplicative units is found in the final Units.

Returns

multiplicative factor, base units

get_symbol(name_or_alias)

Return the preferred alias for a unit

get_system(name, create_if_needed=True)

Return a Group.

Parameters
  • name – Name of the group to be

  • create_if_needed – Create a group if not Found. If False, raise an Exception.

Returns

System

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.

parse_expression(input_string, case_sensitive=True, **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.

parse_unit_name(unit_name, case_sensitive=True)

Parse a unit to identify prefix, unit name and suffix by walking the list of prefix and suffix.

Return type

(str, str, str)

parse_units(input_string, as_delta=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

as_delta – if the expression has multiple units, the parser will interpret non multiplicative units as their delta_ counterparts.

Raises

pint.UndefinedUnitError if a unit is not in the registry ValueError if the expression is invalid.

pi_theorem(quantities)

Builds dimensionless quantities using the Buckingham π theorem :param quantities: mapping between variable name and units :type quantities: dict :return: a list of dimensionless quantities expressed as dicts

remove_context(name_or_alias)

Remove a context from the registry and return it.

Notice that this methods will not disable the context. Use disable_contexts.

setup_matplotlib(enable=True)

Set up handlers for matplotlib’s unit support. :param enable: whether support should be enabled or disabled :type enable: bool

property sys
with_context(name, **kw)

Decorator to wrap a function call in a Pint context.

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

>>> @ureg.with_context('sp')
... def my_cool_fun(wavelenght):
...     print('This wavelength is equivalent to: %s', wavelength.to('terahertz'))
Parameters
  • names – name of the context.

  • kwargs – keyword arguments for the contexts.

Returns

the wrapped function.

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.

Use None to skip argument conversion. Set strict to False, to accept also numerical values.

Parameters
  • ureg – a UnitRegistry instance.

  • ret – output units.

  • args – iterable of input units.

  • strict – boolean to indicate that only quantities are accepted.

Returns

the wrapped function.

Raises

ValueError if strict and one of the arguments is not a Quantity.

class openscm.core.units.UnitConverter(source, target, context=None)

Bases: object

Converts numbers between two units.

__init__(source, target, context=None)

Initialize.

Parameters
  • source (str) – Unit to convert from

  • target (str) – Unit to convert to

  • context (Optional[str]) – Context to use for the conversion i.e. which metric to apply when performing CO2-equivalent calculations. If None, no metric will be applied and CO2-equivalent calculations will raise DimensionalityError.

Raises
  • pint.errors.DimensionalityError – Units cannot be converted into each other.

  • pint.errors.UndefinedUnitError – Unit undefined.

_offset = None

Offset for units (e.g. for temperature units)

_scaling = None

Scaling factor between units

_source = None

Source unit

_target = None

Target unit

property contexts

Available contexts for unit conversions

Return type

Sequence[str]

convert_from(v)

Convert value from source unit to target unit.

Parameters

value – Value in source unit

Returns

Value in target unit

Return type

Union[float, np.ndarray]

convert_to(v)

Convert value from target unit to source unit.

Parameters

value – Value in target unit

Returns

Value in source unit

Return type

Union[float, np.ndarray]

property source

Source unit

Return type

str

property target

Target unit

Return type

str

property unit_registry

Underlying unit registry

Return type

ScmUnitRegistry

openscm.core.units._unit_registry(input_string, case_sensitive=True, **values) = <openscm.core.units.ScmUnitRegistry object>

OpenSCM standard unit registry

The unit registry contains all of the recognised units.