#!/bin/env python """ Module simtk.unit.doctests Lots of in-place doctests would no longer work after I rearranged so that specific unit definitions are defined late. So those tests are here. Examples >>> furlong = BaseUnit(length_dimension, "furlong", "fur") Examples >>> furlong_base_unit = BaseUnit(length_dimension, "furlong", "fur") >>> furlong_base_unit.define_conversion_factor_to(meter_base_unit, 201.16800) >>> furlong_base_unit.conversion_factor_to(angstrom_base_unit) 2011680000000.0 Examples >>> furlong_base_unit = BaseUnit(length_dimension, "furlong", "fur") >>> furlong_base_unit.define_conversion_factor_to(meter_base_unit, 201.16800) Examples Some of these example test methods from Unit and Quantity from unit.is_unit >>> is_unit(meter) True >>> is_unit(5*meter) False >>> c = 1.0*calories >>> c Quantity(value=1.0, unit=calorie) >>> print calorie.conversion_factor_to(joule) 4.184 >>> print joule.conversion_factor_to(calorie) 0.239005736138 >>> c.in_units_of(joules) Quantity(value=4.1840000000000002, unit=joule) >>> j = 1.0*joules >>> j Quantity(value=1.0, unit=joule) >>> j.in_units_of(calories) Quantity(value=0.23900573613766729, unit=calorie) >>> j/joules 1.0 >>> print j/calories 0.239005736138 >>> print c/joules 4.184 >>> c/calories 1.0 >>> c**2 Quantity(value=1.0, unit=calorie**2) >>> (c**2).in_units_of(joule*joule) Quantity(value=17.505856000000001, unit=joule**2) >>> ScaledUnit(1000.0, kelvin, "kilokelvin", "kK") ScaledUnit(factor=1000.0, master=kelvin, name='kilokelvin', symbol='kK') >>> str(ScaledUnit(1000.0, kelvin, "kilokelvin", "kK")) 'kilokelvin' Examples >>> meters > centimeters True >>> angstroms > centimeters False Examples >>> print meter / second meter/second >>> print meter / meter dimensionless Heterogeneous units are not reduced unless they are in a quantity. >>> print meter / centimeter meter/centimeter Examples >>> meters_per_second = Unit({meter_base_unit: 1.0, second_base_unit: -1.0}) >>> print meters_per_second meter/second >>> us = UnitSystem([ScaledUnit(1.0, coulomb/second, "ampere", "A"), second_base_unit]) >>> print us.express_unit(second) second >>> print us.express_unit(coulomb/second) ampere >>> print us.express_unit(coulomb) second*ampere >>> print us.express_unit(meter/second) meter/second >>> us = UnitSystem([ScaledUnit(1.0, coulomb/second, "ampere", "A"), second_base_unit]) >>> print us UnitSystem([ampere, second]) Examples >>> meter.is_dimensionless() False >>> (meter/meter).is_dimensionless() True >>> print (meter*meter).sqrt() meter >>> meter.sqrt() Traceback (most recent call last): ... ArithmeticError: Exponents in Unit.sqrt() must be even. >>> (meter*meter*meter).sqrt() Traceback (most recent call last): ... ArithmeticError: Exponents in Unit.sqrt() must be even. >>> print (meter*meter/second/second).sqrt() meter/second Mixture of BaseUnits and ScaledUnits should cause no trouble: >>> print sqrt(kilogram*joule) kilogram*meter/second >>> print sqrt(kilogram*calorie) kilogram*meter/second Examples >>> newton.get_name() 'newton' >>> meter.get_name() 'meter' Examples >>> newton.get_symbol() 'N' >>> meter.get_symbol() 'm' Examples >>> print angstrom.in_unit_system(si_unit_system) meter >>> print angstrom.in_unit_system(cgs_unit_system) centimeter >>> print angstrom.in_unit_system(md_unit_system) nanometer >>> u = meter/second**2 >>> print u meter/(second**2) >>> print u.in_unit_system(si_unit_system) meter/(second**2) >>> print u.in_unit_system(cgs_unit_system) centimeter/(second**2) >>> print u.in_unit_system(md_unit_system) nanometer/(picosecond**2) Examples >>> meter.is_compatible(centimeter) True >>> meter.is_compatible(meter) True >>> meter.is_compatible(kelvin) False >>> meter.is_compatible(meter/second) False >>> joule.is_compatible(calorie) True Examples >>> meter.conversion_factor_to(centimeter) 100.0 >>> print (md_kilocalorie/mole/angstrom).conversion_factor_to(md_kilojoule/mole/nanometer) 41.84 Examples >>> print meter meter >>> print meter * second * second * kilogram kilogram*meter*second**2 >>> print meter / second / second / kilogram meter/(kilogram*second**2) Examples >>> print meter**3 meter**3 >>> print meter**3 meter**3 >>> meter.get_conversion_factor_to_base_units() 1.0 Simple ScaledUnit in calorie >>> print calorie.get_conversion_factor_to_base_units() 4.184 Compound ScaledUnit in md_kilocalorie >>> print md_kilocalorie.get_conversion_factor_to_base_units() 4.184 calorie in a more complex unit >>> print (md_kilocalorie/mole/angstrom).get_conversion_factor_to_base_units() 4.184 Examples Create simple Quantities with either the multiply operator or the Quantity constructor. >>> print 5 * centimeters 5 cm >>> print Quantity(value=5, unit=centimeter) 5 cm >>> print Quantity(5, centimeter) 5 cm Extract the underlying value using either division or the value_in_unit() method. >>> i = 5 * centimeters >>> print i / millimeters 50.0 >>> print i.value_in_unit(millimeters) 50.0 Collections of numbers can also be used as values. >>> s = [1,2,3] * centimeters >>> print s [1, 2, 3] cm >>> print s / millimeters [10.0, 20.0, 30.0] >>> s2 = [[1,2,3],[4,5,6]] * centimeters >>> print s2 [[1, 2, 3], [4, 5, 6]] cm >>> print s2 / millimeters [[10.0, 20.0, 30.0], [40.0, 50.0, 60.0]] >>> s3 = [(1,2,3),(4,5,6)] * centimeters >>> print s3 [(1, 2, 3), (4, 5, 6)] cm >>> print s3 / millimeters [[10.0, 20.0, 30.0], [40.0, 50.0, 60.0]] >>> s4 = ((1,2,3),(4,5,6)) * centimeters >>> print s4 ((1, 2, 3), (4, 5, 6)) cm >>> print s4 / millimeters [[10.0, 20.0, 30.0], [40.0, 50.0, 60.0]] >>> t = (1,2,3) * centimeters >>> print t (1, 2, 3) cm >>> print t / millimeters [10.0, 20.0, 30.0] Numpy examples are commented out because not all systems have numpy installed # >>> import numpy # >>> # >>> a = Quantity(numpy.array([1,2,3]), centimeters) # >>> print a # [1 2 3] cm # >>> print a / millimeters # [ 10. 20. 30.] # >>> # >>> a2 = Quantity(numpy.array([[1,2,3],[4,5,6]]), centimeters) # >>> print a2 # [[1 2 3] # [4 5 6]] cm # >>> print a2 / millimeters # [[ 10. 20. 30.] # [ 40. 50. 60.]] Addition, subtraction, multiplication, division, and powers of Quantities exhibit correct dimensional analysis and unit conversion. >>> x = 1.3 * meters >>> y = 75.2 * centimeters >>> print x + y 2.052 m >>> print x - y 0.548 m >>> print x/y 1.72872340426 >>> print x*y 0.9776 m**2 The following examples are derived from the C++ Boost.Units examples at http://www.boost.org/doc/libs/1_37_0/doc/html/boost_units/Examples.html >>> >>> l = 2.0 * meters >>> >>> print l + 2.0 * nanometers 2.000000002 m >>> print 2.0 * nanometers + l 2000000002.0 nm >>> >>> print l 2.0 m >>> print l+l 4.0 m >>> print l-l 0.0 m >>> print l*l 4.0 m**2 >>> print l/l 1.0 >>> print l * meter 2.0 m**2 >>> print kilograms * (l/seconds) * (l/seconds) 4.0 kg m**2/(s**2) >>> print kilograms * (l/seconds)**2 4.0 kg m**2/(s**2) >>> print l ** 3 8.0 m**3 >>> print l ** (3.0/2.0) 2.82842712475 m**1.5 >>> print l ** 0.5 1.41421356237 m**0.5 >>> print l ** (2.0/3.0) 1.58740105197 m**0.666667 >>> # complex example >>> l = (3.0 + 4.0j) * meters >>> print l (3+4j) m >>> print l+l (6+8j) m >>> print l-l 0j m >>> print l*l (-7+24j) m**2 >>> # Numerical error yields tiny imaginary component of l/l on linux CentOS5 >>> err = abs(l/l - 1) >>> assert err < 1e-8 >>> print l * meter (3+4j) m**2 >>> print kilograms * (l/seconds) * (l/seconds) (-7+24j) kg m**2/(s**2) >>> print kilograms * (l/seconds)**2 (-7+24j) kg m**2/(s**2) >>> print l ** 3 (-117+44j) m**3 >>> print l ** (3.0/2.0) (2+11j) m**1.5 >>> print l ** 0.5 (2+1j) m**0.5 >>> print l ** (2.0/3.0) (2.38285471252+1.69466313833j) m**0.666667 >>> # kitchen sink example ... s1 = 2.0 >>> x1 = 2 >>> x2 = 4.0/3.0 >>> u1 = kilogram * meter / second**2 >>> u2 = u1 * meter >>> q1 = 1.0*u1 >>> q2 = 2.0*u2 >>> print s1 2.0 >>> print x1 2 >>> print x2 1.33333333333 >>> print u1 kilogram*meter/(second**2) >>> print u2 kilogram*meter**2/(second**2) >>> print q1 1.0 kg m/(s**2) >>> print q2 2.0 kg m**2/(s**2) >>> print u1*s1 2.0 kg m/(s**2) >>> print s1*u1 2.0 kg m/(s**2) >>> print u1/s1 0.5 kg m/(s**2) >>> print s1/u1 2.0 s**2/(kg m) >>> print u1*u1 kilogram**2*meter**2/(second**4) >>> print u1/u1 dimensionless >>> print u1*u2 kilogram**2*meter**3/(second**4) >>> print u1/u2 /meter >>> print u1**x1 kilogram**2*meter**2/(second**4) >>> print u1**(1.0/x1) kilogram**0.5*meter**0.5/second >>> print u1**x2 kilogram**1.33333*meter**1.33333/(second**2.66667) >>> print u1**(1.0/x2) kilogram**0.75*meter**0.75/(second**1.5) >>> l1 = 1.0*meters >>> l2 = 2.0*meters >>> print l1 == l2 False >>> print l1 != l2 True >>> print l1 <= l2 True >>> print l1 < l2 True >>> print l1 >= l2 False >>> print l1 > l2 False >>> >>> def work(f, dx): ... return f * dx ... >>> F = 1.0 * kilogram * meter / second**2 >>> dx = 1.0 * meter >>> E = work(F, dx) >>> >>> print "F = ", F F = 1.0 kg m/(s**2) >>> print "dx = ", dx dx = 1.0 m >>> >>> def idealGasLaw(P, V, T): ... R = MOLAR_GAS_CONSTANT_R ... print "P * V = ", P * V ... print "R * T = ", R * T ... return (P * V / (R * T)).in_units_of(mole) ... >>> T = (273.0 + 37.0) * kelvin >>> P = 1.01325e5 * pascals >>> r = 0.5e-6 * meters >>> V = 4.0/3.0 * 3.14159 * r**3 >>> n = idealGasLaw(P, V, T) P * V = 5.3053601125e-14 m**3 Pa R * T = 2577.48646608 J/mol >>> R = MOLAR_GAS_CONSTANT_R >>> >>> print "r = ", r r = 5e-07 m >>> print "P = ", P P = 101325.0 Pa >>> print "V = ", V V = 5.23598333333e-19 m**3 >>> print "T = ", T T = 310.0 K >>> print "n = ", n n = 2.05834644811e-17 mol >>> print "R = ", R R = 8.31447247122 J/(K mol) >>> print "E = ", E E = 1.0 kg m**2/(s**2) >>> print "is_quantity(V) = ", is_quantity(V) is_quantity(V) = True >>> print (1.0*radians) / degrees 57.2957795131 >>> print (1.0*radians).in_units_of(degrees) 57.2957795131 deg >>> print (1.0*angstroms).in_units_of(nanometers) 0.1 nm >>> >>> print (90*degrees)/radians 1.57079632679 >>> print sin(90*degrees) 1.0 >>> x = 90 * degrees >>> x += 0.3 * radians >>> print x 107.188733854 deg >>> print 1 * nanometers > 1 * angstroms True >>> print 1 * nanometers > 1 * degrees Traceback (most recent call last): ... TypeError: Unit "degree" is not compatible with Unit "nanometer". >>> >>> x = 1.5 * nanometers >>> print x / meters 1.5e-09 >>> x = 1.5 * angstroms >>> print x / meters 1.5e-10 >>> print x / nanometers 0.15 Examples >>> print is_quantity(meters) False >>> print is_quantity(2.3*meters) True >>> print is_quantity(2.3) False Examples >>> x = 100.0 * millimeter >>> print x.value_in_unit_system(si_unit_system) 0.1 >>> print x.value_in_unit_system(cgs_unit_system) 10.0 >>> print x.value_in_unit_system(md_unit_system) 100000000.0 >>> >>> y = 20 * millimeters / millisecond**2 >>> print y.value_in_unit_system(si_unit_system) 20000.0 >>> print y.value_in_unit_system(cgs_unit_system) 2000000.0 >>> print y.value_in_unit_system(md_unit_system) 2e-11 >>> eps = Quantity(1.0, md_kilocalorie/mole) >>> epsQ = eps.value_in_unit_system(md_unit_system) >>> print epsQ 4.184 Dimensionless quantities return their unmodified values. >>> Quantity(5, dimensionless).value_in_unit_system(md_unit_system) 5 Examples >>> x = 2.3*meters >>> print x.value_in_unit(centimeters) 230.0 Examples >>> print bool(2.3*meters) True >>> print bool(0*meters) False Examples >>> print -(2.3*meters) -2.3 m >>> print -(-2.3*meters) 2.3 m Examples >>> print +(2.3*meters) 2.3 m Examples >>> print abs(-2.3*meters) 2.3 m >>> (9.0*meter*meter).sqrt() Quantity(value=3.0, unit=meter) >>> (9.0*meter).sqrt() Traceback (most recent call last): ... ArithmeticError: Exponents in Unit.sqrt() must be even. >>> (9.0*meter*meter*meter).sqrt() Traceback (most recent call last): ... ArithmeticError: Exponents in Unit.sqrt() must be even. >>> (9.0*meter*meter/second/second).sqrt() Quantity(value=3.0, unit=meter/second) Mixture of BaseUnits and ScaledUnits should cause no trouble: >>> sqrt(1.0 * kilogram * joule) Quantity(value=1.0, unit=kilogram*meter/second) >>> sqrt(1.0 * kilogram * calorie) Quantity(value=2.0454828280872954, unit=kilogram*meter/second) Examples >>> print (2.3*meters)**2 5.29 m**2 Examples >>> x = 4.2 * centimeters >>> print 8.4 / x 2.0 /cm Examples >>> x = 4.3 * meters >>> print x/centimeters 430.0 >>> print x/seconds 4.3 m/s >>> x = [1,2,3]*centimeter >>> x/millimeter [10.0, 20.0, 30.0] Examples >>> x = 1.2*meters >>> print 5*x 6.0 m Examples >>> x = 1.2*meters >>> y = 72*centimeters >>> print x*y 0.864 m**2 >>> x = [1,2,3]*centimeter >>> x Quantity(value=[1, 2, 3], unit=centimeter) >>> x * meter Quantity(value=[100.0, 200.0, 300.0], unit=centimeter**2) >>> u = nanometer**2/angstrom**2 >>> print u nanometer**2/(angstrom**2) >>> q = Quantity(2.0, u) >>> q Quantity(value=2.0, unit=nanometer**2/(angstrom**2)) >>> "%.1f" % q.reduce_unit() '200.0' Examples >>> 1.2*meters < 72*centimeters False >>> meter != None True >>> meter == None False Examples >>> print 1.2 * meters - 72 * centimeters 0.48 m Examples >>> print 1.2 * meters + 72 * centimeters 1.92 m Examples >>> print repr(1.2*meter) Quantity(value=1.2, unit=meter) Examples >>> print 5.0 * nanometers 5.0 nm Examples >>> Quantity(5.0, meters) Quantity(value=5.0, unit=meter) >>> Quantity([1*angstrom,2*nanometer,3*angstrom]) Quantity(value=[1, 20.0, 3], unit=angstrom) >>> Quantity((1,2,3)) Quantity(value=(1, 2, 3), unit=dimensionless) >>> Quantity([1*angstrom,2*nanometer,3*angstrom]) Quantity(value=[1, 20.0, 3], unit=angstrom) >>> Quantity([1*angstrom,2*nanometer,3*second]) Traceback (most recent call last): ... TypeError: Unit "second" is not compatible with Unit "angstrom". >>> Quantity(5) Quantity(value=5, unit=dimensionless) Passing a unit to the constructor yields a Quantity with an empty list value. >>> Quantity(angstrom) Quantity(value=[], unit=angstrom) >>> Quantity(5*angstrom) Quantity(value=5, unit=angstrom) >>> Quantity(([1*angstrom,2*nanometer,3*angstrom], [1*angstrom,4*nanometer,3*angstrom])) Quantity(value=([1, 20.0, 3], [1, 40.0, 3]), unit=angstrom) >>> Quantity([]) Quantity(value=[], unit=dimensionless) A simple scalar Quantity can be used as the unit argument. >>> Quantity(value=5.0, unit=100.0*meters) Quantity(value=500.0, unit=meter) Examples >>> x = 2.3*meters >>> y = x.in_units_of(centimeters) >>> print y 230.0 cm >>> x = 2.3*meters >>> print x.in_units_of(centimeters) 230.0 cm >>> print x.in_units_of(seconds) Traceback (most recent call last): ... TypeError: Unit "meter" is not compatible with Unit "second". Examples >>> x = 100.0 * millimeter >>> print x 100.0 mm >>> print x.in_unit_system(si_unit_system) 0.1 m >>> print x.in_unit_system(cgs_unit_system) 10.0 cm >>> print x.in_unit_system(md_unit_system) 100000000.0 nm >>> y = 20 * millimeters / millisecond**2 >>> print y 20 mm/(ms**2) >>> print y.in_unit_system(si_unit_system) 20000.0 m/(s**2) >>> print y.in_unit_system(cgs_unit_system) 2000000.0 cm/(s**2) >>> print y.in_unit_system(md_unit_system) 2e-11 nm/(ps**2) Sometimes mixed internal units have caused trouble: >>> q = 1.0 * md_kilocalorie/mole/angstrom >>> print q.in_units_of(md_kilojoule/mole/nanometer) 41.84 kJ/(nm mol) Examples >>> class Foo: ... def bar(self): ... print "bar" ... >>> x = Foo() >>> x.bar() bar >>> y = x * nanometers >>> y.bar() bar Examples >>> print meters * centimeters centimeter*meter >>> print meters * meters meter**2 >>> print meter * meter meter**2 Examples >>> print meter / 2 0.5 m Examples >>> define_prefixed_units(kelvin_base_unit, sys.modules["__main__"]) >>> from __main__ import millikelvin >>> print 5.0 * millikelvin 5.0 mK Creating a new BaseUnit: >>> ms = milli * second_base_unit >>> ms BaseUnit(base_dim=BaseDimension("time"), name="millisecond", symbol="ms") >>> ms.conversion_factor_to(second_base_unit) 0.001 Creating a new ScaledUnit: >>> mC = milli * ScaledUnit(4.184, joule, "calorie", "cal") >>> mC ScaledUnit(factor=0.0041840000000000002, master=joule, name='millicalorie', symbol='mcal') Creating a new Unit: >>> ms = milli * second >>> ms Unit({BaseUnit(base_dim=BaseDimension("time"), name="millisecond", symbol="ms"): 1.0}) Don't try a Quantity though: >>> ms = milli * (1.0 * second) Traceback (most recent call last): ... TypeError: Unit prefix "milli" can only be applied to a Unit, BaseUnit, or ScaledUnit. Comparison of dimensionless quantities issue (fixed in svn 513) >>> x = Quantity(1.0, dimensionless) >>> y = Quantity(1.0, dimensionless) >>> assert not x is y >>> assert x == y Formatting of Quantities >>> x = 5.439999999 * picosecond >>> x Quantity(value=5.4399999990000003, unit=picosecond) >>> x.format("%.3f") '5.440 ps' # Bug report Dec 17, 2009 from John Chodera # deepcopy of Quantity containing numpy array wrongly strips units >>> try: ... import numpy ... import copy ... x = Quantity(numpy.zeros([2,3]), nanometer) ... y = copy.deepcopy(x) ... assert x[0][0] == y[0][0] ... except ImportError: ... pass # Passing a string through Quantity constructor should return a string/dimensionless >>> x = Quantity("string").value_in_unit_system(md_unit_system) >>> assert x == "string" # Trouble with complicated unit conversion factors # Jan 29 1010 email from John Chodera >>> p1 = 1.0 * atmosphere >>> p2 = (1.0 * atmosphere).in_units_of(joule/nanometer**3) >>> V = 2.4 * nanometer**3 >>> beta = 4.e-4 * mole/joule >>> x1 = beta*p1*V >>> # print x1 ... y1 = x1 * AVOGADRO_CONSTANT_NA >>> print y1 0.0585785776197 # Wrong answer is 5.85785776197e+25 >>> x2 = beta*p2*V >>> # print x2 ... y2 = x2 * AVOGADRO_CONSTANT_NA >>> print y2 0.0585785776197 >>> assert( abs(y1 - y2) < 0.01) # division of numpy arrays error # April 2010, thanks to John Chodera for reporting >>> try: ... import numpy ... x = Quantity(numpy.array([1.,2.]), nanometer) ... y = Quantity(numpy.array([3.,4.]), picosecond) ... assert str(x/y) == '[ 0.33333333 0.5 ] nm/ps' ... except ImportError: ... pass # another numpy problem from retarded implementation of == operator # Thanks to Kyle Beauchamp July 2010 >>> try: ... import numpy ... from simtk.unit.quantity import _is_string ... a = numpy.array([[1,2,3],[4,5,6]]) ... assert isinstance("", str) ... assert _is_string("") ... assert _is_string("t") ... assert _is_string("test") ... assert not _is_string(3) ... assert not _is_string(a) ... except ImportError: ... pass """ __author__ = "Christopher M. Bruns" __version__ = "0.5" # This unit code might be found in different packages... # So use local import from baseunit import BaseUnit from standard_dimensions import * from unit import is_unit, dimensionless from quantity import Quantity, is_quantity, is_dimensionless from unit_definitions import * from unit_math import * from constants import * # run module directly for testing if __name__=='__main__': # Test the examples in the docstrings import doctest, sys (failed, passed) = doctest.testmod(sys.modules[__name__]) # For use in automated testing, return number of failed tests as exit code exit(failed)