quantities.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. """
  2. Physical quantities.
  3. """
  4. from sympy.core.expr import AtomicExpr
  5. from sympy.core.symbol import Symbol
  6. from sympy.core.sympify import sympify
  7. from sympy.physics.units.dimensions import _QuantityMapper
  8. from sympy.physics.units.prefixes import Prefix
  9. class Quantity(AtomicExpr):
  10. """
  11. Physical quantity: can be a unit of measure, a constant or a generic quantity.
  12. """
  13. is_commutative = True
  14. is_real = True
  15. is_number = False
  16. is_nonzero = True
  17. is_physical_constant = False
  18. _diff_wrt = True
  19. def __new__(cls, name, abbrev=None,
  20. latex_repr=None, pretty_unicode_repr=None,
  21. pretty_ascii_repr=None, mathml_presentation_repr=None,
  22. is_prefixed=False,
  23. **assumptions):
  24. if not isinstance(name, Symbol):
  25. name = Symbol(name)
  26. if abbrev is None:
  27. abbrev = name
  28. elif isinstance(abbrev, str):
  29. abbrev = Symbol(abbrev)
  30. # HACK: These are here purely for type checking. They actually get assigned below.
  31. cls._is_prefixed = is_prefixed
  32. obj = AtomicExpr.__new__(cls, name, abbrev)
  33. obj._name = name
  34. obj._abbrev = abbrev
  35. obj._latex_repr = latex_repr
  36. obj._unicode_repr = pretty_unicode_repr
  37. obj._ascii_repr = pretty_ascii_repr
  38. obj._mathml_repr = mathml_presentation_repr
  39. obj._is_prefixed = is_prefixed
  40. return obj
  41. def set_global_dimension(self, dimension):
  42. _QuantityMapper._quantity_dimension_global[self] = dimension
  43. def set_global_relative_scale_factor(self, scale_factor, reference_quantity):
  44. """
  45. Setting a scale factor that is valid across all unit system.
  46. """
  47. from sympy.physics.units import UnitSystem
  48. scale_factor = sympify(scale_factor)
  49. if isinstance(scale_factor, Prefix):
  50. self._is_prefixed = True
  51. # replace all prefixes by their ratio to canonical units:
  52. scale_factor = scale_factor.replace(
  53. lambda x: isinstance(x, Prefix),
  54. lambda x: x.scale_factor
  55. )
  56. scale_factor = sympify(scale_factor)
  57. UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity)
  58. UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity
  59. @property
  60. def name(self):
  61. return self._name
  62. @property
  63. def dimension(self):
  64. from sympy.physics.units import UnitSystem
  65. unit_system = UnitSystem.get_default_unit_system()
  66. return unit_system.get_quantity_dimension(self)
  67. @property
  68. def abbrev(self):
  69. """
  70. Symbol representing the unit name.
  71. Prepend the abbreviation with the prefix symbol if it is defines.
  72. """
  73. return self._abbrev
  74. @property
  75. def scale_factor(self):
  76. """
  77. Overall magnitude of the quantity as compared to the canonical units.
  78. """
  79. from sympy.physics.units import UnitSystem
  80. unit_system = UnitSystem.get_default_unit_system()
  81. return unit_system.get_quantity_scale_factor(self)
  82. def _eval_is_positive(self):
  83. return True
  84. def _eval_is_constant(self):
  85. return True
  86. def _eval_Abs(self):
  87. return self
  88. def _eval_subs(self, old, new):
  89. if isinstance(new, Quantity) and self != old:
  90. return self
  91. def _latex(self, printer):
  92. if self._latex_repr:
  93. return self._latex_repr
  94. else:
  95. return r'\text{{{}}}'.format(self.args[1] \
  96. if len(self.args) >= 2 else self.args[0])
  97. def convert_to(self, other, unit_system="SI"):
  98. """
  99. Convert the quantity to another quantity of same dimensions.
  100. Examples
  101. ========
  102. >>> from sympy.physics.units import speed_of_light, meter, second
  103. >>> speed_of_light
  104. speed_of_light
  105. >>> speed_of_light.convert_to(meter/second)
  106. 299792458*meter/second
  107. >>> from sympy.physics.units import liter
  108. >>> liter.convert_to(meter**3)
  109. meter**3/1000
  110. """
  111. from .util import convert_to
  112. return convert_to(self, other, unit_system)
  113. @property
  114. def free_symbols(self):
  115. """Return free symbols from quantity."""
  116. return set()
  117. @property
  118. def is_prefixed(self):
  119. """Whether or not the quantity is prefixed. Eg. `kilogram` is prefixed, but `gram` is not."""
  120. return self._is_prefixed
  121. class PhysicalConstant(Quantity):
  122. """Represents a physical constant, eg. `speed_of_light` or `avogadro_constant`."""
  123. is_physical_constant = True