UnitValues 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: UnitValues
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A small package for using units in Python. Allows for computation with dimensioned qauntities and allows you to convert between different units. Do anything you would do with regular floats or integers in Python except now with units. Package is compatible with NumPy, SciPy + Pandas are in the works. I think you'll find this implementation more elegant then most other unit packages.
5
5
  Author-email: Brody Howard <brody.howard@mail.utoronto.ca>
6
6
  Project-URL: Homepage, https://github.com/BroRocket/unitvalue/
@@ -8,7 +8,7 @@ Project-URL: Issues, https://github.com/BroRocket/unitvalue/issues
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: numpy>=1.23.2
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "UnitValues"
3
- version = "0.1.2"
3
+ version = "0.1.4"
4
4
  dependencies = [
5
- "numpy>=1.23.2"
5
+ "numpy >= 1.23.2"
6
6
  ]
7
- requires-python = ">=3.8"
7
+ requires-python = ">=3.10"
8
8
  authors = [
9
9
  { name="Brody Howard", email="brody.howard@mail.utoronto.ca" },
10
10
  ]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: UnitValues
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A small package for using units in Python. Allows for computation with dimensioned qauntities and allows you to convert between different units. Do anything you would do with regular floats or integers in Python except now with units. Package is compatible with NumPy, SciPy + Pandas are in the works. I think you'll find this implementation more elegant then most other unit packages.
5
5
  Author-email: Brody Howard <brody.howard@mail.utoronto.ca>
6
6
  Project-URL: Homepage, https://github.com/BroRocket/unitvalue/
@@ -8,7 +8,7 @@ Project-URL: Issues, https://github.com/BroRocket/unitvalue/issues
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: numpy>=1.23.2
@@ -2,10 +2,104 @@
2
2
  This module allows you to easly store numbers with units and easily convert the units and value of the numbers.
3
3
  The two supported systems currently are Imperial and Metric.
4
4
  Typically used units are supported and more can be added upon request or in your instance.
5
+
6
+ AUTHOR: Brody Howard
7
+
5
8
  '''
6
9
  import warnings
7
10
  import numpy as np
8
11
 
12
+
13
+ class _gauge_pressure():
14
+ '''
15
+ This class is used for specifc units which can have guage versus absolute values and facilatest the conversion of these values to absolute or back to gauge.
16
+ Mainly useful for pressure. Do not use outside of this file
17
+ '''
18
+ def __init__(self, unit_conversion_to_SI: float|int, conv_to_absolute: float|int) -> None:
19
+ '''
20
+ Args:
21
+ unit_conversion_to_SI (float|int): value to multiply the non gauge unit value by to convert it to the standard SI unit.
22
+ conv_to_absolute (float|int): value to add to get from gauge to absolute value, note this value must be negative if you subtract to convert to absolute from gauge
23
+ '''
24
+ self.__to_SI = unit_conversion_to_SI
25
+ self.__to_ABSOLUTE = conv_to_absolute
26
+
27
+ def __mul__(self, m) -> int|float:
28
+ '''
29
+ Used in unit class to convert the unit to SI. Thus converts the guage value to absolute and then SI base unit.
30
+
31
+ Args:
32
+ d : the current value of the gauge unit.
33
+
34
+ Returns:
35
+ float|int : The base SI absolute value of the gauge value
36
+ '''
37
+ absolute_value = m + self.__to_ABSOLUTE
38
+ return absolute_value * self.__to_SI
39
+
40
+ __rmul__ = __mul__
41
+
42
+ def __truediv__(self, d):
43
+ '''
44
+ Used in unit class to convert to the gauge unit. Thus converts the absolute base SI value to the gauge unit value.
45
+
46
+ Args:
47
+ d : the current value of theabsolute SI unit.
48
+
49
+ Returns:
50
+ float|int : The base SI absolute value of the gauge value
51
+ '''
52
+ new_unit_value = d / self.__to_SI
53
+ return new_unit_value - self.__to_ABSOLUTE
54
+
55
+ __rtruediv__ = __truediv__
56
+
57
+
58
+ class metric_temperature():
59
+ def __init__(self, unit_conversion_to_SI) -> None:
60
+ self.__to_SI = unit_conversion_to_SI
61
+
62
+ def __mul__(self, m) -> int|float:
63
+ return m + self.__to_SI
64
+
65
+ __rmul__ = __mul__
66
+
67
+ def __truediv__(self, d):
68
+ return d - self.__to_SI
69
+
70
+ __rtruediv__ = __truediv__
71
+
72
+ class farenheit():
73
+ def __init__(self) -> None:
74
+ pass
75
+
76
+ def __mul__(self, m) -> int|float:
77
+ kelvin = ((m - 32) * (5/9)) + 273.15
78
+ return kelvin
79
+
80
+ __rmul__ = __mul__
81
+
82
+ def __truediv__(self, d):
83
+ val = ((d - 273.15) / (5/9)) + 32
84
+ return val
85
+
86
+ __rtruediv__ = __truediv__
87
+
88
+ class rankine():
89
+ def __init__(self) -> None:
90
+ pass
91
+
92
+ def __mul__(self, m) -> int|float:
93
+ return m *(5/9)
94
+
95
+ __rmul__ = __mul__
96
+
97
+ def __truediv__(self, d):
98
+ return d * 1.8
99
+
100
+ __rtruediv__ = __truediv__
101
+
102
+
9
103
  class UnitValue:
10
104
  """
11
105
  Represents a value with dimension/units.
@@ -15,18 +109,18 @@ class UnitValue:
15
109
  __dimension (str): The dimension of the unit (e.g., LENGTH, MASS).
16
110
  __unit (str): The unit of the value (e.g., m, kg).
17
111
  value (float): The numerical value.
18
- """
112
+ """
19
113
  UNITS = {"IMPERIAL": {
20
114
  "DISTANCE": {"in": 0.0254, "mi": 1609.34, "yd": 0.9144, "ft": 0.3048},
21
- "PRESSURE": {"psi": 6894.76, "psf": 47.8803},
115
+ "PRESSURE": {"psi": 6894.76, "psig": _gauge_pressure(6894.76, 14.696), "psf": 47.8803},
22
116
  "MASS": {"lb": 0.453592, "ton": 907.1847, "slug": 14.59390, "st": 6.35029, "oz": 0.0283495},
23
117
  "VELOCITY": {"ft/s": 0.3048, "mi/s": 1609.34, "mph": 0.44704, "in/s": 0.0254},
24
118
  "DENSITY": {"lb/in^3": 27679.9, "lb/ft^3": 16.0185, "lb/yd^3": 0.593276},
25
119
  "VOLUME": {"gal": 0.00378541, "yd^3": 0.764555, "ft^3": 0.0283168, "in^3": 0.0000163871},
26
120
  "AREA": {"in^2": 0.00064516, "mi^2": 2590000, "yd^2": 0.836127, "ft^2": 0.092903},
27
- "TEMPERATURE": {"f": None, "R":None},
121
+ "TEMPERATURE": {"f": farenheit(), "R": rankine()},
28
122
  "MASS FLOW RATE": {"lb/s": 0.453592, "ton/s": 907.1847, "st/s": 6.35029, "oz": 0.0283495, "lb/min": 0.00755987},
29
- "ENERGY": {"ftlb": 1.35582, "kcal": 4184, "cal": 4.184},
123
+ "ENERGY": {"BTU": 1055.05585, "ftlb": 1.35582, "kcal": 4184, "cal": 4.184},
30
124
  "TIME": {"s": 1, "h": 3600, "min": 60, "ms": 0.001},
31
125
  "MOMENTUM": {"slugft/s": 4.449670915354, "lbft/s": 0.1383},
32
126
  "FREQUENCY": {"rpm": 0.016667},
@@ -35,20 +129,21 @@ class UnitValue:
35
129
  "ENERGY PER UNIT MASS": {"ft^2/s^2": 0.09290304},
36
130
  "MASS PER UNIT LENGTH": {"lb/ft": 1.48816, "oz/in": 1.11612},
37
131
  "MASS PER AREA": {"lb/ft^2": 4.88243},
38
- "VOLUMETRIC FLOW RATE": {"ft^3/s": 0.0283168, "gal/s": 0.00378541},
132
+ "VOLUMETRIC FLOW RATE": {"ft^3/s": 0.0283168, "gal/s": 0.00378541, "ft^3/min": 0.000471947, "SCFM": None},
39
133
  "DYNAMIC VISCOCITY": {"lb/fts": 1.488163943568},
40
134
  "KINEMATIC VISCOCITY": {"ft^2/s": 0.092903},
41
- "MASS FLUX": {"lb/ft^2s": 4.88243}
135
+ "MASS FLUX": {"lb/ft^2s": 4.88243},
136
+ "GAS CONSTANTS": {"BTU/lbf": 4186.8000000087}
42
137
  },
43
138
  "METRIC": {
44
139
  "DISTANCE": {"m": 1, "km": 1000, "cm": 0.01, "mm": 0.001},
45
- "PRESSURE": {"kg/ms^2": 1, "MPa": 1000000, "bar": 100000, "kPa": 1000, "hPa": 100, "Pa": 1},
140
+ "PRESSURE": {"kg/ms^2": 1, "MPa": 1000000, "atm": 101325, "bar": 100000, "kPa": 1000, "hPa": 100, "Pa": 1},
46
141
  "MASS": {"kg": 1, "tonne": 1000, "g": 0.001},
47
142
  "VELOCITY": {"m/s": 1, "km/s": 1000, "km/h": 0.277778, "cm/s": 0.01, "mm/s": 0.001},
48
143
  "DENSITY": {"kg/m^3": 1, "t/m^3": 1000, "g/m^3": 0.001},
49
144
  "VOLUME": {"m^3": 1, "L": 0.001, "cm^3": 0.000001, "mL": 0.000001, "mm^3": 0.000000001},
50
145
  "AREA": {"m^2": 1, "km^2": 1000000, "cm^2": 0.0001, "mm^2": 0.000001},
51
- "TEMPERATURE": {"K": None, "c": None},
146
+ "TEMPERATURE": {"K": 1, "c": metric_temperature(273.15)},
52
147
  "MASS FLOW RATE": {"kg/s": 1, "t/s": 1000, "kg/min": 0.0166667, "g/s": 0.001},
53
148
  "ENERGY": {"kgm^2/s^2": 1, "MJ": 1000000, "kJ": 1000, "Nm": 1, "J": 1, "eV": 1.602177e-19},
54
149
  "TIME": {"s": 1, "h": 3600, "min": 60, "ms": 0.001},
@@ -59,19 +154,21 @@ class UnitValue:
59
154
  "ENERGY PER UNIT MASS": {"m^2/s^2": 1},
60
155
  "MASS PER LENGTH": {"kg/m": 1, "kg/cm": 100, "g/cm": 0.1},
61
156
  "MASS PER AREA": {"kg/m^2": 1, "g/cm^2": 10},
62
- "VOLUMETRIC FLOW RATE": {"m^3/s": 1, "cm^3/s": 0.000001},
157
+ "VOLUMETRIC FLOW RATE": {"m^3/s": 1, "cm^3/s": 0.000001, "L/min": 0.001/60, "SLPM": None},
63
158
  "DYNAMIC VISCOCITY": {"kg/ms": 1, "g/cms":0.1},
64
159
  "KINEMATIC VISCOCITY": {"m^2/s": 1, "cm^2/s": 0.0001},
65
- "MASS FLUX": {"kg/m^2s": 1}
160
+ "MASS FLUX": {"kg/m^2s": 1},
161
+ "GAS CONSTANTS": {"m^2/s^2K": 1, "J/kgK": 1, "J/kgc": 1},
162
+ "MOLECULAR COUNT": {'Mol': 1, "kMol": 1000}
66
163
  }
67
164
  }
68
165
 
69
- SPELLING_MAP = {'mtr': 'm', 'meters': 'm', 'mtr.': 'm', 'metres': 'm', 'metre': 'm', 'm ': 'm', 'meter': 'm', 'kilometer': 'km', 'kilometre': 'km', 'kilo meter': 'km', 'k meter': 'km', 'klometer': 'km', 'km ': 'km', 'kmeter': 'km', 'kmtr': 'km', 'centemeter': 'cm', 'centimetre': 'cm', 'cn': 'cm', 'c meter': 'cm', 'cm ': 'cm', 'centi meter': 'cm', 'centimeter': 'cm', 'cmeter': 'cm', 'cmtr': 'cm', 'mmeter': 'mm', 'millimeter': 'mm', 'milimeter': 'mm', 'milli meter': 'mm', 'millimetre': 'mm', 'm meter': 'mm', 'mn': 'mm', 'mmtr': 'mm', 'mm ': 'mm', 'g ': 'g', 'gramme': 'g', 'grm': 'g', 'gms': 'g', 'gram': 'g', 'gm': 'g', 'gramm': 'g', 'gram ': 'g', 'kilograms': 'kg', 'k gram': 'kg', 'kilogramme': 'kg', 'kilogram ': 'kg', 'kilogramme ': 'kg', 'kilogrammes': 'kg', 'kg ': 'kg', 'kilogram': 'kg', 'kilo gram': 'kg', 'kgrm': 'kg', 'liters': 'L', 'l': 'L', 'litres': 'L', 'ltrs': 'L', 'liter': 'L', 'litre ': 'L', 'litre': 'L', 'liters ': 'L', 'liter ': 'L', 'litter': 'L', 'ltr': 'L', 'ml': 'mL', 'milliliter': 'mL', 'mlitres': 'mL', 'millilitre': 'mL', 'milli litre': 'mL', 'mliters': 'mL', 'milli liter': 'mL', 'mltr': 'mL', 'sec': 's', 'seconds': 's', 'sedonds': 's', 'sconds': 's', 'second': 's', 'secs': 's', 'secnd': 's', 'minute': 'min', 'minuts': 'min', 'mins': 'min', 'minutes': 'min', 'min': 'min', 'minut': 'min', 'hours': 'h', 'hr': 'h', 'howr': 'h', 'houer': 'h', 'hour': 'h', 'hou': 'h', 'hrs': 'h', 'square meters': 'm^2', 'square meter': 'm^2', 'sqr meter': 'm^2', 'square metre': 'm^2', 'sq meter': 'm^2', 'sqmetre': 'm^2', 'sq metres': 'm^2', 'sqm': 'm^2', 'cube meter': 'm^3', 'cu meter': 'm^3', 'cbm': 'm^3', 'cubic meters': 'm^3', 'cubic metre': 'm^3', 'cubic meter': 'm^3', 'cu m': 'm^3', 'degree centigrade': 'c', 'degree celsius': 'c', 'celcius': 'c', 'deg celsius': 'c', 'celsius degree': 'c', 'celsus': 'c', 'celsius': 'c', 'deg c': 'c', 'fahrenheit degree': 'f', 'deg f': 'f', 'deg fahrenheit': 'f', 'fahrenhiet': 'f', 'degree fahrenheit': 'f', 'farhenheit': 'f', 'force': 'kgm/s^2', 'Newton': 'kgm/s^2', 'newtn': 'kgm/s^2', 'nwton': 'kgm/s^2', 'nwt': 'kgm/s^2', 'newton': 'kgm/s^2', 'joule': 'kgm^2/s^2', 'energy': 'kgm^2/s^2', 'juole': 'kgm^2/s^2', 'jl': 'kgm^2/s^2', 'joules': 'kgm^2/s^2', 'juul': 'kgm^2/s^2', 'inck': 'in', 'inche': 'in', 'inch': 'in', 'inc': 'in', 'inch ': 'in', 'inchh': 'in', 'foot': 'ft', 'foott': 'ft', 'fot': 'ft', 'foor': 'ft', 'foot ': 'ft', 'feet': 'ft', 'yardd': 'yd', 'yad': 'yd', 'yarrd': 'yd', 'yard ': 'yd', 'yard': 'yd', 'mille': 'mi', 'mile ': 'mi', 'milee': 'mi', 'mil': 'mi', 'mile': 'mi', 'pounds': 'lb', 'pounnd': 'lb', 'pound ': 'lb', 'pound': 'lb', 'lbs': 'lb', 'poundd': 'lb', 'galln': 'gal', 'gllon': 'gal', 'gallon': 'gal', 'galllon': 'gal', 'gallon ': 'gal', 'ounze': 'oz', 'ouncce': 'oz', 'ounce ': 'oz', 'ozs': 'oz', 'ounce': 'oz', 'ounc': 'oz', 'ounc ': 'oz', 'stn': 'st', 'stone ': 'st', 'sts': 'st', 'stone': 'st', 'st ': 'st', 'ft2': 'ft^2', 'square foot': 'ft^2', 'sqft': 'ft^2', 'square feet': 'ft^2', 'sq foot': 'ft^2', 'ft3': 'ft^3', 'cft': 'ft^3', 'cubic foot': 'ft^3', 'cu ft': 'ft^3', 'cubic feet': 'ft^3'}
166
+ SPELLING_MAP = {'mtr': 'm', 'meters': 'm', 'mtr.': 'm', 'metres': 'm', 'metre': 'm', 'm ': 'm', 'meter': 'm', 'kilometer': 'km', 'kilometre': 'km', 'kilo meter': 'km', 'k meter': 'km', 'klometer': 'km', 'km ': 'km', 'kmeter': 'km', 'kmtr': 'km', 'centemeter': 'cm', 'centimetre': 'cm', 'cn': 'cm', 'c meter': 'cm', 'cm ': 'cm', 'centi meter': 'cm', 'centimeter': 'cm', 'cmeter': 'cm', 'cmtr': 'cm', 'mmeter': 'mm', 'millimeter': 'mm', 'milimeter': 'mm', 'milli meter': 'mm', 'millimetre': 'mm', 'm meter': 'mm', 'mn': 'mm', 'mmtr': 'mm', 'mm ': 'mm', 'g ': 'g', 'gramme': 'g', 'grm': 'g', 'gms': 'g', 'gram': 'g', 'gm': 'g', 'gramm': 'g', 'gram ': 'g', 'kilograms': 'kg', 'k gram': 'kg', 'kilogramme': 'kg', 'kilogram ': 'kg', 'kilogramme ': 'kg', 'kilogrammes': 'kg', 'kg ': 'kg', 'kilogram': 'kg', 'kilo gram': 'kg', 'kgrm': 'kg', 'liters': 'L', 'l': 'L', 'litres': 'L', 'ltrs': 'L', 'liter': 'L', 'litre ': 'L', 'litre': 'L', 'liters ': 'L', 'liter ': 'L', 'litter': 'L', 'ltr': 'L', 'ml': 'mL', 'milliliter': 'mL', 'mlitres': 'mL', 'millilitre': 'mL', 'milli litre': 'mL', 'mliters': 'mL', 'milli liter': 'mL', 'mltr': 'mL', 'sec': 's', 'seconds': 's', 'sedonds': 's', 'sconds': 's', 'second': 's', 'secs': 's', 'secnd': 's', 'minute': 'min', 'minuts': 'min', 'mins': 'min', 'minutes': 'min', 'min': 'min', 'minut': 'min', 'hours': 'h', 'hr': 'h', 'howr': 'h', 'houer': 'h', 'hour': 'h', 'hou': 'h', 'hrs': 'h', 'square meters': 'm^2', 'square meter': 'm^2', 'sqr meter': 'm^2', 'square metre': 'm^2', 'sq meter': 'm^2', 'sqmetre': 'm^2', 'sq metres': 'm^2', 'sqm': 'm^2', 'cube meter': 'm^3', 'cu meter': 'm^3', 'cbm': 'm^3', 'cubic meters': 'm^3', 'cubic metre': 'm^3', 'cubic meter': 'm^3', 'cu m': 'm^3', 'C': 'c','degree centigrade': 'c', 'degree celsius': 'c', 'celcius': 'c', 'deg celsius': 'c', 'celsius degree': 'c', 'celsus': 'c', 'celsius': 'c', 'deg c': 'c', 'fahrenheit degree': 'f', 'deg f': 'f', 'deg fahrenheit': 'f', 'fahrenhiet': 'f', 'degree fahrenheit': 'f', 'farhenheit': 'f', 'force': 'kgm/s^2', 'Newton': 'kgm/s^2', 'newtn': 'kgm/s^2', 'nwton': 'kgm/s^2', 'nwt': 'kgm/s^2', 'newton': 'kgm/s^2', 'joule': 'kgm^2/s^2', 'energy': 'kgm^2/s^2', 'juole': 'kgm^2/s^2', 'jl': 'kgm^2/s^2', 'joules': 'kgm^2/s^2', 'juul': 'kgm^2/s^2', 'inck': 'in', 'inche': 'in', 'inch': 'in', 'inc': 'in', 'inch ': 'in', 'inchh': 'in', 'foot': 'ft', 'foott': 'ft', 'fot': 'ft', 'foor': 'ft', 'foot ': 'ft', 'feet': 'ft', 'yardd': 'yd', 'yad': 'yd', 'yarrd': 'yd', 'yard ': 'yd', 'yard': 'yd', 'mille': 'mi', 'mile ': 'mi', 'milee': 'mi', 'mil': 'mi', 'mile': 'mi', 'pounds': 'lb', 'pounnd': 'lb', 'pound ': 'lb', 'pound': 'lb', 'lbs': 'lb', 'poundd': 'lb', 'galln': 'gal', 'gllon': 'gal', 'gallon': 'gal', 'galllon': 'gal', 'gallon ': 'gal', 'ounze': 'oz', 'ouncce': 'oz', 'ounce ': 'oz', 'ozs': 'oz', 'ounce': 'oz', 'ounc': 'oz', 'ounc ': 'oz', 'stn': 'st', 'stone ': 'st', 'sts': 'st', 'stone': 'st', 'st ': 'st', 'ft2': 'ft^2', 'square foot': 'ft^2', 'sqft': 'ft^2', 'square feet': 'ft^2', 'sq foot': 'ft^2', 'ft3': 'ft^3', 'cft': 'ft^3', 'cubic foot': 'ft^3', 'cu ft': 'ft^3', 'cubic feet': 'ft^3', 'mol': 'Mol', 'moles': 'Mol', 'mols': 'Mol', 'Moles': 'Mol', 'Mols': 'Mol'}
70
167
 
71
168
  @classmethod
72
169
  def add_custom_unit(cls, system: str, dimension:str, unit:str, conversion_factor: float) -> None:
73
170
  """
74
- Add your own units to the package instance whihc you can then use in conversion and arithmatic. Note there is a small chance new SI/Metric units will mess with unit conversion during arithmatic.
171
+ Add your own units to the package instance which you can then use in conversion and arithmatic. Note there is a small chance new SI/Metric units will mess with unit conversion during arithmatic.
75
172
 
76
173
  Args:
77
174
  system (str): The measurement system ('IMPERIAL' or 'METRIC').
@@ -139,7 +236,7 @@ class UnitValue:
139
236
  @classmethod
140
237
  def create_unit(cls, unit: str, value: float=0) -> 'UnitValue':
141
238
  """
142
- Create a UnitValue object based on the unit and value. Will also account for speeling mistakes/alternate names of units.
239
+ Create a UnitValue object based on the unit and value. Will also account for spelling mistakes/alternate names of units.
143
240
 
144
241
  Args:
145
242
  unit (str): The unit of the value.
@@ -182,7 +279,7 @@ class UnitValue:
182
279
  raise ValueError("First element of string could not be converted to number, ensure string of the form e.g., '10 kg'")
183
280
 
184
281
  @classmethod
185
- def from_dict(cls, data: dict) -> 'UnitValue':
282
+ def unit_from_dict(cls, data: dict) -> 'UnitValue':
186
283
  """
187
284
  Create a UnitValue object from a dictionary.
188
285
 
@@ -260,7 +357,10 @@ class UnitValue:
260
357
  continue
261
358
  elif unit_str[i] == "k":
262
359
  key = unit_str[i:i+2]
263
- i += 1
360
+ i += 1
361
+ elif unit_str[i] == "M":
362
+ key = unit_str[i:i+3]
363
+ i += 2
264
364
  else:
265
365
  key = unit_str[i]
266
366
 
@@ -299,6 +399,13 @@ class UnitValue:
299
399
  units = {}
300
400
  self.__process_unit(self.__unit, units, 1)
301
401
  self.__process_unit(m.__unit, units, 1)
402
+
403
+ empty_units = []
404
+ for unit, count in units.items():
405
+ if count == 0:
406
+ empty_units.append(unit)
407
+ for unit in empty_units:
408
+ units.pop(unit)
302
409
 
303
410
  for dimension, units_dict in UnitValue.UNITS["METRIC"].items():
304
411
  temp = {}
@@ -345,6 +452,13 @@ class UnitValue:
345
452
  self.__process_unit(self.__unit, units, 1)
346
453
  self.__process_unit(d.__unit, units, -1)
347
454
 
455
+ empty_units = []
456
+ for unit, count in units.items():
457
+ if count == 0:
458
+ empty_units.append(unit)
459
+ for unit in empty_units:
460
+ units.pop(unit)
461
+
348
462
  for dimension, units_dict in UnitValue.UNITS["METRIC"].items():
349
463
  temp = {}
350
464
  self.__process_unit(list(units_dict)[0], temp, 1)
@@ -387,6 +501,13 @@ class UnitValue:
387
501
  self.__process_unit(self.__unit, units, -1)
388
502
  self.__process_unit(d.__unit, units, 1)
389
503
 
504
+ empty_units = []
505
+ for unit, count in units.items():
506
+ if count == 0:
507
+ empty_units.append(unit)
508
+ for unit in empty_units:
509
+ units.pop(unit)
510
+
390
511
  for dimension, units_dict in UnitValue.UNITS["METRIC"].items():
391
512
  temp = {}
392
513
  self.__process_unit(list(units_dict)[0], temp, 1)
@@ -444,6 +565,8 @@ class UnitValue:
444
565
  """
445
566
  Raises UnitValue object to the power of a float or interger.
446
567
  """
568
+ if self.value < 0 and p < 1.0 and not p < -1:
569
+ raise ValueError("Trying to take root of a a negative number")
447
570
  if isinstance(p, (int, float)):
448
571
  if p == 1:
449
572
  return self
@@ -558,8 +681,8 @@ class UnitValue:
558
681
  Checks if UnitValue object is equal to other.
559
682
  """
560
683
  if isinstance(other, UnitValue):
561
- a = self.__cpy().convert_base_metric()
562
- b = other.__cpy().convert_base_metric()
684
+ a = self.copy().convert_base_metric()
685
+ b = other.copy().convert_base_metric()
563
686
  return a.value == b.value and a.__unit == b.__unit
564
687
  elif isinstance(other, (int, float)):
565
688
  return self.value == other
@@ -567,8 +690,8 @@ class UnitValue:
567
690
 
568
691
  def __ne__(self, other) -> bool:
569
692
  if isinstance(other, UnitValue):
570
- a = self.__cpy().convert_base_metric()
571
- b = other.__cpy().convert_base_metric()
693
+ a = self.copy().convert_base_metric()
694
+ b = other.copy().convert_base_metric()
572
695
  return a.value != b.value and a.__unit != b.__unit
573
696
  elif isinstance(other, (int, float)):
574
697
  return self.value != other
@@ -576,8 +699,8 @@ class UnitValue:
576
699
 
577
700
  def __lt__(self, other) -> bool:
578
701
  if isinstance(other, UnitValue):
579
- a = self.__cpy().convert_base_metric()
580
- b = other.__cpy().convert_base_metric()
702
+ a = self.copy().convert_base_metric()
703
+ b = other.copy().convert_base_metric()
581
704
  return a.value < b.value
582
705
  elif isinstance(other, (int, float)):
583
706
  return self.value < other
@@ -585,8 +708,8 @@ class UnitValue:
585
708
 
586
709
  def __le__(self, other) -> bool:
587
710
  if isinstance(other, UnitValue):
588
- a = self.__cpy().convert_base_metric()
589
- b = other.__cpy().convert_base_metric()
711
+ a = self.copy().convert_base_metric()
712
+ b = other.copy().convert_base_metric()
590
713
  return a.value <= b.value
591
714
  elif isinstance(other, (int, float)):
592
715
  return self.value <= other
@@ -594,8 +717,8 @@ class UnitValue:
594
717
 
595
718
  def __gt__(self, other) -> bool:
596
719
  if isinstance(other, UnitValue):
597
- a = self.__cpy().convert_base_metric()
598
- b = other.__cpy().convert_base_metric()
720
+ a = self.copy().convert_base_metric()
721
+ b = other.copy().convert_base_metric()
599
722
  return a.value > b.value
600
723
  elif isinstance(other, (int, float)):
601
724
  return self.value > other
@@ -603,8 +726,8 @@ class UnitValue:
603
726
 
604
727
  def __ge__(self, other) -> bool:
605
728
  if isinstance(other, UnitValue):
606
- a = self.__cpy().convert_base_metric()
607
- b = other.__cpy().convert_base_metric()
729
+ a = self.copy().convert_base_metric()
730
+ b = other.copy().convert_base_metric()
608
731
  return a.value >= b.value
609
732
  elif isinstance(other, (int, float)):
610
733
  return self.value >= other
@@ -618,10 +741,10 @@ class UnitValue:
618
741
 
619
742
  def __round__(self, ndigits: int=0) -> 'UnitValue':
620
743
  """
621
- Rounds UnitValue to ndigts returns rounded Unitvale
744
+ Returns Rounded UnitValue to ndigts
622
745
  """
623
- self.value = round(self.value, ndigits)
624
- return self
746
+ value = round(self.value, ndigits)
747
+ return UnitValue(self.__system, self.__dimension, self.__unit, value)
625
748
 
626
749
  def __repr__(self) -> str:
627
750
  return f"{self.value} {self.__unit}"
@@ -641,12 +764,14 @@ class UnitValue:
641
764
  for ind, element in enumerate(inputs[0]):
642
765
  inputs[0][ind] = ufunc(element, inputs[1], **kwargs)
643
766
  return inputs[0]
644
- elif isinstance(inputs[1], np.ndarray):
767
+ elif len(inputs) > 1 and isinstance(inputs[1], np.ndarray):
645
768
  inputs = [inputs[0], inputs[1]]
646
769
  for ind, element in enumerate(inputs[1]):
647
770
  inputs[1][ind] = ufunc(inputs[0], element, **kwargs)
648
771
  return inputs[1]
649
772
  else:
773
+ if isinstance(inputs[0], (np.float64, np.int64)):
774
+ inputs = [float(inputs[0]), inputs[1]]
650
775
  if ufunc == np.add:
651
776
  return inputs[0] + inputs[1]
652
777
  elif ufunc == np.subtract:
@@ -655,16 +780,22 @@ class UnitValue:
655
780
  return inputs[0] * inputs[1]
656
781
  elif ufunc == np.divide:
657
782
  return inputs[0] / inputs[1]
783
+ elif ufunc == np.sqrt:
784
+ return inputs[0] ** 0.5
658
785
  elif ufunc == np.power:
659
786
  return inputs[0] ** inputs[1]
660
787
  elif ufunc == np.mod:
661
788
  return inputs[0] % inputs[1]
789
+ elif ufunc == np.log10:
790
+ return np.log10(inputs[0].value)
791
+ else:
792
+ return NotImplemented
662
793
 
663
794
  def __array_function__(self, func, types, *args, **kwargs):
664
795
  if func is np.concatenate:
665
796
  unit_cache = []
666
797
  for arr in args[0]:
667
- unit_cache += [item.get_unit if isinstance(item, UnitValue) else None for item in arr]
798
+ unit_cache += [item.unit if isinstance(item, UnitValue) else None for item in arr]
668
799
  for i in range(len(arr)):
669
800
  arr[i] = arr[i].value if isinstance(arr[i], UnitValue) else arr[i]
670
801
  new_array = np.concatenate(args[0], **kwargs)
@@ -700,58 +831,8 @@ class UnitValue:
700
831
  self.__unit = unit
701
832
  else:
702
833
  raise Exception(f"Unit {unit} invalid: Unit must be {list(UnitValue.UNITS[self.__system][self.__dimension].keys())} for {self.__system} {self.__dimension}")
703
-
704
- def __cpy(self) -> 'UnitValue':
705
- return UnitValue(self.__system, self.__dimension, self.__unit, self.value)
706
834
 
707
- def __temperature_handler(self, old_unit: str, new_unit: str): # add Rankine
708
- if new_unit == "K":
709
- if old_unit == "c":
710
- self.value += 273.15
711
- elif old_unit == "f":
712
- self.value = (self.value - 32) * (5/9) + 273.15
713
- elif old_unit == "R":
714
- self.value *= 5/9
715
- elif new_unit == "c":
716
- if old_unit == "K":
717
- self.value -= 273.15
718
- elif old_unit == "f":
719
- self.value = (self.value - 32) * (5/9)
720
- elif old_unit == "R":
721
- self.value = (self.value - 491.67) * (5/9)
722
- elif new_unit == "f":
723
- if old_unit == "K":
724
- self.value = ((self.value -273.15) / (5/9)) + 32
725
- elif old_unit == "c":
726
- self.value = (self.value / (5/9)) + 32
727
- elif old_unit == "R":
728
- self.value -= 459.67
729
- elif new_unit == "R":
730
- if old_unit == "c":
731
- self.value = self.value * (9/5) + 491.67
732
- elif old_unit == "f":
733
- self.value += 459.67
734
- elif old_unit == "K":
735
- self.value *= 1.8
736
-
737
- def __convert_temp(self, change_system: bool, unit: str=""):
738
- if change_system:
739
- self.__system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
740
- if unit in UnitValue.UNITS[self.__system][self.__dimension].keys():
741
- self.__temperature_handler(self.__unit, unit)
742
- self.__unit = unit
743
- else:
744
- raise Exception(f"Unit {unit} invalid: Unit must be {list(UnitValue.UNITS[self.__system][self.__dimension].keys())} for {self.__system} {self.__dimension}")
745
- elif unit:
746
- if unit in UnitValue.UNITS[self.__system][self.__dimension].keys():
747
- self.__temperature_handler(self.__unit, unit)
748
- self.__unit = unit
749
- else:
750
- raise Exception(f"Unit {unit} invalid: Unit must be {list(UnitValue.UNITS[self.__system][self.__dimension].keys())} for {self.__system} {self.__dimension}")
751
- else:
752
- raise Exception("No conversion performed as change_system was false and unit was empty")
753
-
754
- def convert_base_metric(self) -> 'UnitValue':
835
+ def convert_base_metric(self, **kwargs) -> 'UnitValue':
755
836
  """
756
837
  Convert the current value to it's base SI/Metric unit.
757
838
 
@@ -760,17 +841,74 @@ class UnitValue:
760
841
  """
761
842
  if self.__system is None:
762
843
  return
763
- elif self.__dimension != "TEMPERATURE":
764
- self.value *= UnitValue.UNITS[self.__system][self.__dimension][self.__unit]
765
- self.__system = "METRIC"
766
- self.__unit = list(UnitValue.UNITS[self.__system][self.__dimension].keys())[0]
844
+
845
+ if self.__unit == "SCFM" or self.__unit == "SLPM":
846
+ try:
847
+ return self.__standard_flowrate_handler("m^3/s", kwargs["temperature"], kwargs["pressure"])
848
+ except Exception as e:
849
+ raise ValueError(f"Was unable to convert flow rate to standard metric unit. You have ommited the required key word arguments (temperature and pressure) when converting from or to SLPM or SCFM. Occured Error: {e}")
850
+
851
+ self.value *= UnitValue.UNITS[self.__system][self.__dimension][self.__unit]
852
+ self.__system = "METRIC"
853
+ self.__unit = list(UnitValue.UNITS[self.__system][self.__dimension].keys())[0]
854
+ return self
855
+
856
+ def __standard_flowrate_handler(self, unit:str, temperature: 'UnitValue', pressure: 'UnitValue') -> 'UnitValue':
857
+ '''Handles the standard flow rate conversions which involve knwoing orher properties opf the fluid'''
858
+ std_temp = UnitValue("METRIC", "TEMPERATURE", "K", 273.15)
859
+ std_pressure = UnitValue("IMPERIAL", "PRESSURE", "psi", 14.504)
860
+ if self.__unit == "SLPM":
861
+ if unit == "SCFM":
862
+ self.value /= 28.316847
863
+ self.__dimension = "IMPERIAL"
864
+ self.__unit = "SCFM"
865
+ return self
866
+
867
+ self.value = (self.value * (temperature/std_temp) * (std_pressure/pressure)) / 60000 # converted to base metric
868
+ other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
869
+ if unit in UnitValue.UNITS[self.__system][self.__dimension]:
870
+ self.value /= UnitValue.UNITS[self.__system][self.__dimension][unit]
871
+ elif unit in UnitValue.UNITS[other_system][self.__dimension]:
872
+ self.value /= UnitValue.UNITS[other_system][self.__dimension][unit]
873
+ self.__system = other_system
874
+ else:
875
+ raise TypeError(f"Cannot convert unit of dimension {self.__dimension} to {unit}")
876
+ self.__unit = unit
877
+
878
+ elif self.__unit == "SCFM":
879
+ if unit == "SLPM":
880
+ self.value *= 28.316847
881
+ self.__dimension = "METRIC"
882
+ self.__unit = "SLPM"
883
+ return self
884
+
885
+ self.value = ((self.value*28.316847) * (temperature/std_temp) * (std_pressure/pressure)) / 60000 # converted to base metric
886
+ other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
887
+ if unit in UnitValue.UNITS[self.__system][self.__dimension]:
888
+ self.value /= UnitValue.UNITS[self.__system][self.__dimension][unit]
889
+ elif unit in UnitValue.UNITS[other_system][self.__dimension]:
890
+ self.value /= UnitValue.UNITS[other_system][self.__dimension][unit]
891
+ self.__system = other_system
892
+ else:
893
+ raise TypeError(f"Cannot convert unit of dimension {self.__dimension} to {unit}")
894
+ self.__unit = unit
895
+
767
896
  else:
768
- self.__temperature_handler(self.__unit, "K")
769
- self.__system = "METRIC"
770
- self.__unit = "K"
897
+ self.value *= UnitValue.UNITS[self.__system][self.__dimension][self.__unit]
898
+ if unit == "SLPM":
899
+ self.value = (self.value * 60000) * (std_temp/temperature) * (pressure/std_pressure)
900
+ self.__system = "METRIC"
901
+ self.__unit = "SLPM"
902
+
903
+ elif unit == "SCFM":
904
+ self.value = ((self.value * 60000) * (std_temp/temperature) * (pressure/std_pressure)) / 28.316847
905
+ self.__system = "IMPERIAL"
906
+ self.__unit = "SCFM"
907
+
771
908
  return self
909
+
772
910
 
773
- def to(self, unit:str) -> 'UnitValue':
911
+ def to(self, unit:str, **kwargs) -> 'UnitValue':
774
912
  """
775
913
  Convert the current value to a new unit.
776
914
 
@@ -784,23 +922,24 @@ class UnitValue:
784
922
  Exception: If the unit is not recognized or conversion is not possible.
785
923
  """
786
924
  u = UnitValue.SPELLING_MAP.get(unit)
787
- if u: unit = u
925
+ if u: unit = u
926
+
927
+ if unit == self.unit: return self
788
928
 
789
929
  cache_key = (self.__system, self.__dimension, self.__unit, unit)
790
930
  if cache_key in self._conversion_cache:
791
931
  cached_value = self._conversion_cache[cache_key]
792
932
  return UnitValue(self.__system, self.__dimension, unit, cached_value)
933
+
934
+ if unit == "SCFM" or unit == "SLPM" or self.__unit == "SCFM" or self.__unit == "SLPM":
935
+ try:
936
+ return self.__standard_flowrate_handler(unit, kwargs["temperature"], kwargs["pressure"])
937
+ except Exception as e:
938
+ raise ValueError(f"Was unable to convert flow rate to standard metric unit. You have ommited the required key word arguments (temperature and pressure) when converting from or to SLPM or SCFM. Occured Error: {e}")
793
939
 
794
940
  other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
795
941
  if self.__system is None:
796
942
  raise Exception(f"Invalid unit {self.__unit}: this unit is not currently supported by the module")
797
- elif self.__dimension == "TEMPERATURE":
798
- if unit in UnitValue.UNITS[self.__system][self.__dimension]:
799
- self.__convert_temp(False, unit)
800
- elif unit in UnitValue.UNITS[other_system][self.__dimension]:
801
- self.__convert_temp(True, unit)
802
- else:
803
- raise TypeError(f"Cannot convert unit of dimension {self.__dimension} to {unit}")
804
943
  else:
805
944
  if unit in UnitValue.UNITS[self.__system][self.__dimension]:
806
945
  self.__convert_unit(unit)
@@ -811,6 +950,10 @@ class UnitValue:
811
950
 
812
951
  self._conversion_cache[cache_key] = self.value
813
952
  return self
953
+
954
+ def copy(self) -> 'UnitValue':
955
+ '''Returns copy of the unit that can be used without changing the original unit, i.e. not a soft copy'''
956
+ return UnitValue(self.__system, self.__dimension, self.__unit, self.value)
814
957
 
815
958
  def to_dict(self) -> dict:
816
959
  """
@@ -827,14 +970,13 @@ class UnitValue:
827
970
  }
828
971
 
829
972
  @property
830
- def get_unit(self) -> str:
973
+ def unit(self) -> str:
831
974
  return self.__unit
832
975
 
833
976
  @property
834
- def get_dimension(self) -> str:
977
+ def dimension(self) -> str:
835
978
  return self.__dimension
836
979
 
837
980
  @property
838
- def get_system(self) -> str:
839
- return self.__system
840
-
981
+ def system(self) -> str:
982
+ return self.__system
File without changes
File without changes
File without changes