图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
8.2 KiB

  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. from sympy.utilities.exceptions import (sympy_deprecation_warning,
  10. SymPyDeprecationWarning,
  11. ignore_warnings)
  12. class Quantity(AtomicExpr):
  13. """
  14. Physical quantity: can be a unit of measure, a constant or a generic quantity.
  15. """
  16. is_commutative = True
  17. is_real = True
  18. is_number = False
  19. is_nonzero = True
  20. _diff_wrt = True
  21. def __new__(cls, name, abbrev=None, dimension=None, scale_factor=None,
  22. latex_repr=None, pretty_unicode_repr=None,
  23. pretty_ascii_repr=None, mathml_presentation_repr=None,
  24. **assumptions):
  25. if not isinstance(name, Symbol):
  26. name = Symbol(name)
  27. # For Quantity(name, dim, scale, abbrev) to work like in the
  28. # old version of SymPy:
  29. if not isinstance(abbrev, str) and not \
  30. isinstance(abbrev, Symbol):
  31. dimension, scale_factor, abbrev = abbrev, dimension, scale_factor
  32. if dimension is not None:
  33. sympy_deprecation_warning(
  34. """
  35. The 'dimension' argument to to Quantity() is deprecated.
  36. Instead use the unit_system.set_quantity_dimension() method.
  37. """,
  38. deprecated_since_version="1.3",
  39. active_deprecations_target="deprecated-quantity-dimension-scale-factor"
  40. )
  41. if scale_factor is not None:
  42. sympy_deprecation_warning(
  43. """
  44. The 'scale_factor' argument to to Quantity() is deprecated.
  45. Instead use the unit_system.set_quantity_scale_factors()
  46. method.
  47. """,
  48. deprecated_since_version="1.3",
  49. active_deprecations_target="deprecated-quantity-dimension-scale-factor"
  50. )
  51. if abbrev is None:
  52. abbrev = name
  53. elif isinstance(abbrev, str):
  54. abbrev = Symbol(abbrev)
  55. obj = AtomicExpr.__new__(cls, name, abbrev)
  56. obj._name = name
  57. obj._abbrev = abbrev
  58. obj._latex_repr = latex_repr
  59. obj._unicode_repr = pretty_unicode_repr
  60. obj._ascii_repr = pretty_ascii_repr
  61. obj._mathml_repr = mathml_presentation_repr
  62. if dimension is not None:
  63. # TODO: remove after deprecation:
  64. with ignore_warnings(SymPyDeprecationWarning):
  65. obj.set_dimension(dimension)
  66. if scale_factor is not None:
  67. # TODO: remove after deprecation:
  68. with ignore_warnings(SymPyDeprecationWarning):
  69. obj.set_scale_factor(scale_factor)
  70. return obj
  71. def set_dimension(self, dimension, unit_system="SI"):
  72. sympy_deprecation_warning(
  73. f"""
  74. Quantity.set_dimension() is deprecated. Use either
  75. unit_system.set_quantity_dimension() or
  76. {self}.set_global_dimension() instead.
  77. """,
  78. deprecated_since_version="1.5",
  79. active_deprecations_target="deprecated-quantity-methods",
  80. )
  81. from sympy.physics.units import UnitSystem
  82. unit_system = UnitSystem.get_unit_system(unit_system)
  83. unit_system.set_quantity_dimension(self, dimension)
  84. def set_scale_factor(self, scale_factor, unit_system="SI"):
  85. sympy_deprecation_warning(
  86. f"""
  87. Quantity.set_scale_factor() is deprecated. Use either
  88. unit_system.set_quantity_scale_factors() or
  89. {self}.set_global_relative_scale_factor() instead.
  90. """,
  91. deprecated_since_version="1.5",
  92. active_deprecations_target="deprecated-quantity-methods",
  93. )
  94. from sympy.physics.units import UnitSystem
  95. unit_system = UnitSystem.get_unit_system(unit_system)
  96. unit_system.set_quantity_scale_factor(self, scale_factor)
  97. def set_global_dimension(self, dimension):
  98. _QuantityMapper._quantity_dimension_global[self] = dimension
  99. def set_global_relative_scale_factor(self, scale_factor, reference_quantity):
  100. """
  101. Setting a scale factor that is valid across all unit system.
  102. """
  103. from sympy.physics.units import UnitSystem
  104. scale_factor = sympify(scale_factor)
  105. # replace all prefixes by their ratio to canonical units:
  106. scale_factor = scale_factor.replace(
  107. lambda x: isinstance(x, Prefix),
  108. lambda x: x.scale_factor
  109. )
  110. scale_factor = sympify(scale_factor)
  111. UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity)
  112. UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity
  113. @property
  114. def name(self):
  115. return self._name
  116. @property
  117. def dimension(self):
  118. from sympy.physics.units import UnitSystem
  119. unit_system = UnitSystem.get_default_unit_system()
  120. return unit_system.get_quantity_dimension(self)
  121. @property
  122. def abbrev(self):
  123. """
  124. Symbol representing the unit name.
  125. Prepend the abbreviation with the prefix symbol if it is defines.
  126. """
  127. return self._abbrev
  128. @property
  129. def scale_factor(self):
  130. """
  131. Overall magnitude of the quantity as compared to the canonical units.
  132. """
  133. from sympy.physics.units import UnitSystem
  134. unit_system = UnitSystem.get_default_unit_system()
  135. return unit_system.get_quantity_scale_factor(self)
  136. def _eval_is_positive(self):
  137. return True
  138. def _eval_is_constant(self):
  139. return True
  140. def _eval_Abs(self):
  141. return self
  142. def _eval_subs(self, old, new):
  143. if isinstance(new, Quantity) and self != old:
  144. return self
  145. @staticmethod
  146. def get_dimensional_expr(expr, unit_system="SI"):
  147. sympy_deprecation_warning(
  148. """
  149. Quantity.get_dimensional_expr() is deprecated. It is now
  150. associated with UnitSystem objects. The dimensional relations
  151. depend on the unit system used. Use
  152. unit_system.get_dimensional_expr() instead.
  153. """,
  154. deprecated_since_version="1.5",
  155. active_deprecations_target="deprecated-quantity-methods",
  156. )
  157. from sympy.physics.units import UnitSystem
  158. unit_system = UnitSystem.get_unit_system(unit_system)
  159. return unit_system.get_dimensional_expr(expr)
  160. @staticmethod
  161. def _collect_factor_and_dimension(expr, unit_system="SI"):
  162. """Return tuple with scale factor expression and dimension expression."""
  163. sympy_deprecation_warning(
  164. """
  165. Quantity._collect_factor_and_dimension() is deprecated. This
  166. method has been moved to the UnitSystem class. Use
  167. unit_system._collect_factor_and_dimension(expr) instead.
  168. """,
  169. deprecated_since_version="1.5",
  170. active_deprecations_target="deprecated-quantity-methods",
  171. )
  172. from sympy.physics.units import UnitSystem
  173. unit_system = UnitSystem.get_unit_system(unit_system)
  174. return unit_system._collect_factor_and_dimension(expr)
  175. def _latex(self, printer):
  176. if self._latex_repr:
  177. return self._latex_repr
  178. else:
  179. return r'\text{{{}}}'.format(self.args[1] \
  180. if len(self.args) >= 2 else self.args[0])
  181. def convert_to(self, other, unit_system="SI"):
  182. """
  183. Convert the quantity to another quantity of same dimensions.
  184. Examples
  185. ========
  186. >>> from sympy.physics.units import speed_of_light, meter, second
  187. >>> speed_of_light
  188. speed_of_light
  189. >>> speed_of_light.convert_to(meter/second)
  190. 299792458*meter/second
  191. >>> from sympy.physics.units import liter
  192. >>> liter.convert_to(meter**3)
  193. meter**3/1000
  194. """
  195. from .util import convert_to
  196. return convert_to(self, other, unit_system)
  197. @property
  198. def free_symbols(self):
  199. """Return free symbols from quantity."""
  200. return set()