wc_utils/util/units.py
""" Utilities for dealing with units
:Author: Jonathan <jonrkarr@gmail.com>
:Date: 2017-05-29
:Copyright: 2017-2018, Karr Lab
:License: MIT
"""
import operator
import os
import pint
import pkg_resources
DEFAULT_UNIT_DEFINITION_FILENAME = pkg_resources.resource_filename('wc_utils', 'util/units.txt')
def get_unit_registry(base_filename='', extra_filenames=None):
""" Get a unit registry
Args:
base_filename (:obj:`str`, optional): Path to base unit system definition. If :obj:`None`, the
default pint unit system will be used
extra_filenames (:obj:`list` of :obj:`str`, optional): List of paths to additional unit definitions
beyond the base unit system definition
Returns:
:obj:`pint.UnitRegistry`: unit registry
"""
unit_registry = pint.UnitRegistry(base_filename)
extra_filenames = extra_filenames or []
for extra_filename in extra_filenames:
unit_registry = pint.UnitRegistry()
unit_registry.load_definitions(extra_filename)
return unit_registry
unit_registry = get_unit_registry(extra_filenames=[DEFAULT_UNIT_DEFINITION_FILENAME])
# :obj:`pint.UnitRegistry`: unit registry
def are_units_equivalent(units1, units2, check_same_magnitude=True):
""" Determine if two units are equivalent
Args:
units1 (:obj:`pint.unit._Unit`): units
units2 (:obj:`pint.unit._Unit`): other units
check_same_magnitude (:obj:`bool`, optional): if :obj:`True`, units are only equivalent if they
have the same magnitude
Returns:
:obj:`bool`: :obj:`True` if the units are equivalent
"""
if units1 is None:
if units2 is None:
return True
return False
else:
if units2 is None:
return False
else:
if not isinstance(units1, (pint.unit._Unit, pint.quantity._Quantity)):
return False
registry = units1._REGISTRY
if not isinstance(units2, (registry.Unit, registry.Quantity)):
return False
if units1 == units2:
return True
units1_expr = registry.parse_expression(str(units1))
units2_expr = registry.parse_expression(str(units2))
if check_same_magnitude:
try:
return units1_expr.compare(units2_expr, operator.eq) or \
(abs(units1_expr.to(units2_expr).magnitude - 1) < 1e-12)
except pint.DimensionalityError:
return False
else:
return units1_expr.check(units2_expr)