UnitValues 0.1.3__tar.gz → 0.1.5__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.4
2
2
  Name: UnitValues
3
- Version: 0.1.3
3
+ Version: 0.1.5
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/
@@ -12,6 +12,7 @@ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: numpy>=1.23.2
15
+ Dynamic: license-file
15
16
 
16
17
  # UnitValues Package
17
18
  ## Introduction
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "UnitValues"
3
- version = "0.1.3"
3
+ version = "0.1.5"
4
4
  dependencies = [
5
5
  "numpy >= 1.23.2"
6
6
  ]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: UnitValues
3
- Version: 0.1.3
3
+ Version: 0.1.5
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/
@@ -12,6 +12,7 @@ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: numpy>=1.23.2
15
+ Dynamic: license-file
15
16
 
16
17
  # UnitValues Package
17
18
  ## Introduction
@@ -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
@@ -491,6 +612,10 @@ class UnitValue: # add specific heat
491
612
  if self.__unit != a.__unit:
492
613
  raise TypeError(f"Cannot add unit {self.__unit} and unit {a.__unit}")
493
614
  return UnitValue(self.__system, self.__dimension, self.__unit, self.value + a.value)
615
+ if self.__dimension == "TEMPERATURE" and self.__unit != "K" or a.__unit != "K":
616
+ self.convert_base_metric()
617
+ a.convert_base_metric()
618
+ return UnitValue(self.__system, self.__dimension, self.__unit, self.value + a.value - 273.15)
494
619
  self.convert_base_metric()
495
620
  a.convert_base_metric()
496
621
  return UnitValue(self.__system, self.__dimension, self.__unit, self.value + a.value)
@@ -515,6 +640,10 @@ class UnitValue: # add specific heat
515
640
  if self.__unit != s.__unit:
516
641
  raise TypeError(f"Cannot subtract unit {self.__unit} and unit {s.__unit}")
517
642
  return UnitValue(self.__system, self.__dimension, self.__unit, self.value - s.value)
643
+ if self.__dimension == "TEMPERATURE" and self.__unit != "K" or s.__unit != "K":
644
+ self.convert_base_metric()
645
+ s.convert_base_metric()
646
+ return UnitValue(self.__system, self.__dimension, self.__unit, self.value - s.value + 273.15)
518
647
  self.convert_base_metric()
519
648
  s.convert_base_metric()
520
649
  return UnitValue(self.__system, self.__dimension, self.__unit, self.value - s.value)
@@ -620,10 +749,10 @@ class UnitValue: # add specific heat
620
749
 
621
750
  def __round__(self, ndigits: int=0) -> 'UnitValue':
622
751
  """
623
- Rounds UnitValue to ndigts returns rounded Unitvale
752
+ Returns Rounded UnitValue to ndigts
624
753
  """
625
- self.value = round(self.value, ndigits)
626
- return self
754
+ value = round(self.value, ndigits)
755
+ return UnitValue(self.__system, self.__dimension, self.__unit, value)
627
756
 
628
757
  def __repr__(self) -> str:
629
758
  return f"{self.value} {self.__unit}"
@@ -674,7 +803,7 @@ class UnitValue: # add specific heat
674
803
  if func is np.concatenate:
675
804
  unit_cache = []
676
805
  for arr in args[0]:
677
- unit_cache += [item.get_unit if isinstance(item, UnitValue) else None for item in arr]
806
+ unit_cache += [item.unit if isinstance(item, UnitValue) else None for item in arr]
678
807
  for i in range(len(arr)):
679
808
  arr[i] = arr[i].value if isinstance(arr[i], UnitValue) else arr[i]
680
809
  new_array = np.concatenate(args[0], **kwargs)
@@ -710,58 +839,8 @@ class UnitValue: # add specific heat
710
839
  self.__unit = unit
711
840
  else:
712
841
  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
842
 
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':
843
+ def convert_base_metric(self, **kwargs) -> 'UnitValue':
765
844
  """
766
845
  Convert the current value to it's base SI/Metric unit.
767
846
 
@@ -770,17 +849,74 @@ class UnitValue: # add specific heat
770
849
  """
771
850
  if self.__system is None:
772
851
  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]
852
+
853
+ if self.__unit == "SCFM" or self.__unit == "SLPM":
854
+ try:
855
+ return self.__standard_flowrate_handler("m^3/s", kwargs["temperature"], kwargs["pressure"])
856
+ except Exception as e:
857
+ 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}")
858
+
859
+ self.value *= UnitValue.UNITS[self.__system][self.__dimension][self.__unit]
860
+ self.__system = "METRIC"
861
+ self.__unit = list(UnitValue.UNITS[self.__system][self.__dimension].keys())[0]
862
+ return self
863
+
864
+ def __standard_flowrate_handler(self, unit:str, temperature: 'UnitValue', pressure: 'UnitValue') -> 'UnitValue':
865
+ '''Handles the standard flow rate conversions which involve knwoing orher properties opf the fluid'''
866
+ std_temp = UnitValue("METRIC", "TEMPERATURE", "K", 273.15)
867
+ std_pressure = UnitValue("IMPERIAL", "PRESSURE", "psi", 14.504)
868
+ if self.__unit == "SLPM":
869
+ if unit == "SCFM":
870
+ self.value /= 28.316847
871
+ self.__dimension = "IMPERIAL"
872
+ self.__unit = "SCFM"
873
+ return self
874
+
875
+ self.value = (self.value * (temperature/std_temp) * (std_pressure/pressure)) / 60000 # converted to base metric
876
+ other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
877
+ if unit in UnitValue.UNITS[self.__system][self.__dimension]:
878
+ self.value /= UnitValue.UNITS[self.__system][self.__dimension][unit]
879
+ elif unit in UnitValue.UNITS[other_system][self.__dimension]:
880
+ self.value /= UnitValue.UNITS[other_system][self.__dimension][unit]
881
+ self.__system = other_system
882
+ else:
883
+ raise TypeError(f"Cannot convert unit of dimension {self.__dimension} to {unit}")
884
+ self.__unit = unit
885
+
886
+ elif self.__unit == "SCFM":
887
+ if unit == "SLPM":
888
+ self.value *= 28.316847
889
+ self.__dimension = "METRIC"
890
+ self.__unit = "SLPM"
891
+ return self
892
+
893
+ self.value = ((self.value*28.316847) * (temperature/std_temp) * (std_pressure/pressure)) / 60000 # converted to base metric
894
+ other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
895
+ if unit in UnitValue.UNITS[self.__system][self.__dimension]:
896
+ self.value /= UnitValue.UNITS[self.__system][self.__dimension][unit]
897
+ elif unit in UnitValue.UNITS[other_system][self.__dimension]:
898
+ self.value /= UnitValue.UNITS[other_system][self.__dimension][unit]
899
+ self.__system = other_system
900
+ else:
901
+ raise TypeError(f"Cannot convert unit of dimension {self.__dimension} to {unit}")
902
+ self.__unit = unit
903
+
777
904
  else:
778
- self.__temperature_handler(self.__unit, "K")
779
- self.__system = "METRIC"
780
- self.__unit = "K"
905
+ self.value *= UnitValue.UNITS[self.__system][self.__dimension][self.__unit]
906
+ if unit == "SLPM":
907
+ self.value = (self.value * 60000) * (std_temp/temperature) * (pressure/std_pressure)
908
+ self.__system = "METRIC"
909
+ self.__unit = "SLPM"
910
+
911
+ elif unit == "SCFM":
912
+ self.value = ((self.value * 60000) * (std_temp/temperature) * (pressure/std_pressure)) / 28.316847
913
+ self.__system = "IMPERIAL"
914
+ self.__unit = "SCFM"
915
+
781
916
  return self
917
+
782
918
 
783
- def to(self, unit:str) -> 'UnitValue':
919
+ def to(self, unit:str, **kwargs) -> 'UnitValue':
784
920
  """
785
921
  Convert the current value to a new unit.
786
922
 
@@ -794,23 +930,28 @@ class UnitValue: # add specific heat
794
930
  Exception: If the unit is not recognized or conversion is not possible.
795
931
  """
796
932
  u = UnitValue.SPELLING_MAP.get(unit)
797
- if u: unit = u
933
+ if u: unit = u
934
+
935
+ if unit == self.unit: return self
936
+
937
+ other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
798
938
 
799
939
  cache_key = (self.__system, self.__dimension, self.__unit, unit)
800
940
  if cache_key in self._conversion_cache:
801
941
  cached_value = self._conversion_cache[cache_key]
802
- return UnitValue(self.__system, self.__dimension, unit, cached_value)
942
+ if unit in UnitValue.UNITS[self.__system][self.__dimension]:
943
+ return UnitValue(self.__system, self.__dimension, unit, cached_value)
944
+ else:
945
+ return UnitValue(other_system, self.__dimension, unit, cached_value)
946
+
947
+ if unit == "SCFM" or unit == "SLPM" or self.__unit == "SCFM" or self.__unit == "SLPM":
948
+ try:
949
+ return self.__standard_flowrate_handler(unit, kwargs["temperature"], kwargs["pressure"])
950
+ except Exception as e:
951
+ 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
952
 
804
- other_system = "IMPERIAL" if self.__system == "METRIC" else "METRIC"
805
953
  if self.__system is None:
806
954
  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
955
  else:
815
956
  if unit in UnitValue.UNITS[self.__system][self.__dimension]:
816
957
  self.__convert_unit(unit)
@@ -821,6 +962,10 @@ class UnitValue: # add specific heat
821
962
 
822
963
  self._conversion_cache[cache_key] = self.value
823
964
  return self
965
+
966
+ def copy(self) -> 'UnitValue':
967
+ '''Returns copy of the unit that can be used without changing the original unit, i.e. not a soft copy'''
968
+ return UnitValue(self.__system, self.__dimension, self.__unit, self.value)
824
969
 
825
970
  def to_dict(self) -> dict:
826
971
  """
@@ -837,14 +982,15 @@ class UnitValue: # add specific heat
837
982
  }
838
983
 
839
984
  @property
840
- def get_unit(self) -> str:
985
+ def unit(self) -> str:
841
986
  return self.__unit
842
987
 
843
988
  @property
844
- def get_dimension(self) -> str:
989
+ def dimension(self) -> str:
845
990
  return self.__dimension
846
991
 
847
992
  @property
848
- def get_system(self) -> str:
993
+ def system(self) -> str:
849
994
  return self.__system
850
995
 
996
+
File without changes
File without changes
File without changes