""" Tests the functionality in the openmm.unit package. """ from __future__ import division from openmm import unit as u import copy import math import unittest try: import numpy as np except ImportError: np = None try: from itertools import izip as zip except ImportError: pass # Python 3... zip _is_ izip class QuantityTestCase(unittest.TestCase): def assertAlmostEqualQuantities(self, item1, item2, places=6): try: val1 = item1.value_in_unit(item1.unit) val2 = item2.value_in_unit(item1.unit) except TypeError: raise self.failureException('Incompatible units %s and %s' % (item1.unit, item2.unit)) try: if len(val1) != len(val2): raise self.failureException('collections are different lengths') for x, y in zip(val1, val2): self.assertAlmostEqual(x, y, places=places) except TypeError: self.assertAlmostEqual(val1, val2, places=places) class TestUnits(QuantityTestCase): def testBaseUnit(self): """ Tests the creation of a base unit furlong """ furlong = u.BaseUnit(u.length_dimension, "furlong", "fur") furlong.define_conversion_factor_to(u.meter_base_unit, 201.168) self.assertEqual(furlong.conversion_factor_to(u.angstrom_base_unit), 201.168e10) def testIsUnit(self): """ Tests the unit.is_unit introspective function """ self.assertTrue(u.is_unit(u.meters)) self.assertFalse(u.is_unit(None)) self.assertFalse(u.is_unit(10)) # Distinguish between "units" and "quantities" self.assertFalse(u.is_unit(1*u.meters)) def testCalorieConversion(self): """ Tests unit conversion with calories to joules """ c = 1.0 * u.calories j = 1.0 * u.joules j2c = j.in_units_of(u.calories) self.assertNotEqual(c, 1.0) # Units do not equal scalars! self.assertIs(c.unit, u.calories) self.assertEqual(c._value, 1) self.assertEqual(u.calorie.conversion_factor_to(u.joule), 4.184) self.assertEqual(u.joule.conversion_factor_to(u.calorie), 1/4.184) self.assertIs(j2c.unit, u.calories) self.assertEqual(j2c._value, 1/4.184) self.assertEqual(c / u.calories, 1.0) # Dimensionless now self.assertEqual(j / u.calories, j2c._value) c2 = c**2 cc = c * c self.assertEqual(cc, c2) self.assertTrue(c2.unit, u.calories**2) self.assertEqual(c2.in_units_of(u.joules**2), (4.184*u.joules)**2) def testScaledUnit(self): """ Tests ScaledUnit class with kilokelvins """ kK = u.ScaledUnit(1000.0, u.kelvin, "kilokelvin", "kK") self.assertIs(kK.master, u.kelvin) self.assertEqual(kK.factor, 1000) self.assertEqual(str(kK), 'kilokelvin') self.assertEqual(kK.name, 'kilokelvin') self.assertEqual(kK.symbol, 'kK') def testComparisonOperators(self): """ Tests unit comparison operators """ self.assertGreater(u.meters, u.centimeters) self.assertLess(u.angstroms, u.centimeters) def testUnitDivision(self): """ Tests the division of units and is_dimensionless """ mps = u.meter / u.second mpm = u.meter / u.meter mpc = u.meter / u.centimeter self.assertTrue(u.is_unit(mps)) self.assertTrue(u.is_unit(mpm)) self.assertTrue(u.is_unit(mpc)) self.assertFalse(mps.is_dimensionless()) self.assertTrue(mpm.is_dimensionless()) self.assertTrue(mpc.is_dimensionless()) def testCompositeUnits(self): """ Tests the creation of a composite unit """ mps = u.Unit({u.meter_base_unit : 1.0, u.second_base_unit : -1.0}) self.assertTrue(u.is_unit(mps)) self.assertEqual(str(mps), 'meter/second') def testUnitSystem(self): """ Tests the creation of a UnitSystem and its behavior """ us = u.UnitSystem([u.ScaledUnit(1.0, u.coulomb/u.second, 'ampere', 'A'), u.second_base_unit]) self.assertEqual(us.express_unit(u.second), u.second) self.assertEqual(us.express_unit(u.hour), u.second) self.assertNotEqual(u.hour, u.second) self.assertEqual(us.express_unit(u.coulomb/u.second), u.ampere) self.assertEqual(us.express_unit(u.meter/u.second), u.meter/u.second) self.assertEqual(us.express_unit(u.kilometer/u.hour), u.kilometer/u.second) x = 100 * u.millimeters self.assertEqual(x.value_in_unit_system(u.si_unit_system), 0.1) self.assertEqual(x.value_in_unit_system(u.cgs_unit_system), 10.0) self.assertAlmostEqual(x.value_in_unit_system(u.md_unit_system), 1e8) y = 20 * u.millimeters / u.millisecond**2 self.assertAlmostEqual(y.value_in_unit_system(u.si_unit_system), 2e4) self.assertAlmostEqual(y.value_in_unit_system(u.cgs_unit_system), 2e6) self.assertAlmostEqual(y.value_in_unit_system(u.md_unit_system), 2e-11, places=18) kcal = 1 * u.md_kilocalorie / u.mole self.assertEqual(kcal.value_in_unit_system(u.md_unit_system), 4.184) def testUnitSqrt(self): """ Tests taking the square root of units """ self.assertEqual((u.meter * u.meter).sqrt(), u.meter) self.assertEqual((u.meter**4).sqrt(), u.meter**2) def testQuantitySqrt(self): """ Tests taking the square root of quantities """ self.assertEqual((9.0*u.meters**2).sqrt(), 3.0*u.meters) self.assertEqual((9.0*u.meters**2/u.second**2).sqrt(), 3.0*u.meters/u.second) def testUnitBadSqrt(self): """ Tests that illegal sqrt calls on incompatible units fails """ mps2 = u.meters/u.second**2 self.assertRaises(ArithmeticError, lambda: u.meter.sqrt()) self.assertRaises(ArithmeticError, lambda: (u.meters**3).sqrt()) self.assertRaises(ArithmeticError, lambda: mps2.sqrt()) def testQuantityBadSqrt(self): " Tests that taking sqrt of Quantities with incompatible units fails " self.assertRaises(ArithmeticError, lambda: (9.0*u.meters).sqrt()) self.assertRaises(ArithmeticError, lambda: (9.0*u.meters**3).sqrt()) def testBaseScaleMix(self): """ Test mixing of BaseUnit and ScaledUnit instances """ kgj = u.kilogram * u.joule self.assertTrue(u.is_unit(kgj)) self.assertEqual(str(kgj.sqrt()), 'kilogram*meter/second') def testGetUnitAttributes(self): """ Tests the unit attribute `getters' """ self.assertEqual(u.newton.get_name(), 'newton') self.assertEqual(u.newtons.get_name(), 'newton') self.assertEqual(u.newton.get_symbol(), 'N') self.assertEqual(u.ampere.get_symbol(), 'A') self.assertEqual(u.meter.get_name(), 'meter') self.assertEqual(u.meter.get_symbol(), 'm') def testPresetUnitSystems(self): """ Tests some of the pre-set UnitSystem's """ self.assertEqual(u.angstrom.in_unit_system(u.si_unit_system), u.meter) self.assertEqual(u.angstrom.in_unit_system(u.cgs_unit_system), u.centimeter) self.assertEqual(u.angstrom.in_unit_system(u.md_unit_system), u.nanometer) mps = u.meter / u.second**2 self.assertEqual(str(mps), 'meter/(second**2)') self.assertEqual(mps.in_unit_system(u.si_unit_system), mps) self.assertEqual(mps.in_unit_system(u.cgs_unit_system), u.centimeter/u.second**2) self.assertEqual(mps.in_unit_system(u.md_unit_system), u.nanometer/u.picosecond**2) def testIsCompatible(self): """ Tests the is_compatible attribute of units """ self.assertTrue(u.meter.is_compatible(u.centimeter)) self.assertTrue(u.centimeter.is_compatible(u.meter)) self.assertTrue(u.meter.is_compatible(u.meter)) self.assertTrue(u.joule.is_compatible(u.calorie)) self.assertFalse(u.meter.is_compatible(u.kelvin)) self.assertFalse(u.meter.is_compatible(u.meter/u.second)) self.assertFalse(u.meter.is_compatible(u.joule)) def testConversionFactorTo(self): """ Tests the "conversion_factor_to" attribute of Units """ self.assertEqual(u.meter.conversion_factor_to(u.centimeter), 100) self.assertEqual(u.kilocalorie.conversion_factor_to(u.joule), 4184) self.assertEqual(u.calorie.conversion_factor_to(u.kilojoule), 4.184e-3) self.assertEqual((u.kilocalorie/u.mole/u.angstrom).conversion_factor_to( u.kilojoule/u.mole/u.nanometer), 41.84) def testUnitString(self): """ Test the Unit->str casting functionality """ # Always alphabetical order self.assertEqual(str(u.meter * u.second * u.second * u.kilogram), 'kilogram*meter*second**2') self.assertEqual(str(u.meter / u.second / u.second / u.kilogram), 'meter/(kilogram*second**2)') self.assertEqual(str(u.meter**3), 'meter**3') def testToBaseUnit(self): """ Tests the "get_conversion_factor_to_base_units" method """ self.assertEqual(u.meter.get_conversion_factor_to_base_units(), 1) self.assertEqual(u.calorie.get_conversion_factor_to_base_units(), 4.184) kcpma = u.md_kilocalorie/u.mole/u.angstrom self.assertEqual(kcpma.get_conversion_factor_to_base_units(), 4.184) def testScalarQuantityMultiplyDivide(self): """ Tests creating a scalar Quantity object by * or / by a Unit """ self.assertTrue(u.is_quantity(5 * u.centimeters)) self.assertTrue(u.is_quantity(1 / u.centimeters)) self.assertTrue(u.is_quantity(10 * u.centimeters)) self.assertTrue(u.is_quantity(9.81 * u.meters / u.second**2)) def testScalarQuantityConstructor(self): """ Tests creating a Quantity using the Quantity constructor """ self.assertTrue(u.is_quantity(u.Quantity(5, u.centimeters))) self.assertTrue(u.is_quantity(u.Quantity(5, u.centimeters**-1))) x = u.Quantity(value=5.0, unit=100.0*u.meters) self.assertTrue(u.is_quantity(x)) self.assertEqual(x, 500*u.meters) def testValueInUnit(self): """ Tests the value_in_unit functionality for Quantity """ i = 5 * u.centimeters self.assertEqual(i.value_in_unit(u.millimeters), 50) self.assertEqual(i / u.millimeters, 50) def testCollectionQuantities(self): """ Tests the use of collections as Quantity values """ s = [1, 2, 3] * u.centimeters self.assertEqual(str(s), '[1, 2, 3] cm') self.assertTrue(u.is_quantity(s)) s2 = s / u.millimeters self.assertEqual(s2, [10.0, 20.0, 30.0]) self.assertEqual(s2, s.value_in_unit(u.millimeters)) # Test 2-D list s = [[1, 2, 3], [4, 5, 6]] s *= u.centimeters self.assertTrue(u.is_quantity(s)) s2 = s / u.millimeters self.assertEqual(s2, [[10.0, 20.0, 30.0], [40.0, 50.0, 60.0]]) self.assertEqual(s.value_in_unit(u.millimeters), s2) # Test tuples s = (1, 2, 3) * u.centimeters self.assertTrue(u.is_quantity(s)) self.assertEqual(str(s), '(1, 2, 3) cm') s2 = s / u.millimeters self.assertEqual(s2, (10, 20, 30)) self.assertIsInstance(s2, tuple) self.assertEqual(s.value_in_unit(u.millimeters), s2) self.assertIsInstance(s.value_in_unit(u.millimeters), tuple) x = [1, 2, 3] * u.centimeters x *= u.meters self.assertEqual(x, [100, 200, 300] * u.centimeters**2) def testReduceUnit(self): """ Tests the reduce_unit functionality """ x = u.nanometer**2 / u.angstrom**2 self.assertEqual(str(x), 'nanometer**2/(angstrom**2)') self.assertTrue(x.is_dimensionless()) q = u.Quantity(2.0, x) self.assertEqual(str(q), '2.0 nm**2/(A**2)') self.assertEqual(q.reduce_unit(), 200) def testCollectionQuantityOperations(self): """ Tests that Quantity collections behave correctly """ # Tests that __getitem__ returns a unit s = [1, 2, 3, 4] * u.angstroms self.assertTrue(u.is_quantity(s[0])) for i, val in enumerate(s): self.assertTrue(u.is_quantity(val)) self.assertEqual(val, (i+1) * u.angstroms) # Tests that __setitem__ fails when an incompatible type is added def fail(s): s[0] = 5 self.assertRaises(AttributeError, lambda: fail(s)) def fail(s): s[0] = 5 * u.joules self.assertRaises(TypeError, lambda: fail(s)) def fail(s): s[0] /= 10 * u.meters self.assertRaises(AttributeError, lambda: fail(s)) # Tests that __setitem__ converts to the unit of the container s[0] = 1 * u.nanometers self.assertEqual(s[0]._value, 10) # Tests that __setitem__ handles slice assignment correctly x = [0, 1, 2, 3, 4] * u.kelvin x[2:4] = [-2, -3] * u.kelvin self.assertEqual(x._value, [0, 1, -2, -3, 4]) # Tests standard unit conversions x = [1, 2, 3] * u.centimeters self.assertEqual(x / u.millimeters, [10, 20, 30]) # Test the construction of a container in which each element is a # Quantity, passed to the Quantity constructor x = u.Quantity([1*u.angstrom, 2*u.nanometer, 3*u.angstrom]) self.assertEqual(x._value, [1, 20, 3]) self.assertEqual(x.unit, u.angstrom) x = u.Quantity((1, 2, 3)) self.assertTrue(u.is_quantity(x)) self.assertTrue(x.unit.is_dimensionless()) x = u.Quantity(([1*u.angstrom, 2*u.nanometer, 3*u.angstrom], [1*u.angstrom, 4*u.nanometer, 3*u.angstrom])) self.assertEqual(x._value, ([1, 20, 3], [1, 40, 3])) self.assertEqual(x.unit, u.angstrom) self.assertTrue(u.is_quantity(u.Quantity([]))) def testMutableQuantityOperations(self): " Tests that mutable Quantity objects do not get unexpectedly changed " # This used to be a bug -- t and s._value were the same object, so # changing t would also change s silently s = [1, 2, 3, 4] * u.angstroms t = s / u.angstroms self.assertEqual(t, [1, 2, 3, 4]) self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms)) t[0] = 2 self.assertEqual(t, [2, 2, 3, 4]) self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms)) t = s.value_in_unit(u.angstroms) self.assertEqual(t, [1, 2, 3, 4]) self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms)) t[0] = 2 self.assertEqual(t, [2, 2, 3, 4]) self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms)) s = [1, 2, 3, 4] * u.nanometers self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.nanometers)) t = s.in_units_of(u.nanometers) self.assertEqual(s, t) t[0] = 1 * u.meters self.assertAlmostEqualQuantities(t, u.Quantity([1e9, 2, 3, 4], u.nanometers)) self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.nanometers)) def testQuantityMaths(self): """ Tests dimensional analysis & maths on and b/w Quantity objects """ x = 1.3 * u.meters y = 75.2 * u.centimeters self.assertEqual((x + y) / u.meters, 2.052) self.assertEqual((x - y) / u.meters, 0.548) self.assertEqual(x / y, 1.3 / 0.752) self.assertEqual(x * y, 1.3*0.752*u.meters**2) d1 = 2.0*u.meters d2 = 2.0*u.nanometers self.assertEqual(d1 + d2, (2+2e-9)*u.meters) self.assertAlmostEqual((d2+d1-(2e9+2)*u.nanometers)._value, 0, places=6) self.assertEqual(d1 + d1, 4.0*u.meters) self.assertEqual(d1 - d1, 0.0*u.meters) self.assertEqual(d1 / d1, 1.0) self.assertEqual(d1 * u.meters, 2.0*u.meters**2) self.assertEqual(u.kilograms*(d1/u.seconds)*(d1/u.seconds), 4*u.kilograms*u.meters**2/u.seconds**2) self.assertEqual(u.kilograms*(d1/u.seconds)**2, 4*u.kilograms*u.meters**2/u.seconds**2) self.assertEqual(d1**3, 8.0*u.meters**3) x = d1**(3/2) self.assertAlmostEqual(x._value, math.sqrt(2)**3) self.assertEqual(x.unit, u.meters**(3/2)) self.assertAlmostEqual((d1**0.5)._value, math.sqrt(2)) self.assertEqual((d1**0.5).unit, u.meters**0.5) comp = (3.0 + 4.0j) * u.meters self.assertTrue(u.is_quantity(comp)) self.assertEqual(comp.unit, u.meters) self.assertEqual(str(comp), '(3+4j) m') self.assertEqual(comp + comp, (6.0 + 8.0j)*u.meters) self.assertEqual(comp - comp, 0*u.meters) self.assertEqual(comp * comp, (3.0 + 4.0j)**2 * u.meters**2) self.assertAlmostEqual(comp / comp, 1) self.assertAlmostEqual(1.5*u.nanometers / u.meters, 1.5e-9, places=15) self.assertEqual((2.3*u.meters)**2, 2.3**2*u.meters**2) x = 4.3 * u.meters self.assertEqual(x / u.centimeters, 430) self.assertEqual(str(x / u.seconds), '4.3 m/s') self.assertEqual(str(8.4 / (4.2*u.centimeters)), '2.0 /cm') x = 1.2 * u.meters self.assertEqual(x * 5, u.Quantity(6.0, u.meters)) def testQuantityComplicatedMaths(self): """ Tests a complicated set of mathematical operations on a Quantity """ s1 = 2.0 x1 = 2 x2 = 4.0 / 3.0 u1 = u.kilogram * u.meter / u.second**2 u2 = u1 * u.meter q1 = 1.0 * u1 q2 = 2.0 * u2 self.assertEqual(s1, 2.0) self.assertEqual(x1, 2) self.assertAlmostEqual(x2, 1.33333333333333) self.assertEqual(str(u1), 'kilogram*meter/(second**2)') self.assertEqual(str(u2), 'kilogram*meter**2/(second**2)') self.assertEqual(str(q1), '1.0 kg m/(s**2)') self.assertEqual(str(q2), '2.0 kg m**2/(s**2)') self.assertEqual(str(u1*s1), '2.0 kg m/(s**2)') self.assertEqual(str(s1*u1), '2.0 kg m/(s**2)') self.assertEqual(str(u1/s1), '0.5 kg m/(s**2)') self.assertEqual(str(s1/u1), '2.0 s**2/(kg m)') self.assertEqual(str(u1*u1), 'kilogram**2*meter**2/(second**4)') self.assertEqual(u1/u1, u.dimensionless) self.assertEqual(str(u1/u1), 'dimensionless') self.assertEqual(str(u1*u2), 'kilogram**2*meter**3/(second**4)') self.assertEqual(u1/u2, u.meters**-1) self.assertEqual(str(u1/u2), '/meter') self.assertEqual(u1**x1, u.kilogram**2*u.meter**2/(u.second**4)) self.assertEqual(u1**(1/x1), u.kilogram**0.5*u.meter**0.5/u.second) self.assertEqual(u1**x2, u.kilogram**(1+1/3)*u.meter**(1+1/3)/u.second**(2+2/3)) q = 1.0 * u.md_kilocalorie/u.mole/u.angstrom self.assertEqual(str(q.in_units_of(u.md_kilojoule/u.mole/u.nanometer)), '41.84 kJ/(nm mol)') def testQuantityComparisons(self): """ Tests binary comparison operators between Quantity """ l1 = 1.0 * u.meters l2 = 2.0 * u.meters l3 = 1.0 * u.meters self.assertEqual(l1, l3) self.assertNotEqual(l1, l2) self.assertLessEqual(l1, l2) self.assertLess(l1, l2) self.assertGreater(l2, l1) self.assertGreaterEqual(l2, l1) self.assertLessEqual(l1, l3) self.assertGreaterEqual(l1, l3) self.assertGreater(1.2*u.meters, 72*u.centimeters) self.assertLess(1*u.meters, 200*u.centimeters) def testChemistryProblems(self): """ Tests some gen-chem applications with Quantity's """ def work(f, dx): return f * dx F = 1.0 * u.kilogram * u.meter / u.second**2 dx = 1.0 * u.meter self.assertEqual(work(F, dx), 1.0 * u.joule) self.assertEqual(F, 1.0 * u.newton) def ideal_gas_law(P, V, T): R = u.MOLAR_GAS_CONSTANT_R return (P * V / (R * T)).in_units_of(u.mole) T = (273.0 + 37.0) * u.kelvin P = (1.01325e5) * u.pascals r = 0.5e-6 * u.meters V = 4/3 * math.pi * r**3 n = ideal_gas_law(P, V, T) val = 4/3*math.pi*0.5e-6**3*1 self.assertAlmostEqualQuantities(P*V, val * u.atmospheres*u.meters**3) self.assertAlmostEqualQuantities(n, 2.05834818672e-17 * u.mole) self.assertAlmostEqualQuantities(V, 5.2359833333333e-19 * u.meters**3) self.assertEqual(str(T), '310.0 K') self.assertEqual(str(1*u.joules/u.kelvin/u.mole), '1 J/(K mol)') self.assertTrue(u.is_quantity(V)) # Checks trouble with complicated unit conversion factors p1 = 1.0 * u.atmospheres p2 = p1.in_units_of(u.joules/u.nanometers**3) V = 2.4 * u.nanometers**3 beta = 4.e-4 * u.mole/u.joule x1 = beta * p1 * V y1 = x1 * u.AVOGADRO_CONSTANT_NA self.assertAlmostEqual(y1, 0.0585785776197) x2 = beta * p2 * V y2 = x2 * u.AVOGADRO_CONSTANT_NA self.assertAlmostEqual(y1, y2) def testAngleQuantities(self): """ Tests angle measurements """ self.assertEqual(1.0*u.radians / u.degrees, 180 / math.pi) self.assertTrue(u.is_quantity(1.0*u.radians)) self.assertTrue(u.is_quantity(1.0*u.degrees)) self.assertEqual((1.0*u.radians).in_units_of(u.degrees), (180 / math.pi)*u.degrees) self.assertEqual(90*u.degrees/u.radians, math.pi/2) q = 90 * u.degrees + 0.3 * u.radians self.assertEqual(q._value, 90 + 180*0.3/math.pi) self.assertEqual(q.unit, u.degrees) def testIsQuantity(self): """ Tests if is_quantity can detect Quantities vs. scalars and units """ self.assertTrue(u.is_quantity(1/u.second)) self.assertFalse(u.is_quantity(u.second**-1)) self.assertTrue(u.is_quantity(10*u.meters)) self.assertFalse(u.is_quantity(10)) def testBadQuantityMaths(self): """ Tests that Maths of incompatible units properly fails """ self.assertRaises(TypeError, lambda:1*u.meters + 1*u.liters) self.assertRaises(AttributeError, lambda: 1*u.liters + 5) def testBadQuantityComparisons(self): """ Checks that comparisons of incompatible units fails """ self.assertRaises(TypeError, lambda: 1*u.meters > 1*u.liters) self.assertRaises(TypeError, lambda: 1*u.nanometers > 1*u.degrees) def testDimensionless(self): """ Tests the properties of unit.dimensionless """ x = 5 * u.dimensionless y = u.Quantity(5, u.dimensionless) self.assertTrue(u.is_quantity(x)) self.assertTrue(u.is_quantity(y)) self.assertNotEqual(x, 5) self.assertNotEqual(y, 5) self.assertEqual(x, y) self.assertEqual(x.value_in_unit_system(u.si_unit_system), 5) self.assertEqual(x.value_in_unit_system(u.cgs_unit_system), 5) self.assertEqual(x.value_in_unit_system(u.md_unit_system), 5) x = u.Quantity(1.0, u.dimensionless) y = u.Quantity(1.0, u.dimensionless) self.assertIsNot(x, y) self.assertEqual(x, y) def testTruthiness(self): """ Tests the truthiness of units """ true = 2.3 * u.meters false = 0.0 * u.meters self.assertTrue(true) self.assertFalse(false) self.assertTrue(bool(true)) self.assertFalse(bool(false)) def testUnaryOperators(self): """ Tests unary operators on units """ self.assertEqual(-(2.3*u.meters), u.Quantity(-2.3, u.meters)) self.assertEqual(-(2.3*u.meters), -u.Quantity(2.3, u.meters)) self.assertEqual(+(2.3*u.meters), u.Quantity(2.3, u.meters)) self.assertEqual(2.3*u.meters, +u.Quantity(2.3, u.meters)) def testUnitMathModule(self): """ Tests the unit_math functions on Quantity objects """ self.assertEqual(u.sqrt(1.0*u.kilogram*u.joule), 1.0*u.kilogram*u.meter/u.second) self.assertEqual(u.sqrt(1.0*u.kilogram*u.calorie), math.sqrt(4.184)*u.kilogram*u.meter/u.second) self.assertEqual(u.sqrt(9), 3) # Test on a scalar self.assertEqual(u.sin(90*u.degrees), 1) self.assertEqual(u.sin(math.pi/2*u.radians), 1) self.assertEqual(u.sin(math.pi/2), 1) self.assertEqual(u.cos(180*u.degrees), -1) self.assertEqual(u.cos(math.pi*u.radians), -1) self.assertEqual(u.cos(math.pi), -1) self.assertAlmostEqual(u.tan(45*u.degrees), 1) self.assertAlmostEqual(u.tan(math.pi/4*u.radians), 1) self.assertAlmostEqual(u.tan(math.pi/4), 1) acos = u.acos(1.0) asin = u.asin(1.0) atan = u.atan(1.0) self.assertTrue(u.is_quantity(acos)) self.assertTrue(u.is_quantity(asin)) self.assertTrue(u.is_quantity(atan)) self.assertEqual(acos.unit, u.radians) self.assertEqual(asin.unit, u.radians) self.assertEqual(atan.unit, u.radians) self.assertEqual(acos.value_in_unit(u.degrees), 0) self.assertEqual(acos / u.radians, 0) self.assertEqual(asin.value_in_unit(u.degrees), 90) self.assertEqual(asin / u.radians, math.pi/2) self.assertAlmostEqual(atan.value_in_unit(u.degrees), 45) self.assertAlmostEqual(atan / u.radians, math.pi/4) # Check some sequence maths seq = [1, 2, 3, 4] * u.meters self.assertEqual(u.sum(seq), 10*u.meters) self.assertEqual(u.dot(seq, seq), (1+4+9+16)*u.meters**2) self.assertEqual(u.norm(seq), math.sqrt(30)*u.meters) def testUnitMathModuleBadInput(self): """ Tests that bad units to unit_math fails appropriately """ self.assertRaises(ArithmeticError, lambda: u.sqrt(9*u.meters)) self.assertRaises(TypeError, lambda: u.sin(1*u.meters)) def testBadQuantityConversions(self): """ Tests that conversions to incompatible units fails """ self.assertRaises(TypeError, lambda: (1.0*u.meters).in_units_of(u.seconds)) self.assertRaises(TypeError, lambda: (1.0*u.meters).value_in_unit(u.seconds)) def testCreateNewBaseUnit(self): """ Tests creating a new base unit """ ms = u.milli * u.second_base_unit self.assertIsInstance(ms, u.BaseUnit) self.assertEqual(repr(ms), 'BaseUnit(base_dim=BaseDimension("time"), name="millisecond", ' 'symbol="ms")') self.assertEqual(ms.conversion_factor_to(u.second_base_unit), 0.001) def testCreateNewScaledUnit(self): """ Tests creating a new ScaledUnit """ mC = u.milli * u.ScaledUnit(4.184, u.joule, "calorie", "cal") self.assertIsInstance(mC, u.ScaledUnit) self.assertEqual(repr(mC), "ScaledUnit(factor=0.004184, master=joule, name='millicalorie'," " symbol='mcal')") self.assertFalse(u.is_unit(mC)) def testCreateNewUnit(self): """ Tests creating a new Unit """ ms = u.milli * u.second self.assertTrue(u.is_unit(ms)) self.assertEqual(repr(ms), 'Unit({BaseUnit(base_dim=BaseDimension("time"), ' 'name="millisecond", symbol="ms"): 1.0})') def testIllegalQuantityOps(self): """ Test that illegal operations on Quantity objects fails """ self.assertRaises(TypeError, lambda: u.milli * (1.0 * u.second)) def testQuantityFormat(self): """ Tests the format method on Quantity instances """ x = 5.439999999 * u.picosecond self.assertEqual(x.format("%.3f"), '5.440 ps') def testQuantityCollectionMethods(self): """ Tests some sequence methods on Quantity objects (no numpy) """ seq = [1, 2, 3, 4] * u.meters self.assertEqual(seq.sum(), 10*u.meters) self.assertEqual(seq.mean(), 2.5*u.meters) self.assertEqual(seq.max(), 4*u.meters) self.assertEqual(seq.min(), 1*u.meters) self.assertAlmostEqual(seq.std(), 1.1180339887498949*u.meters) def testString(self): """ Tests unit handling with strings, which should be dimensionless """ s = u.Quantity("string") self.assertEqual(s.value_in_unit_system(u.md_unit_system), "string") def testMisc(self): """ Miscellaneous tests for the unit package """ self.assertTrue(u.meter is not None) self.assertFalse(u.meter is None) self.assertEqual(repr(1.2*u.meters), '1.2 m') class Foo(object): def bar(self): return 'bar' x = Foo() self.assertEqual(x.bar(), 'bar') y = x * u.nanometers self.assertEqual(y.bar(), 'bar') self.assertEqual(str(u.meters*u.centimeters), 'centimeter*meter') self.assertEqual(str(u.meters*u.meters), 'meter**2') self.assertEqual(str(u.meter*u.meter), 'meter**2') @unittest.skipIf(np is None, 'Skipping numpy units tests') class TestNumpyUnits(QuantityTestCase): def testNumpyQuantity(self): """ Tests that numpy arrays can form Quantity values """ q = u.Quantity(np.array([1, 2, 3]), u.centimeters) self.assertTrue(u.is_quantity(q)) self.assertIsInstance(q._value, np.ndarray) self.assertTrue(np.all(q / u.millimeters == np.array([1, 2, 3])*10)) def testNumpyDeepCopy(self): """ Check that deepcopy on numpy array does not strip units """ x = u.Quantity(np.zeros((2, 3)), u.nanometer) y = copy.deepcopy(x) self.assertTrue(np.all(x == y)) self.assertTrue(u.is_quantity(x)) self.assertTrue(u.is_quantity(y)) def testNumpyDivision(self): """ Tests that division of numpy Quantities works correctly """ x = u.Quantity(np.asarray([1., 2.]), u.nanometers) y = u.Quantity(np.asarray([3., 4.]), u.picoseconds) xy = x / y self.assertTrue(u.is_quantity(xy)) self.assertEqual(xy.unit, u.nanometers/u.picoseconds) self.assertEqual(xy[0].value_in_unit(u.nanometers/u.picoseconds), 1/3) self.assertEqual(xy[1].value_in_unit(u.nanometers/u.picoseconds), 0.5) def testNumpyIsString(self): """ Tests the internal _is_string method with numpy Quantities """ from openmm.unit.quantity import _is_string a = np.array([[1, 2, 3], [4, 5, 6]]) self.assertIsInstance("", str) self.assertTrue(_is_string("")) self.assertTrue(_is_string("t")) self.assertTrue(_is_string("test")) self.assertFalse(_is_string(3)) self.assertFalse(_is_string(a)) def testNumpyFunctions(self): """ Tests various numpy attributes that they result in Quantities """ a = u.Quantity(np.arange(10), u.seconds) self.assertEqual(a.max(), 9*u.seconds) self.assertEqual(a.min(), 0*u.seconds) self.assertEqual(a.mean(), 4.5*u.seconds) self.assertAlmostEqualQuantities(a.std(), 2.8722813232690143*u.seconds) b = a.reshape((5, 2)) self.assertTrue(u.is_quantity(b)) def testMultiplication(self): """ Tests that units override numpy.ndarray multiplication """ self.assertIsInstance(np.arange(10)*u.angstroms, u.Quantity) # This only works with versions of numpy > 1.7 due to a bug in older # versions. Since Travis-CI installs Python 1.6.1 from aptitude, and we # don't want it to report test failures *every time*, just disable this # particular test for the numpy versions known to be bad. if np.version.version > '1.7': x = np.array([1]) * u.liters self.assertIsInstance(x, u.Quantity) self.assertIsInstance(np.arange(10) * x, u.Quantity)