prefixes.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. """
  2. Module defining unit prefixe class and some constants.
  3. Constant dict for SI and binary prefixes are defined as PREFIXES and
  4. BIN_PREFIXES.
  5. """
  6. from sympy.core.expr import Expr
  7. from sympy.core.sympify import sympify
  8. class Prefix(Expr):
  9. """
  10. This class represent prefixes, with their name, symbol and factor.
  11. Prefixes are used to create derived units from a given unit. They should
  12. always be encapsulated into units.
  13. The factor is constructed from a base (default is 10) to some power, and
  14. it gives the total multiple or fraction. For example the kilometer km
  15. is constructed from the meter (factor 1) and the kilo (10 to the power 3,
  16. i.e. 1000). The base can be changed to allow e.g. binary prefixes.
  17. A prefix multiplied by something will always return the product of this
  18. other object times the factor, except if the other object:
  19. - is a prefix and they can be combined into a new prefix;
  20. - defines multiplication with prefixes (which is the case for the Unit
  21. class).
  22. """
  23. _op_priority = 13.0
  24. is_commutative = True
  25. def __new__(cls, name, abbrev, exponent, base=sympify(10)):
  26. name = sympify(name)
  27. abbrev = sympify(abbrev)
  28. exponent = sympify(exponent)
  29. base = sympify(base)
  30. obj = Expr.__new__(cls, name, abbrev, exponent, base)
  31. obj._name = name
  32. obj._abbrev = abbrev
  33. obj._scale_factor = base**exponent
  34. obj._exponent = exponent
  35. obj._base = base
  36. return obj
  37. @property
  38. def name(self):
  39. return self._name
  40. @property
  41. def abbrev(self):
  42. return self._abbrev
  43. @property
  44. def scale_factor(self):
  45. return self._scale_factor
  46. @property
  47. def base(self):
  48. return self._base
  49. def __str__(self):
  50. # TODO: add proper printers and tests:
  51. if self.base == 10:
  52. return "Prefix(%r, %r, %r)" % (
  53. str(self.name), str(self.abbrev), self._exponent)
  54. else:
  55. return "Prefix(%r, %r, %r, %r)" % (
  56. str(self.name), str(self.abbrev), self._exponent, self.base)
  57. __repr__ = __str__
  58. def __mul__(self, other):
  59. from sympy.physics.units import Quantity
  60. if not isinstance(other, (Quantity, Prefix)):
  61. return super().__mul__(other)
  62. fact = self.scale_factor * other.scale_factor
  63. if fact == 1:
  64. return 1
  65. elif isinstance(other, Prefix):
  66. # simplify prefix
  67. for p in PREFIXES:
  68. if PREFIXES[p].scale_factor == fact:
  69. return PREFIXES[p]
  70. return fact
  71. return self.scale_factor * other
  72. def __truediv__(self, other):
  73. if not hasattr(other, "scale_factor"):
  74. return super().__truediv__(other)
  75. fact = self.scale_factor / other.scale_factor
  76. if fact == 1:
  77. return 1
  78. elif isinstance(other, Prefix):
  79. for p in PREFIXES:
  80. if PREFIXES[p].scale_factor == fact:
  81. return PREFIXES[p]
  82. return fact
  83. return self.scale_factor / other
  84. def __rtruediv__(self, other):
  85. if other == 1:
  86. for p in PREFIXES:
  87. if PREFIXES[p].scale_factor == 1 / self.scale_factor:
  88. return PREFIXES[p]
  89. return other / self.scale_factor
  90. def prefix_unit(unit, prefixes):
  91. """
  92. Return a list of all units formed by unit and the given prefixes.
  93. You can use the predefined PREFIXES or BIN_PREFIXES, but you can also
  94. pass as argument a subdict of them if you don't want all prefixed units.
  95. >>> from sympy.physics.units.prefixes import (PREFIXES,
  96. ... prefix_unit)
  97. >>> from sympy.physics.units import m
  98. >>> pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]}
  99. >>> prefix_unit(m, pref) # doctest: +SKIP
  100. [millimeter, centimeter, decimeter]
  101. """
  102. from sympy.physics.units.quantities import Quantity
  103. from sympy.physics.units import UnitSystem
  104. prefixed_units = []
  105. for prefix_abbr, prefix in prefixes.items():
  106. quantity = Quantity(
  107. "%s%s" % (prefix.name, unit.name),
  108. abbrev=("%s%s" % (prefix.abbrev, unit.abbrev))
  109. )
  110. UnitSystem._quantity_dimensional_equivalence_map_global[quantity] = unit
  111. UnitSystem._quantity_scale_factors_global[quantity] = (prefix.scale_factor, unit)
  112. prefixed_units.append(quantity)
  113. return prefixed_units
  114. yotta = Prefix('yotta', 'Y', 24)
  115. zetta = Prefix('zetta', 'Z', 21)
  116. exa = Prefix('exa', 'E', 18)
  117. peta = Prefix('peta', 'P', 15)
  118. tera = Prefix('tera', 'T', 12)
  119. giga = Prefix('giga', 'G', 9)
  120. mega = Prefix('mega', 'M', 6)
  121. kilo = Prefix('kilo', 'k', 3)
  122. hecto = Prefix('hecto', 'h', 2)
  123. deca = Prefix('deca', 'da', 1)
  124. deci = Prefix('deci', 'd', -1)
  125. centi = Prefix('centi', 'c', -2)
  126. milli = Prefix('milli', 'm', -3)
  127. micro = Prefix('micro', 'mu', -6)
  128. nano = Prefix('nano', 'n', -9)
  129. pico = Prefix('pico', 'p', -12)
  130. femto = Prefix('femto', 'f', -15)
  131. atto = Prefix('atto', 'a', -18)
  132. zepto = Prefix('zepto', 'z', -21)
  133. yocto = Prefix('yocto', 'y', -24)
  134. # http://physics.nist.gov/cuu/Units/prefixes.html
  135. PREFIXES = {
  136. 'Y': yotta,
  137. 'Z': zetta,
  138. 'E': exa,
  139. 'P': peta,
  140. 'T': tera,
  141. 'G': giga,
  142. 'M': mega,
  143. 'k': kilo,
  144. 'h': hecto,
  145. 'da': deca,
  146. 'd': deci,
  147. 'c': centi,
  148. 'm': milli,
  149. 'mu': micro,
  150. 'n': nano,
  151. 'p': pico,
  152. 'f': femto,
  153. 'a': atto,
  154. 'z': zepto,
  155. 'y': yocto,
  156. }
  157. kibi = Prefix('kibi', 'Y', 10, 2)
  158. mebi = Prefix('mebi', 'Y', 20, 2)
  159. gibi = Prefix('gibi', 'Y', 30, 2)
  160. tebi = Prefix('tebi', 'Y', 40, 2)
  161. pebi = Prefix('pebi', 'Y', 50, 2)
  162. exbi = Prefix('exbi', 'Y', 60, 2)
  163. # http://physics.nist.gov/cuu/Units/binary.html
  164. BIN_PREFIXES = {
  165. 'Ki': kibi,
  166. 'Mi': mebi,
  167. 'Gi': gibi,
  168. 'Ti': tebi,
  169. 'Pi': pebi,
  170. 'Ei': exbi,
  171. }