"""""" # Standard library modules. from __future__ import absolute_import, division, print_function, unicode_literals from operator import itemgetter import bisect # Third party modules. # Local modules. # Globals and constants variables. _PREFIXES_FACTORS = {'Y': 1e24, 'Z': 1e21, 'E': 1e18, 'P': 1e15, 'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'd': 1e-1, 'c': 1e-2, 'm': 1e-3, u'\u00b5': 1e-6, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15, 'a': 1e-18, 'z': 1e-21, 'y': 1e-24} class _Dimension(object): def __init__(self, base_units, latexrepr=None): self._base_units = base_units self._units = {base_units: 1.0} if latexrepr is None: latexrepr = base_units self._latexrepr = {base_units: latexrepr} def add_units(self, units, factor, latexrepr=None): """ Add new possible units. :arg units: units :type units: :class:`str` :arg factor: multiplication factor to convert new units into base units :type factor: :class:`float` :arg latexrepr: LaTeX representation of units (if ``None``, use *units) :type latexrepr: :class:`str` """ if units in self._units: raise ValueError('%s already defined' % units) if factor == 1: raise ValueError('Factor cannot be equal to 1') if latexrepr is None: latexrepr = units self._units[units] = factor self._latexrepr[units] = latexrepr def is_valid_units(self, units): return units in self._units and units in self._latexrepr def calculate_preferred(self, value, units): if units not in self._units: raise ValueError('Unknown units: %s' % units) base_value = value * self._units[units] units_factor = sorted(self._units.items(), key=itemgetter(1)) factors = [item[1] for item in units_factor] index = bisect.bisect_right(factors, base_value) newunits, factor = units_factor[index - 1] return base_value / factor, newunits def to_latex(self, units): if units not in self._latexrepr: raise ValueError('Unknown units: %s' % units) return self._latexrepr[units] @property def base_units(self): return self._base_units class SILengthDimension(_Dimension): def __init__(self): super(SILengthDimension, self).__init__('m') for prefix, factor in _PREFIXES_FACTORS.items(): latexrepr = None if prefix == u'\u00b5': latexrepr = '$\\mu$m' self.add_units(prefix + 'm', factor, latexrepr) class SILengthReciprocalDimension(_Dimension): def __init__(self): super(SILengthReciprocalDimension, self).__init__('1/m', 'm$^{-1}$') for prefix, factor in _PREFIXES_FACTORS.items(): latexrepr = '{0}m$^{{-1}}$'.format(prefix) if prefix == u'\u00b5': latexrepr = '$\\mu$m$^{-1}$' self.add_units('1/{0}m'.format(prefix), factor, latexrepr) class ImperialLengthDimension(_Dimension): def __init__(self): super(ImperialLengthDimension, self).__init__('ft') self.add_units('th', 1 / 12000) self.add_units('in', 1 / 12) self.add_units('yd', 3) self.add_units('ch', 66) self.add_units('fur', 660) self.add_units('mi', 5280) self.add_units('lea', 15840)