diff --git a/setup.py b/setup.py index 9d37014..fb77d5e 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name="pyqn", - version="1.4", + version="1.4.1", description="A package for managing physical units and quantities", long_description=long_description, long_description_content_type="text/x-rst", diff --git a/src/pyqn/dimensions.py b/src/pyqn/dimensions.py index ecaf6fb..b41d6a6 100644 --- a/src/pyqn/dimensions.py +++ b/src/pyqn/dimensions.py @@ -47,8 +47,7 @@ def __init__(self, dims=None, **kwargs): if not kwargs: self.dims = dims else: - print("bad initialisation of Dimensions object") - sys.exit(1) + raise ValueError("Bad initialisation of Dimensions object") else: # initialize by keyword arguments for dim_name in kwargs: diff --git a/src/pyqn/units.py b/src/pyqn/units.py index ac6e6c7..9b2ea6c 100644 --- a/src/pyqn/units.py +++ b/src/pyqn/units.py @@ -29,6 +29,10 @@ h, NA, c, kB = (6.62607015e-34, 6.02214076e23, 299792458.0, 1.380649e-23) +class UnitsConversionError(UnitsError): + pass + + class Units: """ A class to represent the units of a physical quantity. @@ -327,25 +331,25 @@ def kBT_conversion(self, other): else: raise UnitsError( "Failure in conversion of units: was expecting to " - "covert between energy and temperature" + "convert between energy and temperature" ) return fac / other.to_si() def mol_conversion(self, other): - from_dims = self.get_dims() # original unit dimensions - to_dims = other.get_dims() # desired unit dimensions - fac = self.to_si() # factor needed to conver to SI units + from_dims_Q = self.get_dims().dims[4] + to_dims_Q = other.get_dims().dims[4] - if from_dims.dims[4] == to_dims.dims[4]: - raise UnitsError( - "Failure in conversion of units: no " - "different in quantity dimensions between %s and %s" % from_dims, - to_dims, + # We can only remove or add the amount dimension in its entirity. + if from_dims_Q and to_dims_Q: + raise UnitsConversionError( + f"Cannot force molar conversion between {self} and {other}" ) - elif from_dims.dims[4] > to_dims.dims[4]: - fac = fac / (NA ** (from_dims.dims[4] - to_dims.dims[4])) + + fac = self.to_si() + if from_dims_Q: + fac = fac * NA**from_dims_Q else: - fac = fac * (NA ** (to_dims.dims[4] - from_dims.dims[4])) + fac = fac * NA**to_dims_Q return fac / other.to_si() def spec_conversion(self, other): diff --git a/tests/test_conversions.py b/tests/test_conversions.py index c31dda1..abc0842 100644 --- a/tests/test_conversions.py +++ b/tests/test_conversions.py @@ -31,13 +31,51 @@ def test_litres(self): self.assertEqual(u1.to_si(), 1.0e-3) def test_molar_units_conversion(self): + + u1 = Units("mol") + u2 = Units("1") + self.assertAlmostEqual(u1.conversion(u2, force="mol"), 6.02214076e23) + + u1 = Units("mol-1") + u2 = Units("1") + self.assertAlmostEqual(u1.conversion(u2, force="mol"), 1 / 6.02214076e23) + print(u1.dims.dims) + + u1 = Units("mol2") + u2 = Units("1") + self.assertAlmostEqual(u1.conversion(u2, force="mol"), 6.02214076e23**2) + + u1 = Units("mol-2") + u2 = Units("1") + self.assertAlmostEqual(u1.conversion(u2, force="mol"), 6.02214076e23**-2) + u1 = Units("kJ") - u2 = Units("J/mol") + u2 = Units("kJ.mol-1") with self.assertRaises(UnitsError) as cm: u1.conversion(u2, strict=True) self.assertAlmostEqual(u1.conversion(u2, force="mol"), 1.660e-21) + u3 = Units("cal.mol-1") + u4 = Units("eV") + self.assertAlmostEqual(u3.conversion(u4, force="mol"), 4.3364104350063916e-05) + + u9 = Units("nmol2.L-1") + u10 = Units("L-1") + self.assertAlmostEqual(u9.conversion(u10, force="mol"), 3.626617933325338e29) + + u5 = Units("J.mmol-1") + u6 = Units("J") + self.assertAlmostEqual(u5.conversion(u6, force="mol"), 1.6605390671738467e-21) + + u7 = Units("1") + u8 = Units("mol-2") + self.assertAlmostEqual(u7.conversion(u8, force="mol"), 2.757389993610589e-48) + + u9 = Units("nmol2.L-1") + u10 = Units("L-1") + self.assertAlmostEqual(u9.conversion(u10, force="mol"), 3.626617933325338e29) + def test_kBT_units_conversion(self): u1 = Units("K") u2 = Units("J")