Commit 2b275024 authored by dboe's avatar dboe
Browse files

flake 8 correct

parent beaf8a52
"""
Description of project with title, state and further constants
"""
import os
__all__ = [
"__version__",
# "__title__",
"__summary__",
"__keywords__",
"__uri__",
"__author__",
"__email__",
"__license__",
"__copyright__",
"__python_requires__",
"__dependencies__",
"__classifiers__",
]
__version__ = '0.2.1'
# __title__ = os.path.basename(os.path.abspath('.')) # problematic
__summary__ = "numpy + sympy implementation of tensor fields with attached coordinate systems"
__keywords__ = "tensors coordinate system trafo sympy numpy"
__uri__ = 'https://gitlab.mpcdf.mpg.de/dboe/tfields'
__author__ = "Daniel Boeckenhoff"
__email__ = "daniel.boeckenhoff@ipp.mpg.de"
__license__ = "Apache Software License"
__copyright__ = "2018 %s" % __author__
__python_requires__ = '>=2.7'
__dependencies__ = [
'pathlib2;python_version<"3.0"',
'pathlib;python_version>="3.0"',
'rna',
'sortedcontainers'
]
__classifiers__ = [
# find the full list of possible classifiers at https://pypi.org/classifiers/
'Development Status :: 3 - Alpha',
'License :: OSI Approved :: {0}'.format(__license__),
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
]
......@@ -7,7 +7,7 @@ Mail: daniel.boeckenhoff@ipp.mpg.de
part of tfields library
Tools for sympy coordinate transformation
"""
from .bases import *
from . import manifold_3
from .manifold_3 import CARTESIAN, CYLINDER, SPHERICAL
from .manifold_3 import cartesian, cylinder, spherical
from .bases import * # NOQA
from . import manifold_3 # NOQA
from .manifold_3 import CARTESIAN, CYLINDER, SPHERICAL # NOQA
from .manifold_3 import cartesian, cylinder, spherical # NOQA
......@@ -22,8 +22,8 @@ def get_coord_system(base):
Return:
sympy.diffgeom.get_coord_system
"""
if (isinstance(base, string_types)
or (isinstance(base, np.ndarray) and base.dtype.kind in {'U', 'S'})):
if isinstance(base, string_types) or (isinstance(base, np.ndarray)
and base.dtype.kind in {'U', 'S'}):
base = getattr(tfields.bases, str(base))
if not isinstance(base, sympy.diffgeom.CoordSystem):
bse_tpe = type(base)
......@@ -105,7 +105,7 @@ def transform(array, base_old, base_new):
... [0, 0, 1]])
>>> cyl = tfields.bases.transform(cart, 'cartesian', 'cylinder')
>>> cyl
Transform cylinder to spherical. No connection is defined so routing via
cartesian
>>> import numpy as np
......
......@@ -105,14 +105,15 @@ cartesian.connect_to(spherical,
(sympy.sign(y) * sympy.acos(x / sympy.sqrt(x**2 + y**2)), True)),
sympy.Piecewise(
(0., sympy.Eq(x**2 + y**2 + z**2, 0)),
(sympy.atan2(z, sympy.sqrt(x**2 + y**2)), True))],
(sympy.atan2(z, sympy.sqrt(x**2 + y**2)), True)),
# sympy.Piecewise(
# (0., (sympy.Eq(x, 0) & sympy.Eq(y, 0))),
# (sympy.atan(y / x), True)),
# sympy.Piecewise(
# (0., sympy.Eq(x**2 + y**2 + z**2, 0)),
# # (0., (sympy.Eq(x, 0) & sympy.Eq(y, 0) & sympy.Eq(z, 0))),
# (sympy.acos(z / sympy.sqrt(x**2 + y**2 + z**2)), True))],
# (sympy.acos(z / sympy.sqrt(x**2 + y**2 + z**2)), True))
],
inverse=False,
fill_in_gaps=False)
......
......@@ -256,7 +256,9 @@ class Node(object):
largest = len(self.remaining_cuts[key])
largest_key = key
median = sorted(self.remaining_cuts[largest_key])[int(0.5 * (len(self.remaining_cuts[largest_key]) - 1))]
median = sorted(
self.remaining_cuts[largest_key]
)[int(0.5 * (len(self.remaining_cuts[largest_key]) - 1))]
# pop median cut from remaining cuts
self.remaining_cuts[largest_key] = [
x for x in self.remaining_cuts[largest_key] if x != median
......
......@@ -73,7 +73,7 @@ class AbstractObject(object):
# get the save method
try:
save_method = getattr(self, "_save_{extension}".format(**locals()))
except:
except AttributeError:
raise NotImplementedError(
"Can not find save method for extension: "
"{extension}.".format(**locals())
......@@ -104,7 +104,7 @@ class AbstractObject(object):
try:
load_method = getattr(cls, "_load_{e}".format(e=extension))
except:
except AttributeError:
raise NotImplementedError(
"Can not find load method for extension: "
"{extension}.".format(**locals())
......@@ -409,7 +409,8 @@ class AbstractNdarray(np.ndarray, AbstractObject):
def __reduce__(self):
"""
important for pickling (see `here <https://stackoverflow.com/questions/26598109/preserve-custom-attributes-when-pickling-subclass-of-numpy-array>`_)
important for pickling (see `here <https://stackoverflow.com/questions/\
26598109/preserve-custom-attributes-when-pickling-subclass-of-numpy-array>`_)
Examples:
>>> from tempfile import NamedTemporaryFile
......@@ -418,12 +419,12 @@ class AbstractNdarray(np.ndarray, AbstractObject):
Build a dummy scalar field
>>> from tfields import Tensors, TensorFields
>>> scalars = Tensors([0, 1, 2])
>>> vectors = Tensors([[0, 0, 0], [0, 0, 1], [0, -1, 0]])
>>> scalar_field = TensorFields(vectors,
... scalars,
... coord_sys='cylinder')
>>> scalars = tfields.Tensors([0, 1, 2])
>>> vectors = tfields.Tensors([[0, 0, 0], [0, 0, 1], [0, -1, 0]])
>>> scalar_field = tfields.TensorFields(
... vectors,
... scalars,
... coord_sys='cylinder')
Save it and restore it
......@@ -463,12 +464,12 @@ class AbstractNdarray(np.ndarray, AbstractObject):
# set the __slot__ attributes
valid_slot_attrs = list(self._iter_slots())
added_slot_attrs = ['name'] # attributes that have been added later
# have not been pickled with the full
# information and thus need to be
# excluded from the __setstate__
# need to be in the same order as they
# have been added to __slots__
"""
attributes that have been added later have not been pickled with the
full information and thus need to be excluded from the __setstate__
need to be in the same order as they have been added to __slots__
"""
added_slot_attrs = ['name']
n_np = 5 # number of numpy array states
n_old = len(valid_slot_attrs) - len(state[n_np:])
if n_old > 0:
......@@ -677,7 +678,7 @@ class Tensors(AbstractNdarray):
""" demand iterable structure """
try:
len(tensors)
except TypeError as err:
except TypeError:
raise TypeError(
"Iterable structure necessary."
" Got {tensors}".format(**locals())
......@@ -1253,9 +1254,12 @@ class Tensors(AbstractNdarray):
if rtol is None and atol is None:
equal_method = np.equal
else:
equal_method = lambda a, b: np.isclose(a, b, rtol=rtol, atol=atol)
equal_method = lambda a, b: np.isclose(a, b, rtol=rtol, atol=atol) # NOQA
# inspired by https://stackoverflow.com/questions/19228295/find-ordered-vector-in-numpy-array
"""
inspired by https://stackoverflow.com/questions/19228295/\
find-ordered-vector-in-numpy-array
"""
if self.rank == 0:
indices = np.where(equal_method((x - y), 0))[0]
elif self.rank == 1:
......@@ -1289,7 +1293,6 @@ class Tensors(AbstractNdarray):
Examples:
>>> import tfields
>>> import numpy as np
Skalars
......@@ -1352,7 +1355,7 @@ class Tensors(AbstractNdarray):
Examples:
>>> import tfields
>>> import numpy
>>> import numpy as np
>>> import sympy
>>> x, y, z = sympy.symbols('x y z')
>>> p = tfields.Tensors([[1., 2., 3.], [4., 5., 6.], [1, 2, -6],
......@@ -1673,7 +1676,6 @@ def as_tensors_list(tensors_list):
Copies input
Examples:
>>> import tfields
>>> import numpy as np
>>> scalars = tfields.Tensors([0, 1, 2])
>>> vectors = tfields.Tensors([[0, 0, 0], [0, 0, 1], [0, -1, 0]])
>>> maps = [tfields.TensorFields([[0, 1, 2], [0, 1, 2]]),
......@@ -1946,7 +1948,6 @@ class TensorFields(Tensors):
Retrive the names of the fields as a list
Examples:
>>> import numpy as np
>>> import tfields
>>> s = tfields.Tensors([1,2,3], name=1.)
>>> tf = tfields.TensorFields(s, *[s]*10)
......@@ -2188,7 +2189,6 @@ class TensorMaps(TensorFields):
Examples:
>>> import tfields
>>> import numpy as np
>>> scalars = tfields.Tensors([0, 1, 2])
>>> vectors = tfields.Tensors([[0, 0, 0], [0, 0, 1], [0, -1, 0]])
>>> maps = [tfields.TensorFields([[0, 1, 2], [0, 1, 2]], [42, 21]),
......@@ -2356,7 +2356,8 @@ class TensorMaps(TensorFields):
if return_templates:
mp, dimension_map_templates = return_value
for i in range(len(objects)):
template_maps_list[i].append((dimension, dimension_map_templates[i]))
template_maps_list[i].append((dimension,
dimension_map_templates[i]))
else:
mp = return_value
maps.append(mp)
......@@ -2364,11 +2365,11 @@ class TensorMaps(TensorFields):
inst.maps = maps
if return_templates:
for i, template_maps in enumerate(template_maps_list):
# template maps will not have dimensions according to their
# tensors which are indices
templates[i] = tfields.TensorMaps(
templates[i],
maps=Maps(template_maps)) # template maps will not have
# dimensions according to their
# tensors which are indices
maps=Maps(template_maps))
return inst, templates
else:
return inst
......@@ -2659,22 +2660,21 @@ class TensorMaps(TensorFields):
Find the minimal amount of graphs building the original graph with
maximum of two links per node i.e.
o-----o o-----o
\ / \ /
\ / \ /
o--o--o o--o 8--o
"o-----o o-----o"
" \\ / \\ /"
"" \\ / \\ /""
"o--o--o o--o 8--o"
| |
| = | + +
o o o
/ \ / \
/ \ / \
/ \\ / \\
/ \\ / \\
o o o o
where 8 is a duplicated node (one has two links and one has only one.)
Examples:
>>> import tfields
>>> import numpy as np
Ascii figure above:
>>> a = tfields.TensorMaps([[1, 0], [3, 0], [2, 2], [0, 4], [2, 4],
......
......@@ -109,10 +109,10 @@ if __name__ == '__main__':
import doctest
doctest.testmod()
else:
from . import grid
from .grid import igrid
from . import stats
from .stats import mode, median, mean
from . import symbolics
from . import sets
from . import util
from . import grid # NOQA
from .grid import igrid # NOQA
from . import stats # NOQA
from .stats import mode, median, mean # NOQA
from . import symbolics # NOQA
from . import sets # NOQA
from . import util # NOQA
......@@ -44,7 +44,7 @@ def igrid(*base_vectors, **kwargs):
iter_order (list): order in which the iteration will be done.
Frequency rises with position in list. default is [0, 1, 2]
iteration will be done like::
for v0 in base_vectors[iter_order[0]]:
for v1 in base_vectors[iter_order[1]]:
for v2 in base_vectors[iter_order[2]]:
......
"""
Input output utilities
"""
import os
import shutil
import subprocess
import contextlib
import logging
try:
from pathlib import Path as PathlibPath
PathlibPath().expanduser() # not existing in python2 version of pathlib
except (ImportError, AttributeError):
from pathlib2 import Path as PathlibPath
class Path(type(PathlibPath())):
def resolve(self):
new_path = self.expanduser()
return super(Path, new_path).resolve()
def resolve(path):
"""
Returns:
path with resolved ~, symbolic links and relative paths.
Examples:
Resolves relative paths
>>> import os
>>> from tfields.lib.in_out import resolve
>>> resolve("../tfields") == resolve(".")
True
Resolves user variables
>>> resolve("~") == os.path.expanduser("~")
True
Also resolves symlincs which i will not test.
"""
# py27 pathlib.Path has no expanduser
# return str(Path(path).expanduser().resolve())
# resolve: relative paths, symlinks and ~
return os.path.realpath(os.path.abspath(os.path.expanduser(path)))
def provide(cls, path, function, *args, **kwargs):
"""
provide the object of type tfields_clas saved unter path
and generated by function with *args and **kwargs
Args:
cls (type): type of the object returned by the function
path (str): path where to save the object returned by function
function (callable): function expected to return an object of type cls
*args: passed to function
**kwargs : passed to function
"""
path = resolve(path)
if os.path.exists(path):
return cls.load(path)
obj = function(*args, **kwargs)
if not isinstance(obj, cls):
return_type = type(obj)
raise TypeError("Return value of function is not {cls} but"
"{return_type}".format(**locals()))
obj.save(path)
return obj
def cp(source, dest, overwrite=True):
"""
copy with shutil
"""
source = resolve(source)
dest = resolve(dest)
if os.path.isfile(dest) and not overwrite:
raise ValueError("Attempting to overwrite destination path"
" {0}.".format(dest))
if os.path.isfile(source):
shutil.copy(source, dest)
elif os.path.isdir(source):
shutil.copytree(source, dest)
else:
raise TypeError("source is not file or dir")
def scp(source, dest):
"""
ssh copy
"""
# subprocess.check_call does not execute in bash, so it does not know ~
# Carefull when giving remote host : ~ replacement is not tested
subprocess.check_call(['scp', source, dest])
def mv(source, dest, overwrite=True):
"""
Move files or whole folders
"""
source = resolve(source)
dest = resolve(dest)
log = logging.getLogger()
if os.path.isfile(dest) and not overwrite:
raise ValueError("Attempting to move to already existing destination"
" path {0}.".format(dest))
log.info("Moving file or dir {0} to {1}".format(source, dest))
if os.path.isfile(source):
shutil.move(source, dest)
elif os.path.isdir(source):
shutil.move(source, dest)
# shutil.copytree(source, dest)
else:
raise TypeError("source is not file or dir")
def rm(path):
"""
Remove path or (empty) directory
"""
path = resolve(path)
if os.path.isfile(path):
os.remove(path)
elif os.path.isdir(path):
if len(ls(path)) > 0:
raise ValueError("Directory {0} is not empty".format(path))
os.rmdir(path)
else:
raise ValueError("Path {0} is not directory and not file".format(path))
def cd(directory):
"""
Change directory
"""
os.chdir(resolve(directory))
@contextlib.contextmanager
def cd_tmp(tmpPath):
"""
Temporarily change directory. change back afterwards
"""
cwd = os.getcwd()
cd(resolve(tmpPath))
try:
yield
finally:
cd(cwd)
def ls(directory, recursive=False):
"""
a bash ls imitation.
"""
if recursive:
return dir_structure(resolve(directory))
else:
return os.listdir(resolve(directory))
def mkdir(path, isDir=False):
"""
Notes:
if you want to create a dir, add '/' behind path or use isDir=True
Args:
path (str): directory or path to create.
isDir (str): tell mkdir that you are explicitly giving a directory.
"""
log = logging.getLogger()
path = resolve(path)
if isDir:
directory = path
else:
directory = os.path.dirname(path)
if not os.path.exists(directory) and not directory == '':
log.info("Create directory {0}".format(directory))
os.makedirs(directory)
else:
log.warning("Directory {0} already exists".format(directory))
def dir_structure(directory):
"""
Creates a nested dictionary that represents the folder structure of
directory
"""
directory = {}
directory = directory.rstrip(os.sep)
start = directory.rfind(os.sep) + 1
for path, dirs, files in os.walk(directory):
folders = path[start:].split(os.sep)
subdir = dict.fromkeys(files)
parent = reduce(dict.get, folders[:-1], directory)
parent[folders[-1]] = subdir
if len(directory) == 0:
return {}
return directory[directory.keys()[0]] # first entry is always directory
......@@ -85,7 +85,7 @@ class UnionFind(object):
using find.
"""
sets = {}
for i in xrange(len(self.objects_to_num)):
for i in range(len(self.objects_to_num)):
sets[i] = []
for i in self.objects_to_num:
sets[self.objects_to_num[self.find(i)]].append(i)
......@@ -101,7 +101,6 @@ class UnionFind(object):
"""
self.insert_objects(tfields.lib.util.flatten(iterator))
i = 0
n = len(iterator)
for item in iterator:
for i1, i2 in tfields.lib.util.pairwise(item):
self.union(i1, i2)
......
......@@ -9,6 +9,7 @@ part of tfields library
import numpy as np
import scipy
import scipy.stats
import logging
def mode(array, axis=0, bins='auto', range=None):
......@@ -16,7 +17,7 @@ def mode(array, axis=0, bins='auto', range=None):
generalisation of the scipy.stats.mode function for floats with binning
Examples:
Forwarding usage:
>>> import tfields
>>> import tfields # NOQA
>>> import numpy as np
>>> tfields.lib.stats.mode([[2,2,3], [4,5,3]])
array([[2, 2, 3]])
......@@ -107,8 +108,8 @@ def _contains_nan(a, nan_policy='propagate'):
# sum things that are not numbers (e.g. as in the function `mode`).
contains_nan = False
nan_policy = 'omit'
warnings.warn("The input array could not be properly checked for nan "
"values. nan values will be ignored.", RuntimeWarning)
logging.warning("The input array could not be properly checked for nan"
" values. nan values will be ignored.")
if contains_nan and nan_policy == 'raise':
raise ValueError("The input contains nan values")
......@@ -183,7 +184,7 @@ def moment(a, moment=1, axis=0, weights=None, nan_policy='propagate'):
contains_nan, nan_policy = _contains_nan(a, nan_policy)
if contains_nan and nan_policy == 'omit':
a = ma.masked_invalid(a)
a = a.masked_invalid(a)
return scipy.mstats_basic.moment(a, moment, axis)
if a.size == 0:
......
......@@ -108,7 +108,7 @@ def multi_sort(array, *others, **kwargs):
reverse = kwargs.pop('reverse', False)
if reverse:
cast_type = lambda x: list(reversed(x))
cast_type = lambda x: list(reversed(x)) # NOQA
return tuple(cast_type(x) for x in zip(*method(zip(array, *others), **kwargs)))
......
......@@ -27,27 +27,33 @@ def evalf(array, cutExpression=None, coords=None):
>>> import tfields
>>> 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]])
>>> assert np.array_equal(tfields.evalf(a, x > 0),
... np.array([ True, True, True, False, True, False]))
>>> a = np.array([[1., 2., 3.], [4., 5., 6.], [1, 2, -6],
... [-5, -5, -5], [1,0,-1], [0,1,-1]])
>>> assert np.array_equal(
... tfields.evalf(a, x > 0),
... np.array([ True, True, True, False, True, False]))
And combination
>>> assert np.array_equal(tfields.evalf(a, (x > 0) & (y < 3)),
... np.array([True, False, True, False, True, False]))
>>> assert np.array_equal(
... tfields.evalf(a, (x > 0) & (y < 3)),
... np.array([True, False, True, False, True, False]))
Or combination
>>> assert np.array_equal(tfields.evalf(a, (x > 0) | (y > 3)),
... np.array([True, True, True, False, True, False]))
>>> assert np.array_equal(
... tfields.evalf(a, (x > 0) | (y > 3)),
... 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')
>>> assert np.array_equal(tfields.evalf([[0., 1.], [-1, 3]], a1 > 2,
... coords=[a0, a1]),
... np.array([False, True], dtype=bool))
>>> assert np.array_equal(
... tfields.evalf([[0., 1.], [-1, 3]], a1 > 2, coords=[a0, a1]),
... np.array([False, True], dtype=bool))
>= is taken care of
>>> assert np.array_equal(tfields.evalf(a, x >= 0),
... np.array([ True, True, True, False, True, True]))
>>> assert np.array_equal(
... tfields.evalf(a, x >= 0),
... np.array([ True, True, True, False, True, True]))