Commit 4ae68749 authored by Jason Swails's avatar Jason Swails
Browse files

A large number of unit cleanups and fix numpy wart

The main thing that's done here is that numpy arrays can be given units via the
* operator, rather than relying on the Quantity constructor

e.g.,

>>> import numpy as np
>>> np.zeros(10) * u.angstroms
Quantity(value=array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]), unit=angstrom)

yay!
parent 71b56ad5
#!/bin/env python
"""
Module simtk.unit.basedimension
......@@ -34,6 +32,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import print_function, division
__author__ = "Christopher M. Bruns"
__version__ = "0.6"
......
......@@ -33,6 +33,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import print_function, division, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.6"
......@@ -44,6 +45,7 @@ class BaseUnit(object):
For example, meter_base_unit could be a BaseUnit for the length dimension.
The BaseUnit class is used internally in the more general Unit class.
'''
__array_priority__ = 100
def __init__(self, base_dim, name, symbol):
"""Creates a new BaseUnit.
......@@ -127,7 +129,7 @@ class BaseUnit(object):
self._conversion_factor_to_by_name[other.name] = factor
for (unit, cfac) in other._conversion_factor_to.items():
if unit is self: continue
if self._conversion_factor_to.has_key(unit): continue
if unit in self._conversion_factor_to: continue
self._conversion_factor_to[unit] = factor * cfac
unit._conversion_factor_to[self] = pow(factor * cfac, -1)
self._conversion_factor_to_by_name[unit.name] = factor * cfac
......@@ -138,7 +140,7 @@ class BaseUnit(object):
other._conversion_factor_to_by_name[self.name] = invFac
for (unit, cfac) in self._conversion_factor_to.items():
if unit is other: continue
if other._conversion_factor_to.has_key(unit): continue
if unit in other._conversion_factor_to: continue
other._conversion_factor_to[unit] = invFac * cfac
unit._conversion_factor_to[other] = pow(invFac * cfac, -1)
other._conversion_factor_to_by_name[unit.name] = invFac * cfac
......
......@@ -29,13 +29,12 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import division
from __future__ import print_function, division, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.5"
from unit_definitions import *
from .unit_definitions import *
#################
### CONSTANTS ###
......
......@@ -28,6 +28,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import print_function, division, absolute_import
import sys
......@@ -41,9 +42,9 @@ def eye(size):
[0, 0, 1]]
"""
result = []
for row in range(0, size):
for row in range(size):
r = []
for col in range(0, size):
for col in range(size):
if row == col:
r.append(1)
else:
......@@ -63,9 +64,9 @@ def zeros(m, n=None):
if n is None:
n = m
result = []
for row in range(0, m):
for row in range(m):
r = []
for col in range(0, n):
for col in range(n):
r.append(0)
result.append(r)
return MyMatrix(result)
......@@ -171,7 +172,7 @@ class MyMatrix(MyVector):
def __str__(self):
result = ""
start_char = "["
for m in range(0, self.numRows()):
for m in range(self.numRows()):
result += start_char
result += str(self[m])
if m < self.numRows() - 1:
......@@ -226,9 +227,9 @@ class MyMatrix(MyVector):
if self.numCols() != r:
raise ArithmeticError("Matrix multplication size mismatch (%d vs %d)" % (self.numCols(), r))
result = zeros(m, n)
for i in range(0, m):
for j in range(0, n):
for k in range(0, r):
for i in range(m):
for j in range(n):
for k in range(r):
result[i][j] += self[i][k]*rhs[k][j]
return result
......@@ -245,8 +246,8 @@ class MyMatrix(MyVector):
assert len(rhs) == m
assert len(rhs[0]) == n
result = zeros(m,n)
for i in range(0,m):
for j in range(0,n):
for i in range(m):
for j in range(n):
result[i][j] = self[i][j] + rhs[i][j]
return result
......@@ -263,8 +264,8 @@ class MyMatrix(MyVector):
assert len(rhs) == m
assert len(rhs[0]) == n
result = zeros(m,n)
for i in range(0,m):
for j in range(0,n):
for i in range(m):
for j in range(n):
result[i][j] = self[i][j] - rhs[i][j]
return result
......@@ -275,8 +276,8 @@ class MyMatrix(MyVector):
m = self.numRows()
n = self.numCols()
result = zeros(m, n)
for i in range(0,m):
for j in range(0,n):
for i in range(m):
for j in range(n):
result[i][j] = -self[i][j]
return result
......@@ -358,7 +359,7 @@ class MyMatrix(MyVector):
ipiv[icol] += 1
# We now have the pivot element, so we interchange rows...
if irow != icol:
for l in range(0,n):
for l in range(n):
temp = a[irow][l]
a[irow][l] = a[icol][l]
a[icol][l] = temp
......@@ -368,20 +369,20 @@ class MyMatrix(MyVector):
raise ArithmeticError("Cannot invert singular matrix")
pivinv = 1.0/a[icol][icol]
a[icol][icol] = 1.0
for l in range(0,n):
for l in range(n):
a[icol][l] *= pivinv
for ll in range(0,n): # next we reduce the rows
for ll in range(n): # next we reduce the rows
if ll == icol:
continue # except the pivot one, of course
dum = a[ll][icol]
a[ll][icol] = 0.0
for l in range(0,n):
for l in range(n):
a[ll][l] -= a[icol][l]*dum
# Unscramble the permuted columns
for l in range(n-1, -1, -1):
if indxr[l] == indxc[l]:
continue
for k in range(0,n):
for k in range(n):
temp = a[k][indxr[l]]
a[k][indxr[l]] = a[k][indxc[l]]
a[k][indxc[l]] = temp
......@@ -415,7 +416,7 @@ class MyMatrixTranspose(MyMatrix):
return MyVector(result)
def __setitem__(self, key, rhs):
for n in range(0, len(self.data)):
for n in range(len(self.data)):
self.data[n][key] = rhs[n]
def __str__(self):
......@@ -423,11 +424,11 @@ class MyMatrixTranspose(MyMatrix):
return "[[]]"
start_char = "["
result = ""
for m in range(0, len(self.data[0])):
for m in range(len(self.data[0])):
result += start_char
result += "["
sep_char = ""
for n in range(0, len(self.data)):
for n in range(len(self.data)):
result += sep_char
result += str(self.data[n][m])
sep_char = ", "
......@@ -443,11 +444,11 @@ class MyMatrixTranspose(MyMatrix):
return "MyMatrixTranspose([[]])"
start_char = "["
result = 'MyMatrixTranspose('
for m in range(0, len(self.data[0])):
for m in range(len(self.data[0])):
result += start_char
result += "["
sep_char = ""
for n in range(0, len(self.data)):
for n in range(len(self.data)):
result += sep_char
result += repr(self.data[n][m])
sep_char = ", "
......
......@@ -29,12 +29,13 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import print_function, division, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.6"
from baseunit import BaseUnit
from unit import Unit, ScaledUnit
from .baseunit import BaseUnit
from .unit import Unit, ScaledUnit
import sys
###################
......
......@@ -67,8 +67,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import division
from __future__ import division, print_function, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.5"
......@@ -76,8 +75,8 @@ __version__ = "0.5"
import math
import copy
from standard_dimensions import *
from unit import Unit, is_unit, dimensionless
from .standard_dimensions import *
from .unit import Unit, is_unit, dimensionless
class Quantity(object):
"""Physical quantity, such as 1.3 meters per second.
......@@ -92,17 +91,6 @@ class Quantity(object):
Note - unit conversions will cause tuples to be converted to lists
4 - lists of tuples of numbers, lists of lists of ... etc. of numbers
5 - numpy.arrays
Create numpy.arrays with units using the Quantity constructor, not the
multiply operator. e.g.
Quantity(numpy.array([1,2,3]), centimeters) # correct
*NOT*
numpy.array([1,2,3]) * centimeters # won't work
because numpy.arrays already overload the multiply operator for EVERYTHING.
"""
def __init__(self, value=None, unit=None):
......@@ -136,7 +124,7 @@ class Quantity(object):
if len(value) < 1:
unit = dimensionless
else:
first_item = iter(value).next()
first_item = next(iter(value))
# Avoid infinite recursion for string, because a one-character
# string is its own first element
try:
......@@ -613,6 +601,9 @@ class Quantity(object):
"""
return bool(self._value)
def __bool__(self):
return self.__nonzero__()
def __complex__(self):
return Quantity(complex(self._value), self.unit)
def __float__(self):
......@@ -713,7 +704,7 @@ class Quantity(object):
else:
for i in range(len(value)):
value[i] = factor*value[i]
except TypeError as ex:
except TypeError:
if isinstance(value, tuple):
value = tuple([self._scale_sequence(x, factor, post_multiply) for x in value])
else:
......
......@@ -31,11 +31,12 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import division, print_function, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.6"
from basedimension import BaseDimension
from .basedimension import BaseDimension
##################
### DIMENSIONS ###
......
......@@ -31,8 +31,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import division
from __future__ import division, print_function, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.5"
......@@ -40,15 +39,18 @@ __version__ = "0.5"
import math
import sys
from mymatrix import MyMatrix, zeros
from basedimension import BaseDimension
from baseunit import BaseUnit
from standard_dimensions import *
from .mymatrix import MyMatrix, zeros
from .basedimension import BaseDimension
from .baseunit import BaseUnit
from .standard_dimensions import *
class Unit(object):
"""
Physical unit such as meter or ampere.
"""
__array_priority__ = 100
def __init__(self, base_or_scaled_units):
"""Create a new Unit.
......@@ -495,6 +497,8 @@ class ScaledUnit(object):
ScaledUnit and BaseUnit are both used in the internals of Unit. They
should only be used during the construction of Units.
"""
__array_priority__ = 100
def __init__(self, factor, master, name, symbol):
self.factor = factor
# Convert to one base_unit per dimension
......@@ -576,6 +580,14 @@ class ScaledUnit(object):
+ ", symbol=" + repr(self.symbol) + ")"
class UnitSystem(object):
"""
A complete system of units defining the *base* unit in each dimension
Parameters
----------
units: ``list``
List of base units from which to construct the unit system
"""
def __init__(self, units):
self.units = units
self._unit_conversion_cache = {}
......
......@@ -30,16 +30,16 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import division
from __future__ import division, print_function, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.6"
from baseunit import BaseUnit
from standard_dimensions import *
from unit import Unit, ScaledUnit, UnitSystem, dimensionless
from unit_operators import * ; # needed for manipulation of units
from prefix import *
from .baseunit import BaseUnit
from .standard_dimensions import *
from .unit import Unit, ScaledUnit, UnitSystem, dimensionless
from .unit_operators import * ; # needed for manipulation of units
from .prefix import *
import math
import sys
......@@ -303,20 +303,20 @@ mmHg = Unit({mmHg_base_unit: 1.0})
ampere_base_unit = ScaledUnit(1.0, coulomb/second, "ampere", "A")
si_unit_system = UnitSystem([\
meter_base_unit,\
kilogram_base_unit,\
second_base_unit,\
si_unit_system = UnitSystem([
meter_base_unit,
kilogram_base_unit,
second_base_unit,
ampere_base_unit,
kelvin_base_unit,
mole_base_unit,
candela_base_unit,
radian_base_unit])
cgs_unit_system = UnitSystem([\
centimeter_base_unit,\
gram_base_unit,\
second_base_unit,\
cgs_unit_system = UnitSystem([
centimeter_base_unit,
gram_base_unit,
second_base_unit,
ampere_base_unit,
kelvin_base_unit,
mole_base_unit,
......@@ -324,10 +324,10 @@ cgs_unit_system = UnitSystem([\
dalton_base_unit = ScaledUnit(1.0, gram/mole, "dalton", "Da")
md_unit_system = UnitSystem([\
nanometer_base_unit,\
md_unit_system = UnitSystem([
nanometer_base_unit,
dalton_base_unit,
picosecond_base_unit,\
picosecond_base_unit,
elementary_charge_base_unit,
kelvin_base_unit,
mole_base_unit,
......
......@@ -31,16 +31,15 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import division
from __future__ import division, print_function, absolute_import
__author__ = "Christopher M. Bruns"
__version__ = "0.5"
import math
from quantity import is_quantity
from unit_definitions import *
from .quantity import is_quantity
from .unit_definitions import *
####################
### TRIGONOMETRY ###
......
......@@ -46,12 +46,13 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import print_function, absolute_import, division
__author__ = "Christopher M. Bruns"
__version__ = "0.5"
from unit import Unit, is_unit
from quantity import Quantity, is_quantity
from .unit import Unit, is_unit
from .quantity import Quantity, is_quantity
# Attach methods of Unit class that return a Quantity to Unit class.
# I put them here to avoid circular dependence in imports.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment