Commit b9a36665 authored by Daniel Boeckenhoff's avatar Daniel Boeckenhoff
Browse files

merged with actual tensors library

parent 6d6de152
...@@ -8,7 +8,7 @@ from setuptools import setup, find_packages ...@@ -8,7 +8,7 @@ from setuptools import setup, find_packages
setup( setup(
name='tfields', name='tfields',
version='0.1.0', version='1.1.0.dev1',
description='numpy + sympy implementation of tensor fields with attached coordinate systems', description='numpy + sympy implementation of tensor fields with attached coordinate systems',
author='Daniel Boeckenhoff', author='Daniel Boeckenhoff',
author_email='dboe@ipp.mpg.de', author_email='dboe@ipp.mpg.de',
...@@ -17,9 +17,9 @@ setup( ...@@ -17,9 +17,9 @@ setup(
test_require=['doctest'], test_require=['doctest'],
url='https://gitlab.mpcdf.mpg.de/dboe/tfields', url='https://gitlab.mpcdf.mpg.de/dboe/tfields',
# install_requires=['numpy', 'scipy'], # install_requires=['numpy', 'scipy'],
entry_points={ # entry_points={
'console_scripts': ['tfields = tfields.__main__'] # 'console_scripts': ['tfields = tfields.__main__']
}, # },
classifiers=[ classifiers=[
# How mature is this project? Common values are # How mature is this project? Common values are
# 3 - Alpha # 3 - Alpha
...@@ -43,7 +43,14 @@ setup( ...@@ -43,7 +43,14 @@ setup(
'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6' 'Programming Language :: Python :: 3.6'
] ],
python_requires='>=2.7',
keywords="tensors coordinate trafo sympy numpy",
project_urls={
'Documentation': 'https://packaging.python.org/tutorials/distributing-packages/',
'Source': 'https://gitlab.mpcdf.mpg.de/dboe/tfields/',
'Tracker': 'https://github.com/pypa/sampleproject/issues',
}
) )
......
from . import bases
from . import core from . import core
from . import bases
# __all__ = ['core', 'points3D'] # __all__ = ['core', 'points3D']
from .core import Tensors, TensorFields, TensorMaps from .core import Tensors, TensorFields, TensorMaps
from .mask import getMask
# from .points3D import Points3D # from .points3D import Points3D
from .mask import getMask
if __name__ == '__main__':
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
""" """
Tools for sympy coordinate transformation Tools for sympy coordinate transformation
""" """
import tfields as tf import tfields
import numpy as np import numpy as np
import sympy import sympy
import sympy.diffgeom import sympy.diffgeom
...@@ -70,7 +70,7 @@ cartesian.connect_to(spherical, ...@@ -70,7 +70,7 @@ cartesian.connect_to(spherical,
def getCoordSystem(base): def getCoordSystem(base):
if isinstance(base, string_types): if isinstance(base, string_types):
base = getattr(tf.bases, base) base = getattr(tfields.bases, base)
if not isinstance(base, sympy.diffgeom.CoordSystem): if not isinstance(base, sympy.diffgeom.CoordSystem):
raise TypeError("Wrong type of coordSystem base.") raise TypeError("Wrong type of coordSystem base.")
return base return base
...@@ -95,18 +95,18 @@ def lambdifiedTrafo(baseOld, baseNew): ...@@ -95,18 +95,18 @@ def lambdifiedTrafo(baseOld, baseNew):
Examples: Examples:
>>> import numpy as np >>> import numpy as np
>>> import tfields as tf >>> import tfields
Transform cartestian to cylinder or spherical Transform cartestian to cylinder or spherical
>>> a = np.array([[3,4,0]]) >>> a = np.array([[3,4,0]])
>>> trafo = tf.bases.lambdifiedTrafo(tf.bases.cartesian, >>> trafo = tfields.bases.lambdifiedTrafo(tfields.bases.cartesian,
... tf.bases.cylinder) ... tfields.bases.cylinder)
>>> new = np.concatenate([trafo(*coords).T for coords in a]) >>> new = np.concatenate([trafo(*coords).T for coords in a])
>>> assert new[0, 0] == 5 >>> assert new[0, 0] == 5
>>> trafo = tf.bases.lambdifiedTrafo(tf.bases.cartesian, >>> trafo = tfields.bases.lambdifiedTrafo(tfields.bases.cartesian,
... tf.bases.spherical) ... tfields.bases.spherical)
>>> new = np.concatenate([trafo(*coords).T for coords in a]) >>> new = np.concatenate([trafo(*coords).T for coords in a])
>>> assert new[0, 0] == 5 >>> assert new[0, 0] == 5
...@@ -125,9 +125,9 @@ def transform(array, baseOld, baseNew): ...@@ -125,9 +125,9 @@ def transform(array, baseOld, baseNew):
Transform cylinder to spherical. No connection is defined so routing via Transform cylinder to spherical. No connection is defined so routing via
cartesian cartesian
>>> import numpy as np >>> import numpy as np
>>> from tfields.bases import transform >>> import tfields
>>> b = np.array([[5, np.arctan(4. / 3), 0]]) >>> b = np.array([[5, np.arctan(4. / 3), 0]])
>>> newB = transform(b, 'cylinder', 'spherical') >>> newB = tfields.bases.transform(b, 'cylinder', 'spherical')
>>> assert newB[0, 0] == 5 >>> assert newB[0, 0] == 5
>>> assert round(newB[0, 1], 10) == round(b[0, 1], 10) >>> assert round(newB[0, 1], 10) == round(b[0, 1], 10)
...@@ -142,13 +142,13 @@ def transform(array, baseOld, baseNew): ...@@ -142,13 +142,13 @@ def transform(array, baseOld, baseNew):
return transform(tmpArray, baseTmp, baseNew) return transform(tmpArray, baseTmp, baseNew)
raise ValueError("Trafo not found.") raise ValueError("Trafo not found.")
trafo = tf.bases.lambdifiedTrafo(baseOld, baseNew) trafo = tfields.bases.lambdifiedTrafo(baseOld, baseNew)
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.filterwarnings('ignore', message="invalid value encountered in double_scalars") warnings.filterwarnings('ignore', message="invalid value encountered in double_scalars")
new = np.concatenate([trafo(*coords).T for coords in array]) new = np.concatenate([trafo(*coords).T for coords in array])
return new return new
if __name__ == '__main__': if __name__ == '__main__': # pragma: no cover
import doctest import doctest
doctest.testmod() doctest.testmod()
import tfields import tfields.bases
import numpy as np import numpy as np
from contextlib import contextmanager from contextlib import contextmanager
from collections import Counter from collections import Counter
...@@ -50,7 +49,7 @@ class AbstractNdarray(np.ndarray): ...@@ -50,7 +49,7 @@ class AbstractNdarray(np.ndarray):
__slotDtypes__ = [] __slotDtypes__ = []
__slotSetters__ = [] __slotSetters__ = []
def __new__(cls, array, **kwargs): def __new__(cls, array, **kwargs): # pragma: no cover
raise NotImplementedError("{clsType} type must implement '__new__'" raise NotImplementedError("{clsType} type must implement '__new__'"
.format(clsType=type(cls))) .format(clsType=type(cls)))
...@@ -102,6 +101,7 @@ class AbstractNdarray(np.ndarray): ...@@ -102,6 +101,7 @@ class AbstractNdarray(np.ndarray):
Examples: Examples:
>>> from tempfile import NamedTemporaryFile >>> from tempfile import NamedTemporaryFile
>>> import pickle >>> import pickle
>>> import tfields
Build a dummy scalar field Build a dummy scalar field
>>> from tfields import Tensors, TensorFields >>> from tfields import Tensors, TensorFields
...@@ -204,6 +204,15 @@ class Tensors(AbstractNdarray): ...@@ -204,6 +204,15 @@ class Tensors(AbstractNdarray):
... ...
ValueError: Incorrect dimension: 3 given, 2 demanded. ValueError: Incorrect dimension: 3 given, 2 demanded.
The dimension argument (dim) becomes necessary if you want to initialize
an empty array
>>> _ = Tensors([]) # doctest: +ELLIPSIS
Traceback (most recent call last):
...
ValueError: Empty tensors need dimension parameter 'dim'.
>>> Tensors([], dim=7)
Tensors([], shape=(0, 7), dtype=float64)
""" """
__slots__ = ['coordSys'] __slots__ = ['coordSys']
__slotDefaults__ = ['cartesian'] __slotDefaults__ = ['cartesian']
...@@ -230,13 +239,7 @@ class Tensors(AbstractNdarray): ...@@ -230,13 +239,7 @@ class Tensors(AbstractNdarray):
''' process empty inputs ''' ''' process empty inputs '''
if len(tensors) == 0: if len(tensors) == 0:
if dim is not None: if dim is not None:
if issubclass(type(tensors), cls): tensors = np.empty((0, dim))
if not tensors.dim == dim:
raise ValueError("Tensor dimension and "
"requested dimension are "
"not the same.")
else:
tensors = np.empty((0, dim))
else: else:
raise ValueError("Empty tensors need dimension " raise ValueError("Empty tensors need dimension "
"parameter 'dim'.") "parameter 'dim'.")
...@@ -396,7 +399,7 @@ class Tensors(AbstractNdarray): ...@@ -396,7 +399,7 @@ class Tensors(AbstractNdarray):
self.coordSys = coordSys self.coordSys = coordSys
@contextmanager @contextmanager
def tempCoordSys(self, coordSys=None): def tempCoordSys(self, coordSys):
""" """
Temporarily change the coordSys to another coordSys and change it back at exit Temporarily change the coordSys to another coordSys and change it back at exit
This method is for cleaner code only. This method is for cleaner code only.
...@@ -404,6 +407,7 @@ class Tensors(AbstractNdarray): ...@@ -404,6 +407,7 @@ class Tensors(AbstractNdarray):
Args: Args:
see coordinateTransform see coordinateTransform
Examples: Examples:
>>> import tfields
>>> p = tfields.Tensors([[1,2,3]], coordSys=tfields.bases.SPHERICAL) >>> p = tfields.Tensors([[1,2,3]], coordSys=tfields.bases.SPHERICAL)
>>> with p.tempCoordSys(tfields.bases.CYLINDER): >>> with p.tempCoordSys(tfields.bases.CYLINDER):
... assert p.coordSys == tfields.bases.CYLINDER ... assert p.coordSys == tfields.bases.CYLINDER
...@@ -411,9 +415,7 @@ class Tensors(AbstractNdarray): ...@@ -411,9 +415,7 @@ class Tensors(AbstractNdarray):
""" """
baseBefore = self.coordSys baseBefore = self.coordSys
if coordSys is None: if baseBefore == coordSys:
yield
elif baseBefore == coordSys:
yield yield
else: else:
self.coordinateTransform(coordSys) self.coordinateTransform(coordSys)
...@@ -459,7 +461,7 @@ class TensorFields(Tensors): ...@@ -459,7 +461,7 @@ class TensorFields(Tensors):
super(TensorFields, self).coordinateTransform(coordSys) super(TensorFields, self).coordinateTransform(coordSys)
for field in self.fields: for field in self.fields:
field.coordinateTransform(coordSys) field.coordinateTransform(coordSys)
class TensorMaps(TensorFields): class TensorMaps(TensorFields):
""" """
...@@ -487,19 +489,8 @@ class TensorMaps(TensorFields): ...@@ -487,19 +489,8 @@ class TensorMaps(TensorFields):
__slots__ = ['coordSys', 'fields', 'maps'] __slots__ = ['coordSys', 'fields', 'maps']
__slotDtypes__ = [None, None, int] __slotDtypes__ = [None, None, int]
# @classmethod
# def _updateSlotKwargs(cls, kwargs, skipCache=True):
# maps = kwargs.pop('maps', None)
# # Add maps
# if maps is not None:
# maps = np.empty((0, 3), dtype=int)
# kwargs['maps'] = maps
# super(TensorMaps, cls)._updateSlotKwargs(kwargs, skipCache=skipCache)
if __name__ == '__main__': if __name__ == '__main__': # pragma: no cover
import doctest import doctest
doctest.testmod() doctest.testmod()
# doctest.run_docstring_examples(TensorMaps, globals()) # doctest.run_docstring_examples(TensorMaps, globals())
...@@ -15,6 +15,8 @@ logger = loggingTools.Logger(__name__) ...@@ -15,6 +15,8 @@ logger = loggingTools.Logger(__name__)
def getMask(array, cutExpression=None, coords=None): def getMask(array, cutExpression=None, coords=None):
""" """
Linking sympy and numpy by retrieving a mask according to the cutExpression
Args: Args:
array (numpy ndarray) array (numpy ndarray)
cutExpression (sympy logical expression) cutExpression (sympy logical expression)
...@@ -27,21 +29,22 @@ def getMask(array, cutExpression=None, coords=None): ...@@ -27,21 +29,22 @@ def getMask(array, cutExpression=None, coords=None):
>>> x, y, z = sympy.symbols('x y z') >>> x, y, z = sympy.symbols('x y z')
>>> a = np.array([[1., 2., 3.], [4., 5., 6.], [1, 2, -6], [-5, -5, -5], [1,0,-1], [0,1,-1]]) >>> a = np.array([[1., 2., 3.], [4., 5., 6.], [1, 2, -6], [-5, -5, -5], [1,0,-1], [0,1,-1]])
>>> tfields.getMask(a, x > 0) >>> assert np.array_equal(tfields.getMask(a, x > 0),
array([ True, True, True, False, True, False], dtype=bool) ... np.array([ True, True, True, False, True, False]))
And combination And combination
>>> tfields.getMask(a, (x > 0) & (y < 3)) >>> assert np.array_equal(tfields.getMask(a, (x > 0) & (y < 3)),
array([ True, False, True, False, True, False], dtype=bool) ... np.array([True, False, True, False, True, False]))
Or combination Or combination
>>> tfields.getMask(a, (x > 0) | (y > 3)) >>> assert np.array_equal(tfields.getMask(a, (x > 0) | (y > 3)),
array([ True, True, True, False, True, False], dtype=bool) ... np.array([True, True, True, False, True, False]))
If array of other shape than (?, 3) is given, the coords need to be specified If array of other shape than (?, 3) is given, the coords need to be specified
>>> a0, a1 = sympy.symbols('a0 a1') >>> a0, a1 = sympy.symbols('a0 a1')
>>> tfields.getMask([[0., 1.], [-1, 3]], a1 > 2, coords=[a0, a1]) >>> assert np.array_equal(tfields.getMask([[0., 1.], [-1, 3]], a1 > 2,
array([False, True], dtype=bool) ... coords=[a0, a1]),
... np.array([False, True], dtype=bool))
""" """
if isinstance(array, list): if isinstance(array, list):
...@@ -63,11 +66,11 @@ def getMask(array, cutExpression=None, coords=None): ...@@ -63,11 +66,11 @@ def getMask(array, cutExpression=None, coords=None):
cutExpression, cutExpression,
modules={'&': np.logical_and, '|': np.logical_or}) modules={'&': np.logical_and, '|': np.logical_or})
mask = np.array([preMask(*x) for x in array]) mask = np.array([preMask(*x) for x in array], dtype=bool)
return mask return mask
if __name__ == '__main__': if __name__ == '__main__': # pragma: no cover
import doctest import doctest
doctest.testmod() doctest.testmod()
Supports Markdown
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