Coverage for /usr/lib/python3/dist-packages/sympy/physics/units/quantities.py: 81%

80 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1""" 

2Physical quantities. 

3""" 

4 

5from sympy.core.expr import AtomicExpr 

6from sympy.core.symbol import Symbol 

7from sympy.core.sympify import sympify 

8from sympy.physics.units.dimensions import _QuantityMapper 

9from sympy.physics.units.prefixes import Prefix 

10 

11 

12class Quantity(AtomicExpr): 

13 """ 

14 Physical quantity: can be a unit of measure, a constant or a generic quantity. 

15 """ 

16 

17 is_commutative = True 

18 is_real = True 

19 is_number = False 

20 is_nonzero = True 

21 is_physical_constant = False 

22 _diff_wrt = True 

23 

24 def __new__(cls, name, abbrev=None, 

25 latex_repr=None, pretty_unicode_repr=None, 

26 pretty_ascii_repr=None, mathml_presentation_repr=None, 

27 is_prefixed=False, 

28 **assumptions): 

29 

30 if not isinstance(name, Symbol): 

31 name = Symbol(name) 

32 

33 if abbrev is None: 

34 abbrev = name 

35 elif isinstance(abbrev, str): 

36 abbrev = Symbol(abbrev) 

37 

38 # HACK: These are here purely for type checking. They actually get assigned below. 

39 cls._is_prefixed = is_prefixed 

40 

41 obj = AtomicExpr.__new__(cls, name, abbrev) 

42 obj._name = name 

43 obj._abbrev = abbrev 

44 obj._latex_repr = latex_repr 

45 obj._unicode_repr = pretty_unicode_repr 

46 obj._ascii_repr = pretty_ascii_repr 

47 obj._mathml_repr = mathml_presentation_repr 

48 obj._is_prefixed = is_prefixed 

49 return obj 

50 

51 def set_global_dimension(self, dimension): 

52 _QuantityMapper._quantity_dimension_global[self] = dimension 

53 

54 def set_global_relative_scale_factor(self, scale_factor, reference_quantity): 

55 """ 

56 Setting a scale factor that is valid across all unit system. 

57 """ 

58 from sympy.physics.units import UnitSystem 

59 scale_factor = sympify(scale_factor) 

60 if isinstance(scale_factor, Prefix): 

61 self._is_prefixed = True 

62 # replace all prefixes by their ratio to canonical units: 

63 scale_factor = scale_factor.replace( 

64 lambda x: isinstance(x, Prefix), 

65 lambda x: x.scale_factor 

66 ) 

67 scale_factor = sympify(scale_factor) 

68 UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity) 

69 UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity 

70 

71 @property 

72 def name(self): 

73 return self._name 

74 

75 @property 

76 def dimension(self): 

77 from sympy.physics.units import UnitSystem 

78 unit_system = UnitSystem.get_default_unit_system() 

79 return unit_system.get_quantity_dimension(self) 

80 

81 @property 

82 def abbrev(self): 

83 """ 

84 Symbol representing the unit name. 

85 

86 Prepend the abbreviation with the prefix symbol if it is defines. 

87 """ 

88 return self._abbrev 

89 

90 @property 

91 def scale_factor(self): 

92 """ 

93 Overall magnitude of the quantity as compared to the canonical units. 

94 """ 

95 from sympy.physics.units import UnitSystem 

96 unit_system = UnitSystem.get_default_unit_system() 

97 return unit_system.get_quantity_scale_factor(self) 

98 

99 def _eval_is_positive(self): 

100 return True 

101 

102 def _eval_is_constant(self): 

103 return True 

104 

105 def _eval_Abs(self): 

106 return self 

107 

108 def _eval_subs(self, old, new): 

109 if isinstance(new, Quantity) and self != old: 

110 return self 

111 

112 def _latex(self, printer): 

113 if self._latex_repr: 

114 return self._latex_repr 

115 else: 

116 return r'\text{{{}}}'.format(self.args[1] \ 

117 if len(self.args) >= 2 else self.args[0]) 

118 

119 def convert_to(self, other, unit_system="SI"): 

120 """ 

121 Convert the quantity to another quantity of same dimensions. 

122 

123 Examples 

124 ======== 

125 

126 >>> from sympy.physics.units import speed_of_light, meter, second 

127 >>> speed_of_light 

128 speed_of_light 

129 >>> speed_of_light.convert_to(meter/second) 

130 299792458*meter/second 

131 

132 >>> from sympy.physics.units import liter 

133 >>> liter.convert_to(meter**3) 

134 meter**3/1000 

135 """ 

136 from .util import convert_to 

137 return convert_to(self, other, unit_system) 

138 

139 @property 

140 def free_symbols(self): 

141 """Return free symbols from quantity.""" 

142 return set() 

143 

144 @property 

145 def is_prefixed(self): 

146 """Whether or not the quantity is prefixed. Eg. `kilogram` is prefixed, but `gram` is not.""" 

147 return self._is_prefixed 

148 

149class PhysicalConstant(Quantity): 

150 """Represents a physical constant, eg. `speed_of_light` or `avogadro_constant`.""" 

151 

152 is_physical_constant = True