UnitValues 0.1.3__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.3
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/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "UnitValues"
3
- version = "0.1.3"
3
+ version = "0.1.4"
4
4
  dependencies = [
5
5
  "numpy >= 1.23.2"
6
6
  ]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: UnitValues
3
- Version: 0.1.3
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/
@@ -2,11 +2,105 @@
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
 
9
- class UnitValue: # add specific heat
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
+
103
+ class UnitValue:
10
104
  """
11
105
  Represents a value with dimension/units.
12
106
 
@@ -15,16 +109,16 @@ class UnitValue: # add specific heat
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
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},
@@ -35,21 +129,21 @@ class UnitValue: # add specific heat
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, "ft^3/min": 0.000471947},
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
135
  "MASS FLUX": {"lb/ft^2s": 4.88243},
42
- "SPECIFIC HEAT": {"BTU/lbf": 4186.8000000087}
136
+ "GAS CONSTANTS": {"BTU/lbf": 4186.8000000087}
43
137
  },
44
138
  "METRIC": {
45
139
  "DISTANCE": {"m": 1, "km": 1000, "cm": 0.01, "mm": 0.001},
46
- "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},
47
141
  "MASS": {"kg": 1, "tonne": 1000, "g": 0.001},
48
142
  "VELOCITY": {"m/s": 1, "km/s": 1000, "km/h": 0.277778, "cm/s": 0.01, "mm/s": 0.001},
49
143
  "DENSITY": {"kg/m^3": 1, "t/m^3": 1000, "g/m^3": 0.001},
50
144
  "VOLUME": {"m^3": 1, "L": 0.001, "cm^3": 0.000001, "mL": 0.000001, "mm^3": 0.000000001},
51
145
  "AREA": {"m^2": 1, "km^2": 1000000, "cm^2": 0.0001, "mm^2": 0.000001},
52
- "TEMPERATURE": {"K": None, "c": None},
146
+ "TEMPERATURE": {"K": 1, "c": metric_temperature(273.15)},
53
147
  "MASS FLOW RATE": {"kg/s": 1, "t/s": 1000, "kg/min": 0.0166667, "g/s": 0.001},
54
148
  "ENERGY": {"kgm^2/s^2": 1, "MJ": 1000000, "kJ": 1000, "Nm": 1, "J": 1, "eV": 1.602177e-19},
55
149
  "TIME": {"s": 1, "h": 3600, "min": 60, "ms": 0.001},
@@ -60,20 +154,21 @@ class UnitValue: # add specific heat
60
154
  "ENERGY PER UNIT MASS": {"m^2/s^2": 1},
61
155
  "MASS PER LENGTH": {"kg/m": 1, "kg/cm": 100, "g/cm": 0.1},
62
156
  "MASS PER AREA": {"kg/m^2": 1, "g/cm^2": 10},
63
- "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},
64
158
  "DYNAMIC VISCOCITY": {"kg/ms": 1, "g/cms":0.1},
65
159
  "KINEMATIC VISCOCITY": {"m^2/s": 1, "cm^2/s": 0.0001},
66
160
  "MASS FLUX": {"kg/m^2s": 1},
67
- "SPECIFIC HEAT": {"m^2/s^2K": 1, "J/kgK": 1, "J/kgc": 1}
161
+ "GAS CONSTANTS": {"m^2/s^2K": 1, "J/kgK": 1, "J/kgc": 1},
162
+ "MOLECULAR COUNT": {'Mol': 1, "kMol": 1000}
68
163
  }
69
164
  }
70
165
 
71
- 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'}
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'}
72
167
 
73
168
  @classmethod
74
169
  def add_custom_unit(cls, system: str, dimension:str, unit:str, conversion_factor: float) -> None:
75
170
  """
76
- 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.
77
172
 
78
173
  Args:
79
174
  system (str): The measurement system ('IMPERIAL' or 'METRIC').
@@ -141,7 +236,7 @@ class UnitValue: # add specific heat
141
236
  @classmethod
142
237
  def create_unit(cls, unit: str, value: float=0) -> 'UnitValue':
143
238
  """
144
- 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.
145
240
 
146
241
  Args:
147
242
  unit (str): The unit of the value.
@@ -184,7 +279,7 @@ class UnitValue: # add specific heat
184
279
  raise ValueError("First element of string could not be converted to number, ensure string of the form e.g., '10 kg'")
185
280
 
186
281
  @classmethod
187
- def from_dict(cls, data: dict) -> 'UnitValue':
282
+ def unit_from_dict(cls, data: dict) -> 'UnitValue':
188
283
  """
189
284
  Create a UnitValue object from a dictionary.
190
285
 
@@ -262,7 +357,10 @@ class UnitValue: # add specific heat
262
357
  continue
263
358
  elif unit_str[i] == "k":
264
359
  key = unit_str[i:i+2]
265
- i += 1
360
+ i += 1
361
+ elif unit_str[i] == "M":
362
+ key = unit_str[i:i+3]
363
+ i += 2
266
364
  else:
267
365
  key = unit_str[i]
268
366
 
@@ -301,6 +399,13 @@ class UnitValue: # add specific heat
301
399
  units = {}
302
400
  self.__process_unit(self.__unit, units, 1)
303
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)
304
409
 
305
410
  for dimension, units_dict in UnitValue.UNITS["METRIC"].items():
306
411
  temp = {}
@@ -347,6 +452,13 @@ class UnitValue: # add specific heat
347
452
  self.__process_unit(self.__unit, units, 1)
348
453
  self.__process_unit(d.__unit, units, -1)
349
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
+
350
462
  for dimension, units_dict in UnitValue.UNITS["METRIC"].items():
351
463
  temp = {}
352
464
  self.__process_unit(list(units_dict)[0], temp, 1)
@@ -389,6 +501,13 @@ class UnitValue: # add specific heat
389
501
  self.__process_unit(self.__unit, units, -1)
390
502
  self.__process_unit(d.__unit, units, 1)
391
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
+
392
511
  for dimension, units_dict in UnitValue.UNITS["METRIC"].items():
393
512
  temp = {}
394
513
  self.__process_unit(list(units_dict)[0], temp, 1)
@@ -446,6 +565,8 @@ class UnitValue: # add specific heat
446
565
  """
447
566
  Raises UnitValue object to the power of a float or interger.
448
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")
449
570
  if isinstance(p, (int, float)):
450
571
  if p == 1:
451
572
  return self
@@ -620,10 +741,10 @@ class UnitValue: # add specific heat
620
741
 
621
742
  def __round__(self, ndigits: int=0) -> 'UnitValue':
622
743
  """
623
- Rounds UnitValue to ndigts returns rounded Unitvale
744
+ Returns Rounded UnitValue to ndigts
624
745
  """
625
- self.value = round(self.value, ndigits)
626
- return self
746
+ value = round(self.value, ndigits)
747
+ return UnitValue(self.__system, self.__dimension, self.__unit, value)
627
748
 
628
749
  def __repr__(self) -> str:
629
750
  return f"{self.value} {self.__unit}"
@@ -674,7 +795,7 @@ class UnitValue: # add specific heat
674
795
  if func is np.concatenate:
675
796
  unit_cache = []
676
797
  for arr in args[0]:
677
- 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]
678
799
  for i in range(len(arr)):
679
800
  arr[i] = arr[i].value if isinstance(arr[i], UnitValue) else arr[i]
680
801
  new_array = np.concatenate(args[0], **kwargs)
@@ -710,58 +831,8 @@ class UnitValue: # add specific heat
710
831
  self.__unit = unit
711
832
  else:
712
833
  raise Exception(f"Unit {unit} invalid: Unit must be {list(UnitValue.UNITS[self.__system][self.__dimension].keys())} for {self.__system} {self.__dimension}")
713
-
714
- def copy(self) -> 'UnitValue':
715
- return UnitValue(self.__system, self.__dimension, self.__unit, self.value)
716
834
 
717
- def __temperature_handler(self, old_unit: str, new_unit: str): # add Rankine
718
- if new_unit == "K":
719
- if old_unit == "c":
720
- self.value += 273.15
721
- elif old_unit == "f":
722
- self.value = (self.value - 32) * (5/9) + 273.15
723
- elif old_unit == "R":
724
- self.value *= 5/9
725
- elif new_unit == "c":
726
- if old_unit == "K":
727
- self.value -= 273.15
728
- elif old_unit == "f":
729
- self.value = (self.value - 32) * (5/9)
730
- elif old_unit == "R":
731
- self.value = (self.value - 491.67) * (5/9)
732
- elif new_unit == "f":
733
- if old_unit == "K":
734
- self.value = ((self.value -273.15) / (5/9)) + 32
735
- elif old_unit == "c":
736
- self.value = (self.value / (5/9)) + 32
737
- elif old_unit == "R":
738
- self.value -= 459.67
739
- elif new_unit == "R":
740
- if old_unit == "c":
741
- self.value = self.value * (9/5) + 491.67
742
- elif old_unit == "f":
743
- self.value += 459.67
744
- elif old_unit == "K":
745
- self.value *= 1.8
746
-
747
- def __convert_temp(self, change_system: bool, unit: str=""):
748
- if change_system:
749
- self.__system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
750
- if unit in UnitValue.UNITS[self.__system][self.__dimension].keys():
751
- self.__temperature_handler(self.__unit, unit)
752
- self.__unit = unit
753
- else:
754
- raise Exception(f"Unit {unit} invalid: Unit must be {list(UnitValue.UNITS[self.__system][self.__dimension].keys())} for {self.__system} {self.__dimension}")
755
- elif unit:
756
- if unit in UnitValue.UNITS[self.__system][self.__dimension].keys():
757
- self.__temperature_handler(self.__unit, unit)
758
- self.__unit = unit
759
- else:
760
- raise Exception(f"Unit {unit} invalid: Unit must be {list(UnitValue.UNITS[self.__system][self.__dimension].keys())} for {self.__system} {self.__dimension}")
761
- else:
762
- raise Exception("No conversion performed as change_system was false and unit was empty")
763
-
764
- def convert_base_metric(self) -> 'UnitValue':
835
+ def convert_base_metric(self, **kwargs) -> 'UnitValue':
765
836
  """
766
837
  Convert the current value to it's base SI/Metric unit.
767
838
 
@@ -770,17 +841,74 @@ class UnitValue: # add specific heat
770
841
  """
771
842
  if self.__system is None:
772
843
  return
773
- elif self.__dimension != "TEMPERATURE":
774
- self.value *= UnitValue.UNITS[self.__system][self.__dimension][self.__unit]
775
- self.__system = "METRIC"
776
- 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
+
777
896
  else:
778
- self.__temperature_handler(self.__unit, "K")
779
- self.__system = "METRIC"
780
- 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
+
781
908
  return self
909
+
782
910
 
783
- def to(self, unit:str) -> 'UnitValue':
911
+ def to(self, unit:str, **kwargs) -> 'UnitValue':
784
912
  """
785
913
  Convert the current value to a new unit.
786
914
 
@@ -794,23 +922,24 @@ class UnitValue: # add specific heat
794
922
  Exception: If the unit is not recognized or conversion is not possible.
795
923
  """
796
924
  u = UnitValue.SPELLING_MAP.get(unit)
797
- if u: unit = u
925
+ if u: unit = u
926
+
927
+ if unit == self.unit: return self
798
928
 
799
929
  cache_key = (self.__system, self.__dimension, self.__unit, unit)
800
930
  if cache_key in self._conversion_cache:
801
931
  cached_value = self._conversion_cache[cache_key]
802
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}")
803
939
 
804
940
  other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
805
941
  if self.__system is None:
806
942
  raise Exception(f"Invalid unit {self.__unit}: this unit is not currently supported by the module")
807
- elif self.__dimension == "TEMPERATURE":
808
- if unit in UnitValue.UNITS[self.__system][self.__dimension]:
809
- self.__convert_temp(False, unit)
810
- elif unit in UnitValue.UNITS[other_system][self.__dimension]:
811
- self.__convert_temp(True, unit)
812
- else:
813
- raise TypeError(f"Cannot convert unit of dimension {self.__dimension} to {unit}")
814
943
  else:
815
944
  if unit in UnitValue.UNITS[self.__system][self.__dimension]:
816
945
  self.__convert_unit(unit)
@@ -821,6 +950,10 @@ class UnitValue: # add specific heat
821
950
 
822
951
  self._conversion_cache[cache_key] = self.value
823
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)
824
957
 
825
958
  def to_dict(self) -> dict:
826
959
  """
@@ -837,14 +970,13 @@ class UnitValue: # add specific heat
837
970
  }
838
971
 
839
972
  @property
840
- def get_unit(self) -> str:
973
+ def unit(self) -> str:
841
974
  return self.__unit
842
975
 
843
976
  @property
844
- def get_dimension(self) -> str:
977
+ def dimension(self) -> str:
845
978
  return self.__dimension
846
979
 
847
980
  @property
848
- def get_system(self) -> str:
849
- return self.__system
850
-
981
+ def system(self) -> str:
982
+ return self.__system
File without changes
File without changes
File without changes