Skip to content

Commit c19bc89

Browse files
authored
Merge branch 'master' into 26_06_enable_checking_in_python
2 parents d252c17 + bf752a5 commit c19bc89

8 files changed

Lines changed: 1284 additions & 0 deletions

File tree

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import math
2+
3+
class Unit():
4+
numerator : list
5+
denumerator : list
6+
ratio : float
7+
8+
9+
def getKey(self):
10+
key = {"num" : {}, "denum" : {}}
11+
for unit in self.numerator:
12+
if unit.abrev in key["num"]:
13+
key["num"][unit.abrev] += 1
14+
else:
15+
key["num"][unit.abrev] = 1
16+
for unit in self.denumerator:
17+
if unit.abrev in key["denum"]:
18+
key["denum"][unit.abrev] += 1
19+
else:
20+
key["denum"][unit.abrev] = 1
21+
return key
22+
23+
def __eq__ (self, other):
24+
if not isinstance(other, Unit):
25+
return NotImplemented
26+
27+
if int(math.log10(self.ratio)) != int(math.log10(other.ratio)) :
28+
return False
29+
30+
return self.getKey() == other.getKey()
31+
32+
33+
def __mul__(self, other):
34+
if isinstance(other, Unit):
35+
return DerivedUnit(numerator=self.numerator + other.numerator, denumerator= self.denumerator + other.denumerator, ratio = self.ratio * other.ratio)
36+
else:
37+
return DimensionnedValue(other,self )
38+
39+
40+
def __rmul__(self, other ):
41+
return self.__mul__(other)
42+
43+
def __pow__(self, other : int):
44+
if not isinstance(other, int):
45+
raise ValueError
46+
47+
targetNum = []
48+
targetDenum = []
49+
targetRatio = 1.0
50+
51+
for i in range(abs(other)):
52+
targetNum += self.numerator
53+
targetDenum += self.denumerator
54+
targetRatio *= self.ratio
55+
56+
if other < 0 :
57+
return DerivedUnit(numerator=targetDenum, denumerator= targetNum, ratio = 1.0/targetRatio)
58+
elif other > 0 :
59+
return DerivedUnit(numerator=targetNum, denumerator= targetDenum, ratio = targetRatio)
60+
else:
61+
return NeutralUnit()
62+
63+
def __truediv__(self, other ):
64+
if not isinstance(other, Unit):
65+
return NotImplemented
66+
67+
return DerivedUnit(numerator=self.numerator + other.denumerator, denumerator= self.denumerator + other.numerator, ratio = self.ratio / other.ratio)
68+
69+
def toString(self, addRatio : bool = True):
70+
self_key = self.getKey()
71+
72+
def side(units: dict) -> str:
73+
return " * ".join(
74+
k if exp == 1 else f"{k}^{exp}"
75+
for k, exp in units.items()
76+
)
77+
78+
num = side(self_key["num"])
79+
denum = side(self_key["denum"])
80+
81+
num_s = f"( {num} ) " if num else "1"
82+
denum_s = f"/ ( {denum} )" if denum else ""
83+
84+
prefix = f"{self.ratio} * " if addRatio else ""
85+
return prefix + num_s + denum_s
86+
87+
88+
def __str__(self):
89+
return self.toString()
90+
91+
def __hash__(self):
92+
key = self.getKey()
93+
return hash((
94+
frozenset(key["num"].items()),
95+
frozenset(key["denum"].items()),
96+
int(math.log10(self.ratio)),
97+
))
98+
99+
class NeutralUnit(Unit):
100+
def __init__(self):
101+
self.numerator = []
102+
self.denumerator = []
103+
self.ratio = 1.0
104+
105+
def __str__(self):
106+
return "1"
107+
108+
109+
class PrimaryUnit(Unit):
110+
111+
abrev = str
112+
113+
def __init__(self, abrev : str):
114+
self.abrev = abrev
115+
self.numerator = [self]
116+
self.denumerator = []
117+
self.ratio = 1.0
118+
119+
120+
121+
class DerivedUnit(Unit):
122+
123+
def __init__(self, numerator : list[PrimaryUnit], denumerator : list[PrimaryUnit], ratio : float):
124+
self.numerator = numerator
125+
self.denumerator = denumerator
126+
self.ratio = ratio
127+
128+
self.simplify()
129+
130+
131+
def simplify(self):
132+
futNum = []
133+
for unit in self.numerator:
134+
simplified = False
135+
for i in range(len(self.denumerator)):
136+
if self.denumerator[i].abrev == unit.abrev:
137+
simplified = True
138+
self.denumerator.pop(i)
139+
break
140+
if not(simplified):
141+
futNum.append(unit)
142+
self.numerator = futNum
143+
144+
145+
class ScaledUnit(Unit):
146+
147+
def __init__(self, unit : Unit, ratio : float):
148+
self.numerator = unit.numerator.copy()
149+
self.denumerator = unit.denumerator.copy()
150+
self.ratio = ratio
151+
152+
153+
class DimensionnedValue():
154+
155+
value : float
156+
unit : Unit
157+
158+
def __init__(self, value : float, unit : Unit):
159+
self.value = value
160+
self.unit = unit
161+
162+
def __eq__ (self, other):
163+
if not isinstance(other, DimensionnedValue):
164+
raise TypeError("Dimensionned values can only be compared to other dimensionned values")
165+
166+
167+
if self.unit.getKey() != other.unit.getKey():
168+
raise TypeError("Only values that share the same units can be compared")
169+
170+
return math.isclose(self.value * self.unit.ratio, other.value * other.unit.ratio)
171+
172+
173+
def __mul__(self, other):
174+
if isinstance(other, DimensionnedValue):
175+
return DimensionnedValue(self.value * other.value,self.unit * other.unit)
176+
elif isinstance(other, Unit) :
177+
return DimensionnedValue(self.value ,self.unit * other)
178+
else :
179+
return DimensionnedValue(self.value * other,self.unit)
180+
181+
def __rmul__(self, other ):
182+
return self.__mul__(other)
183+
184+
def __pow__(self, other : int):
185+
if not isinstance(other, int):
186+
raise ValueError
187+
188+
return DimensionnedValue(self.value ** other, self.unit**other)
189+
190+
def __truediv__(self, other):
191+
if isinstance(other, DimensionnedValue):
192+
return DimensionnedValue(self.value / other.value, self.unit / other.unit)
193+
elif isinstance(other, Unit) :
194+
return DimensionnedValue(self.value, self.unit / other)
195+
else:
196+
return DimensionnedValue(self.value / other, self.unit)
197+
198+
def __rtruediv__(self, other):
199+
if isinstance(other, DimensionnedValue):
200+
return DimensionnedValue(other.value / self.value, other.unit / self.unit)
201+
elif isinstance(other, Unit):
202+
return DimensionnedValue(1.0 / self.value, other / self.unit)
203+
else:
204+
return DimensionnedValue(other / self.value, self.unit ** -1)
205+
206+
def __str__(self):
207+
return f"{self.value * self.unit.ratio} * " + self.unit.toString(False)
208+
209+
def __hash__(self):
210+
key = self.unit.getKey()
211+
return hash((
212+
frozenset(key["num"].items()),
213+
frozenset(key["denum"].items()),
214+
round(self.value * self.unit.ratio, 9) # normalized magnitude
215+
))
216+
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
from .Core import *
2+
3+
4+
### Primary units
5+
DimensionLess = NeutralUnit()
6+
s = PrimaryUnit("s") # Time
7+
m = PrimaryUnit("m") # Length
8+
kg = PrimaryUnit("kg") # Mass
9+
A = PrimaryUnit("A") # Electrical current
10+
K = PrimaryUnit("K") # Temperature
11+
mol = PrimaryUnit("mol") # Amount of substance
12+
cd = PrimaryUnit("cd") # Luminous intensity
13+
14+
15+
### (some) Derived units
16+
#### General
17+
Hz = s**(-1) # Frequency (Hertz)
18+
J = kg*m**2/s**2 # Energy (Joule)
19+
W = J/s # Power (Watt)
20+
21+
#### Mechanics
22+
v = m/s # Velocity
23+
a = v/s # Acceleration
24+
N = kg*a # Force (Newton)
25+
Pa = N/(m**2) # Pressure (Pascal)
26+
tau = m*N # Torque
27+
28+
#### Electricity
29+
C = A*s # Electrical charge (Coulomb)
30+
V = J/C # Electrical potential difference (Volt)
31+
ohm = V/A # Electrical resistance (Ohm)
32+
S = ohm**(-1) # Electrical conductance (Siemens)
33+
H = ohm * s # Electrical inductance (Henry)
34+
F = C/V # Electrical capacitance (Farad)
35+
Wb = V * s # Magnetic flux (Weber)
36+
T = Wb/(m**2) # Magnetic flux intensity (Tesla)
37+
38+
### Scaled units
39+
#### Primary units
40+
nm = ScaledUnit(m, 1e-9)
41+
µm = ScaledUnit(m, 1e-6)
42+
mm = ScaledUnit(m, 1e-3)
43+
cm = ScaledUnit(m, 1e-2)
44+
dm = ScaledUnit(m, 1e-1)
45+
km = ScaledUnit(m, 1e3)
46+
47+
ns = ScaledUnit(s, 1e-9)
48+
µs = ScaledUnit(s, 1e-6)
49+
ms = ScaledUnit(s, 1e-3)
50+
51+
µg = ScaledUnit(kg, 1e-9)
52+
mg = ScaledUnit(kg, 1e-6)
53+
g = ScaledUnit(kg, 1e-3)
54+
t = ScaledUnit(kg, 1e3)
55+
56+
#### Derived units
57+
nN = ScaledUnit(N, 1e-9)
58+
µN = ScaledUnit(N, 1e-6)
59+
mN = ScaledUnit(N, 1e-3)
60+
cN = ScaledUnit(N, 1e-2)
61+
dN = ScaledUnit(N, 1e-1)
62+
kN = ScaledUnit(N, 1e3)
63+
MN = ScaledUnit(N, 1e6)
64+
GN = ScaledUnit(N, 1e9)
65+
66+
67+
nPa = ScaledUnit(Pa, 1e-9)
68+
µPa = ScaledUnit(Pa, 1e-6)
69+
mPa = ScaledUnit(Pa, 1e-3)
70+
cPa = ScaledUnit(Pa, 1e-2)
71+
dPa = ScaledUnit(Pa, 1e-1)
72+
kPa = ScaledUnit(Pa, 1e3)
73+
MPa = ScaledUnit(Pa, 1e6)
74+
GPa = ScaledUnit(Pa, 1e9)
75+
76+
mJ = ScaledUnit(J, 1e-3)
77+
cJ = ScaledUnit(J, 1e-2)
78+
dJ = ScaledUnit(J, 1e-1)
79+
kJ = ScaledUnit(J, 1e3)
80+
MJ = ScaledUnit(J, 1e6)
81+
GJ = ScaledUnit(J, 1e9)
82+
83+
mW = ScaledUnit(W, 1e-3)
84+
cW = ScaledUnit(W, 1e-2)
85+
dW = ScaledUnit(W, 1e-1)
86+
kW = ScaledUnit(W, 1e3)
87+
MW = ScaledUnit(W, 1e6)
88+
GW = ScaledUnit(W, 1e9)
89+
90+
kHz = ScaledUnit(Hz, 1e3)
91+
MHz = ScaledUnit(Hz, 1e6)
92+
GHz = ScaledUnit(Hz, 1e9)
93+
94+
95+
96+

0 commit comments

Comments
 (0)