Commit 164e657b authored by Daniel Boeckenhoff's avatar Daniel Boeckenhoff
Browse files

tfields core added disjoint group and parts method for splitting and graph theory

parent 90b6d221
......@@ -743,8 +743,7 @@ class Tensors(AbstractNdarray):
with self.tmp_transform(coordSys):
# map all values to first segment
self[:, coordinate] = \
(self[:, coordinate] - offset) % (periodicity /
num_segments) + \
(self[:, coordinate] - offset) % (periodicity / num_segments) + \
offset + segment * periodicity / num_segments
def equal(self, other,
......@@ -1298,7 +1297,7 @@ class TensorFields(Tensors):
if weights is int: use field at index <weights>
else: see Tensors._weights
"""
if isinstance(weights, int) :
if isinstance(weights, int):
weights = self.fields[weights]
return super(TensorFields, self)._weights(weights, rigid=rigid)
......@@ -1680,15 +1679,60 @@ class TensorMaps(TensorFields):
masks.append(~map_delete_mask)
return masks
def parts(self, *map_descriptions):
"""
Args:
*map_descriptions (tuple): tuples of
map_pos_idx (int): reference to map position
used like: self.maps[map_pos_idx]
map_indices_list (list of list of int): each int refers
to index in a map.
"""
# raise ValueError(map_descriptions)
parts = []
for map_description in map_descriptions:
map_pos_idx, map_indices_list = map_description
for map_indices in map_indices_list:
obj = self.copy()
map_indices = set(map_indices) # for speed up
map_delete_mask = np.array(
[True if i not in map_indices else False
for i in range(len(self.maps[map_pos_idx]))])
obj.maps[map_pos_idx] = obj.maps[map_pos_idx][~map_delete_mask]
obj = obj.cleaned(duplicates=False)
parts.append(obj)
return parts
def disjoint_map(self, mp_idx):
"""
Find the disjoint sets of map = self.maps[mp_idx]
Args:
mp_idx (int): reference to map position
used like: self.maps[mp_idx]
Returns:
map description(tuple): see self.parts
Examples:
>>> import tfields
>>> a = tfields.TensorMaps([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]],
... maps=[[[0, 1, 2], [0, 2, 3]]])
>>> b = a.copy()
>>> b[:, 0] += 2
>>> m = tfields.TensorMaps.merged(a, b)
>>> mp_description = m.disjoint_map(0)
>>> parts = m.parts(mp_description)
>>> aa, ba = parts
>>> assert aa.maps[0].equal(ba.maps[0])
>>> assert aa.equal(a)
>>> assert ba.equal(b)
"""
maps_list = tfields.lib.sets.disjoint_group_indices(self.maps[mp_idx])
return (0, maps_list)
if __name__ == '__main__': # pragma: no cover
import doctest
doctest.testmod()
# doctest.run_docstring_examples(TensorFields.__getitem__, globals())
# doctest.run_docstring_examples(TensorMaps.__getitem__, globals())
# doctest.run_docstring_examples(TensorMaps.keep, globals())
# doctest.run_docstring_examples(TensorMaps.to_maps_masks, globals())
# doctest.run_docstring_examples(TensorMaps, globals())
# doctest.run_docstring_examples(TensorFields, globals())
# doctest.run_docstring_examples(AbstractNdarray.copy, globals())
# doctest.run_docstring_examples(TensorMaps.equal, globals())
......@@ -109,3 +109,5 @@ else:
from . import stats
from .stats import mode, median, mean
from . import symbolics
from . import sets
from . import util
......@@ -239,9 +239,15 @@ class Mesh3D(tfields.TensorMaps):
raise ValueError("Face dimension should be 3")
return obj
@classmethod
def plane(cls, *base_vectors, **kwargs):
"""
Alternative constructor for creating a plane from
Args:
*base_vectors: see grid constructors in core. One base_vector has to
be one-dimensional
**kwargs: forwarded to __new__
"""
vertices = tfields.Tensors.grid(*base_vectors)
base_vectors = tfields.grid.ensure_complex(*base_vectors)
......@@ -274,6 +280,9 @@ class Mesh3D(tfields.TensorMaps):
@classmethod
def grid(cls, *base_vectors, **kwargs):
"""
Construct 'cuboid' along base_vectors
"""
if not len(base_vectors) == 3:
raise AttributeError("3 base_vectors vectors required")
......@@ -349,106 +358,6 @@ class Mesh3D(tfields.TensorMaps):
assign_multiple=assign_multiple)
return masks
def cutScalars(self, expression, coords=None,
replaceValue=np.nan, scalarIndex=None, inplace=False):
"""
Set a threshold to the scalars.
Args:
expression (sympy cut expression or list of those):
threshold(sympy cut expression): cut scalars globaly
threshold(list of sympy cut expressions): set on threshold for every scalar array
Examples:
>>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [0,1,0], [0,0,1]],
... faces=[[0,1,2], [0,1,3]],
... faceScalars=[[1, 1], [2, 2]])
Cuting all scalars at once
>>> from sympy.abc import s
>>> m.cutScalars(s <= 1., replaceValue=0.).faceScalars
array([[ 0., 0.],
[ 2., 2.]])
Cutting scalars different:
>>> m.cutScalars([s <= 1, s >= 2], replaceValue=0.).faceScalars
array([[ 0., 1.],
[ 2., 0.]])
Cuttin one special scalar Array only
>>> m.cutScalars(s <= 1, replaceValue=0., scalarIndex=1).faceScalars
array([[ 1., 0.],
[ 2., 2.]])
Using a list of cut expressions to cut every scalar index different
"""
if inplace:
inst = self
else:
inst = self.copy()
if isinstance(expression, list):
if scalarIndex is not None:
raise ValueError("scalarIndex must be None, "
"if expression is list of expressions")
if not len(expression) == inst.getScalarDepth():
raise ValueError("lenght of expression must meet scalar depth")
for si, ce in enumerate(expression):
inst.cutScalars(ce, coords=coords,
replaceValue=replaceValue,
scalarIndex=si, inplace=True)
else:
if coords is None:
freeSymbols = expression.free_symbols
if len(freeSymbols) > 1:
raise ValueError('coords must be given if multiple variables are given')
elif len(freeSymbols) == 0:
raise NotImplementedError("Expressiongs like {expression} "
"are not understood for coords".format(**locals()))
coords = list(freeSymbols) * inst.getScalarDepth()
scalarArrays = inst.getScalars()
if scalarIndex is not None:
scalarArrays = scalarArrays[:, scalarIndex:scalarIndex + 1]
maskBelow = tfields.evalf(scalarArrays,
expression=expression,
coords=[coords[scalarIndex]])
scalarArrays[maskBelow] = replaceValue
inst.faceScalars[:, scalarIndex:scalarIndex + 1] = scalarArrays
else:
maskBelow = tfields.evalf(scalarArrays,
expression=expression,
coords=coords)
scalarArrays[maskBelow] = replaceValue
inst.faceScalars = scalarArrays
if not inplace:
return inst
def getFaceMask(self, mask):
"""
Examples:
>>> m = tfields.Mesh3D([[1,2,3], [3,3,3], [0,0,0], [5,6,7]],
... [[0, 1, 2], [1, 2, 3]],
... faceScalars=[[1,2,3,4,5], [6,7,8,9,0]])
>>> from sympy.abc import x,y,z
>>> vertexMask = m.evalf(z < 6)
>>> faceMask = m.getFaceMask(vertexMask)
>>> faceMask
array([ True, False], dtype=bool)
Returns:
mask of faces with all vertices in mask
"""
faceDeleteMask = np.full((self.faces.shape[0]), False, dtype=bool)
indices = np.array(range(len(self)))
deleteIndices = set(indices[~mask]) # set speeds up everything
for i, face in enumerate(self.faces):
for index in face:
if index in deleteIndices:
faceDeleteMask[i] = True
break
return ~faceDeleteMask
def removeFaces(self, faceDeleteMask):
"""
Remove faces where faceDeleteMask is True
......@@ -1097,7 +1006,7 @@ class Mesh3D(tfields.TensorMaps):
norm_vectors given.
Examples
>>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [-1,0,0], [0,1,0], [0,0,1]],
... [[0, 1, 3], [1, 3, 4], [1, 3, 2]]);
... maps=[[[0, 1, 3], [1, 3, 4], [1, 3, 2]]]);
>>> newNorms = m.triangles.norms() * -1
>>> m.align_norms(newNorms)
>>> m.faces
......
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