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

109 statements  

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

1""" 

2Module defining unit prefixe class and some constants. 

3 

4Constant dict for SI and binary prefixes are defined as PREFIXES and 

5BIN_PREFIXES. 

6""" 

7from sympy.core.expr import Expr 

8from sympy.core.sympify import sympify 

9 

10 

11class Prefix(Expr): 

12 """ 

13 This class represent prefixes, with their name, symbol and factor. 

14 

15 Prefixes are used to create derived units from a given unit. They should 

16 always be encapsulated into units. 

17 

18 The factor is constructed from a base (default is 10) to some power, and 

19 it gives the total multiple or fraction. For example the kilometer km 

20 is constructed from the meter (factor 1) and the kilo (10 to the power 3, 

21 i.e. 1000). The base can be changed to allow e.g. binary prefixes. 

22 

23 A prefix multiplied by something will always return the product of this 

24 other object times the factor, except if the other object: 

25 

26 - is a prefix and they can be combined into a new prefix; 

27 - defines multiplication with prefixes (which is the case for the Unit 

28 class). 

29 """ 

30 _op_priority = 13.0 

31 is_commutative = True 

32 

33 def __new__(cls, name, abbrev, exponent, base=sympify(10), latex_repr=None): 

34 

35 name = sympify(name) 

36 abbrev = sympify(abbrev) 

37 exponent = sympify(exponent) 

38 base = sympify(base) 

39 

40 obj = Expr.__new__(cls, name, abbrev, exponent, base) 

41 obj._name = name 

42 obj._abbrev = abbrev 

43 obj._scale_factor = base**exponent 

44 obj._exponent = exponent 

45 obj._base = base 

46 obj._latex_repr = latex_repr 

47 return obj 

48 

49 @property 

50 def name(self): 

51 return self._name 

52 

53 @property 

54 def abbrev(self): 

55 return self._abbrev 

56 

57 @property 

58 def scale_factor(self): 

59 return self._scale_factor 

60 

61 def _latex(self, printer): 

62 if self._latex_repr is None: 

63 return r'\text{%s}' % self._abbrev 

64 return self._latex_repr 

65 

66 @property 

67 def base(self): 

68 return self._base 

69 

70 def __str__(self): 

71 return str(self._abbrev) 

72 

73 def __repr__(self): 

74 if self.base == 10: 

75 return "Prefix(%r, %r, %r)" % ( 

76 str(self.name), str(self.abbrev), self._exponent) 

77 else: 

78 return "Prefix(%r, %r, %r, %r)" % ( 

79 str(self.name), str(self.abbrev), self._exponent, self.base) 

80 

81 def __mul__(self, other): 

82 from sympy.physics.units import Quantity 

83 if not isinstance(other, (Quantity, Prefix)): 

84 return super().__mul__(other) 

85 

86 fact = self.scale_factor * other.scale_factor 

87 

88 if fact == 1: 

89 return 1 

90 elif isinstance(other, Prefix): 

91 # simplify prefix 

92 for p in PREFIXES: 

93 if PREFIXES[p].scale_factor == fact: 

94 return PREFIXES[p] 

95 return fact 

96 

97 return self.scale_factor * other 

98 

99 def __truediv__(self, other): 

100 if not hasattr(other, "scale_factor"): 

101 return super().__truediv__(other) 

102 

103 fact = self.scale_factor / other.scale_factor 

104 

105 if fact == 1: 

106 return 1 

107 elif isinstance(other, Prefix): 

108 for p in PREFIXES: 

109 if PREFIXES[p].scale_factor == fact: 

110 return PREFIXES[p] 

111 return fact 

112 

113 return self.scale_factor / other 

114 

115 def __rtruediv__(self, other): 

116 if other == 1: 

117 for p in PREFIXES: 

118 if PREFIXES[p].scale_factor == 1 / self.scale_factor: 

119 return PREFIXES[p] 

120 return other / self.scale_factor 

121 

122 

123def prefix_unit(unit, prefixes): 

124 """ 

125 Return a list of all units formed by unit and the given prefixes. 

126 

127 You can use the predefined PREFIXES or BIN_PREFIXES, but you can also 

128 pass as argument a subdict of them if you do not want all prefixed units. 

129 

130 >>> from sympy.physics.units.prefixes import (PREFIXES, 

131 ... prefix_unit) 

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

133 >>> pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]} 

134 >>> prefix_unit(m, pref) # doctest: +SKIP 

135 [millimeter, centimeter, decimeter] 

136 """ 

137 

138 from sympy.physics.units.quantities import Quantity 

139 from sympy.physics.units import UnitSystem 

140 

141 prefixed_units = [] 

142 

143 for prefix_abbr, prefix in prefixes.items(): 

144 quantity = Quantity( 

145 "%s%s" % (prefix.name, unit.name), 

146 abbrev=("%s%s" % (prefix.abbrev, unit.abbrev)), 

147 is_prefixed=True, 

148 ) 

149 UnitSystem._quantity_dimensional_equivalence_map_global[quantity] = unit 

150 UnitSystem._quantity_scale_factors_global[quantity] = (prefix.scale_factor, unit) 

151 prefixed_units.append(quantity) 

152 

153 return prefixed_units 

154 

155 

156yotta = Prefix('yotta', 'Y', 24) 

157zetta = Prefix('zetta', 'Z', 21) 

158exa = Prefix('exa', 'E', 18) 

159peta = Prefix('peta', 'P', 15) 

160tera = Prefix('tera', 'T', 12) 

161giga = Prefix('giga', 'G', 9) 

162mega = Prefix('mega', 'M', 6) 

163kilo = Prefix('kilo', 'k', 3) 

164hecto = Prefix('hecto', 'h', 2) 

165deca = Prefix('deca', 'da', 1) 

166deci = Prefix('deci', 'd', -1) 

167centi = Prefix('centi', 'c', -2) 

168milli = Prefix('milli', 'm', -3) 

169micro = Prefix('micro', 'mu', -6, latex_repr=r"\mu") 

170nano = Prefix('nano', 'n', -9) 

171pico = Prefix('pico', 'p', -12) 

172femto = Prefix('femto', 'f', -15) 

173atto = Prefix('atto', 'a', -18) 

174zepto = Prefix('zepto', 'z', -21) 

175yocto = Prefix('yocto', 'y', -24) 

176 

177 

178# https://physics.nist.gov/cuu/Units/prefixes.html 

179PREFIXES = { 

180 'Y': yotta, 

181 'Z': zetta, 

182 'E': exa, 

183 'P': peta, 

184 'T': tera, 

185 'G': giga, 

186 'M': mega, 

187 'k': kilo, 

188 'h': hecto, 

189 'da': deca, 

190 'd': deci, 

191 'c': centi, 

192 'm': milli, 

193 'mu': micro, 

194 'n': nano, 

195 'p': pico, 

196 'f': femto, 

197 'a': atto, 

198 'z': zepto, 

199 'y': yocto, 

200} 

201 

202 

203kibi = Prefix('kibi', 'Y', 10, 2) 

204mebi = Prefix('mebi', 'Y', 20, 2) 

205gibi = Prefix('gibi', 'Y', 30, 2) 

206tebi = Prefix('tebi', 'Y', 40, 2) 

207pebi = Prefix('pebi', 'Y', 50, 2) 

208exbi = Prefix('exbi', 'Y', 60, 2) 

209 

210 

211# https://physics.nist.gov/cuu/Units/binary.html 

212BIN_PREFIXES = { 

213 'Ki': kibi, 

214 'Mi': mebi, 

215 'Gi': gibi, 

216 'Ti': tebi, 

217 'Pi': pebi, 

218 'Ei': exbi, 

219}