Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Daniel Boeckenhoff
tfields
Commits
64f4270c
Commit
64f4270c
authored
Jun 13, 2018
by
Daniel Böckenhoff (Laptop)
Browse files
mesh3D runs; triangles mostly
parent
f32720cb
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
tfields/__init__.py
View file @
64f4270c
...
...
@@ -6,10 +6,10 @@ from .lib import *
# __all__ = ['core', 'points3D']
from
.core
import
Tensors
,
TensorFields
,
TensorMaps
from
.points3D
import
Points3D
from
.mask
import
getMask
from
.mask
import
evalf
# methods:
from
.mask
import
getMask
# NOQA
from
.mask
import
evalf
# NOQA
from
.lib
import
*
# NOQA
# classes:
...
...
tfields/core.py
View file @
64f4270c
...
...
@@ -692,7 +692,7 @@ class Tensors(AbstractNdarray):
if
condition
is
None
:
condition
=
np
.
array
([
True
for
i
in
range
(
len
(
self
))])
elif
isinstance
(
condition
,
sympy
.
Basic
):
condition
=
self
.
getMask
(
condition
)
condition
=
self
.
evalf
(
condition
)
if
isinstance
(
coordinate
,
list
)
or
isinstance
(
coordinate
,
tuple
):
for
c
in
coordinate
:
self
.
mirror
(
c
,
condition
)
...
...
@@ -803,7 +803,7 @@ class Tensors(AbstractNdarray):
raise
ValueError
(
"Multiple occurences of value {}"
.
format
(
tensor
))
def
getM
oment
(
self
,
moment
):
def
m
oment
s
(
self
,
moment
):
"""
Returns:
Moments of the distribution.
...
...
@@ -813,9 +813,9 @@ class Tensors(AbstractNdarray):
Args:
moment (int): n-th moment
"""
return
tfields
.
lib
.
stats
.
getM
oment
(
self
,
moment
)
return
tfields
.
lib
.
stats
.
m
oment
s
(
self
,
moment
)
def
closest
Points
(
self
,
other
,
**
kwargs
):
def
closest
(
self
,
other
,
**
kwargs
):
"""
Args:
other (Tensors): closest points to what? -> other
...
...
@@ -827,26 +827,27 @@ class Tensors(AbstractNdarray):
>>> m = tfields.Tensors([[1,0,0], [0,1,0], [1,1,0], [0,0,1],
... [1,0,1]])
>>> p = tfields.Tensors([[1.1,1,0], [0,0.1,1], [1,0,1.1]])
>>> p.closest
Points
(m)
>>> p.closest(m)
array([2, 3, 4])
"""
with
other
.
tmp_transform
(
self
.
coordSys
):
# balanced_tree option gives huge speedup!
kd
T
ree
=
sp
.
spatial
.
cKDTree
(
other
,
1000
,
balanced_tree
=
False
)
res
=
kd
T
ree
.
query
(
self
,
**
kwargs
)
kd
_t
ree
=
sp
.
spatial
.
cKDTree
(
other
,
1000
,
balanced_tree
=
False
)
res
=
kd
_t
ree
.
query
(
self
,
**
kwargs
)
array
=
res
[
1
]
return
array
def
getMask
(
self
,
cutE
xpression
=
None
,
coordSys
=
None
):
def
evalf
(
self
,
e
xpression
=
None
,
coordSys
=
None
):
"""
Args:
cutExpression (sympy logical expression)
coordSys (str): coordSys to evaluate the expression in.
Returns: np.array of dtype bool with lenght of number of points in self.
This array is True, where cutExpression evaluates True.
expression (sympy logical expression)
coordSys (str): coordSys to evalfuate the expression in.
Returns:
np.ndarray: mask of dtype bool with lenght of number of points in self.
This array is True, where expression evalfuates True.
Examples:
>>> import tfields
>>> import numpy
...
...
@@ -854,33 +855,33 @@ class Tensors(AbstractNdarray):
>>> x, y, z = sympy.symbols('x y z')
>>> p = tfields.Points3D([[1., 2., 3.], [4., 5., 6.], [1, 2, -6],
... [-5, -5, -5], [1,0,-1], [0,1,-1]])
>>> np.array_equal(p.
getMask
(x > 0),
>>> np.array_equal(p.
evalf
(x > 0),
... [True, True, True, False, True, False])
True
And combination
>>> np.array_equal(p.
getMask
((x > 0) & (y < 3)),
>>> np.array_equal(p.
evalf
((x > 0) & (y < 3)),
... [True, False, True, False, True, False])
True
Or combination
>>> np.array_equal(p.
getMask
((x > 0) | (y > 3)),
>>> np.array_equal(p.
evalf
((x > 0) | (y > 3)),
... [True, True, True, False, True, False])
True
"""
coords
=
sympy
.
symbols
(
'x y z'
)
with
self
.
tmp_transform
(
coordSys
or
self
.
coordSys
):
mask
=
tfields
.
getMask
(
self
,
cutE
xpression
,
coords
=
coords
)
mask
=
tfields
.
evalf
(
self
,
e
xpression
,
coords
=
coords
)
return
mask
def
cut
(
self
,
cutE
xpression
,
coordSys
=
None
):
def
cut
(
self
,
e
xpression
,
coordSys
=
None
):
"""
Default cut method for Points3D. Works on a copy.
Args:
cutE
xpression (sympy logical expression): logical expression which will be evaluated.
e
xpression (sympy logical expression): logical expression which will be eval
f
uated.
use symbols x, y and z
coordSys (str): coordSys to evaluate the expression in.
coordSys (str): coordSys to eval
f
uate the expression in.
Examples:
>>> import tfields
>>> import sympy
...
...
@@ -903,7 +904,7 @@ class Tensors(AbstractNdarray):
"""
if
len
(
self
)
==
0
:
return
self
.
copy
()
mask
=
self
.
getMask
(
cutE
xpression
,
coordSys
=
coordSys
or
self
.
coordSys
)
mask
=
self
.
evalf
(
e
xpression
,
coordSys
=
coordSys
or
self
.
coordSys
)
mask
.
astype
(
bool
)
inst
=
self
[
mask
].
copy
()
return
inst
...
...
@@ -933,15 +934,18 @@ class Tensors(AbstractNdarray):
other
.
transform
(
self
.
coordSys
)
return
sp
.
spatial
.
distance
.
cdist
(
self
,
other
,
**
kwargs
)
def
min
D
ist
ance
s
(
self
,
other
=
None
,
**
kwargs
):
def
min
_d
ists
(
self
,
other
=
None
,
**
kwargs
):
"""
Args:
other(array
or None)
other(array
| None): if None: closest distance to self
**kwargs:
memory_saving (bool): for very large array comparisons
default False
... rest is forwarded to sp.spatial.distance.cdist
Returns:
np.array: minimal distances of self to other
Examples:
>>> import tfields
...
...
@@ -950,13 +954,13 @@ class Tensors(AbstractNdarray):
... (0, 2, 3),
... (0, 0, 1))
>>> p[4,2] = 1
>>> dMin = p.min
D
ist
ance
s()
>>> dMin = p.min
_d
ists()
>>> expected = [1] * 9
>>> expected[4] = np.sqrt(2)
>>> np.array_equal(dMin, expected)
True
>>> dMin2 = p.min
D
ist
ance
s(memory_saving=True)
>>> dMin2 = p.min
_d
ists(memory_saving=True)
>>> bool((dMin2 == dMin).all())
True
...
...
@@ -1001,6 +1005,60 @@ class Tensors(AbstractNdarray):
distsInEpsilon
=
dists
<=
epsilon
return
[
indices
[
die
]
for
die
in
distsInEpsilon
]
def
_weights
(
self
,
weights
,
rigid
=
True
):
"""
transformer method for weights inputs.
Args:
weights (np.ndarray | None):
If weights is None, use np.ones
Otherwise just pass the weights.
rigid (bool): demand equal weights and tensor length
Returns:
weight array
"""
# set weights to 1.0 if weights is None
if
weights
is
None
:
weights
=
np
.
ones
(
len
(
self
))
if
rigid
:
if
not
len
(
weights
)
==
len
(
self
):
raise
ValueError
(
"Equal number of weights as tensors demanded."
)
return
weights
def
cov_eig
(
self
,
weights
=
None
):
"""
Calculate the covariance eigenvectors with lenghts of eigenvalues
Args:
weights (np.array | int | None): index to scalars to weight with
"""
# weights = self.getNormedWeightedAreas(weights=weights)
weights
=
self
.
_weights
(
weights
)
cov
=
np
.
cov
(
self
.
T
,
ddof
=
0
,
aweights
=
weights
)
# calculate eigenvalues and eigenvectors of covariance
evalfs
,
evecs
=
np
.
linalg
.
eigh
(
cov
)
idx
=
evalfs
.
argsort
()[::
-
1
]
evalfs
=
evalfs
[
idx
]
evecs
=
evecs
[:,
idx
]
e
=
np
.
concatenate
((
evecs
,
evalfs
.
reshape
(
1
,
3
)))
return
e
.
T
.
reshape
(
12
,
)
def
main_axes
(
self
,
weights
=
None
):
"""
Returns:
Main Axes eigen-vectors
"""
# weights = self.getNormedWeightedAreas(weights=weights)
weights
=
self
.
_weights
(
weights
)
mean
=
self
.
moments
(
1
)
relative_coords
=
self
-
mean
cov
=
np
.
cov
(
relative_coords
.
T
,
ddof
=
0
,
aweights
=
weights
)
# calculate eigenvalues and eigenvectors of covariance
evalfs
,
evecs
=
np
.
linalg
.
eigh
(
cov
)
return
(
evecs
*
evalfs
.
T
).
T
class
TensorFields
(
Tensors
):
"""
...
...
@@ -1068,7 +1126,7 @@ class TensorFields(Tensors):
This error can be suppressed by setting rigid=False
>>> loose = tfields.TensorFields([1, 2, 3], [3], rigid=False)
>>> assert len(loose) != 1
"""
__slots__
=
[
'coordSys'
,
'fields'
]
...
...
@@ -1192,6 +1250,18 @@ class TensorFields(Tensors):
mask
&=
field
.
equal
(
other
.
fields
[
i
],
**
kwargs
)
return
mask
def
_weights
(
self
,
weights
,
rigid
=
True
):
"""
Expansion of Tensors._weights with integer inputs
Args:
weights (np.ndarray | int | None):
if weights is int: use field at index <weights>
else: see Tensors._weights
"""
if
isinstance
(
weights
,
int
)
:
weights
=
self
.
fields
[
weights
]
return
super
(
TensorFields
,
self
).
_weights
(
weights
,
rigid
=
rigid
)
class
TensorMaps
(
TensorFields
):
"""
...
...
@@ -1431,7 +1501,7 @@ class TensorMaps(TensorFields):
>>> m = TensorMaps([[1,2,3], [3,3,3], [0,0,0], [5,6,7]],
... maps=[[[0, 1, 2], [1, 2, 3]]])
>>> from sympy.abc import x,y,z
>>> vertexMask = m.
getMask
(z < 6)
>>> vertexMask = m.
evalf
(z < 6)
>>> faceMask = m.to_maps_masks(vertexMask)
>>> assert np.array_equal(faceMask, [[True, False]])
...
...
tfields/mask.py
View file @
64f4270c
...
...
@@ -11,15 +11,16 @@ import numpy as np
import
sympy
def
getMask
(
array
,
cutExpression
=
None
,
coords
=
None
):
def
evalf
(
array
,
cutExpression
=
None
,
coords
=
None
):
"""
Linking sympy and numpy by retrieving a mask according to the cutExpression
Args:
array (numpy ndarray)
cutExpression (sympy logical expression)
coordSys (str): coordSys to evaluate the expression in.
Returns: np.array which is True, where cutExpression evaluates True.
coordSys (str): coordSys to evalfuate the expression in.
Returns:
np.array: mask which is True, where cutExpression evalfuates True.
Examples:
>>> import sympy
>>> import numpy as np
...
...
@@ -27,20 +28,20 @@ def getMask(array, cutExpression=None, coords=None):
>>> 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.
getMask
(a, x > 0),
>>> assert np.array_equal(tfields.
evalf
(a, x > 0),
... np.array([ True, True, True, False, True, False]))
And combination
>>> assert np.array_equal(tfields.
getMask
(a, (x > 0) & (y < 3)),
>>> 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.
getMask
(a, (x > 0) | (y > 3)),
>>> 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
>>> a0, a1 = sympy.symbols('a0 a1')
>>> assert np.array_equal(tfields.
getMask
([[0., 1.], [-1, 3]], a1 > 2,
>>> assert np.array_equal(tfields.
evalf
([[0., 1.], [-1, 3]], a1 > 2,
... coords=[a0, a1]),
... np.array([False, True], dtype=bool))
...
...
tfields/mesh3D.py
View file @
64f4270c
...
...
@@ -36,7 +36,7 @@ def fields_to_scalars(fields):
return
np
.
array
(
fields
)
def
faces_to_maps
(
faces
,
*
fields
):
return
[
tfields
.
TensorFields
(
faces
,
*
fields
,
dtype
=
int
)]
return
[
tfields
.
TensorFields
(
faces
,
*
fields
,
dtype
=
int
,
dim
=
3
)]
def
maps_to_faces
(
maps
):
if
len
(
maps
)
==
0
:
...
...
@@ -74,10 +74,9 @@ class Mesh3D(tfields.TensorMaps):
going from Mesh3D to Triangles3D instance is easy and will be cached.
>>> m = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0]], faces=[[0, 1, 2]]);
>>> m.triangles
Triangles3D([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 0.]])
>>> assert m.triangles.equal(tfields.Triangles3D([[ 1., 0., 0.],
... [ 0., 1., 0.],
... [ 0., 0., 0.]]))
a list of scalars is assigned to each face
>>> mScalar = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0]], faces=[[0, 1, 2]], faceScalars=[.5]);
...
...
@@ -95,9 +94,7 @@ class Mesh3D(tfields.TensorMaps):
... [ 2., 0., 0.],
... [ 0., 3., 0.]])
True
>>> msum.faces
array([[0, 1, 2],
[3, 4, 5]])
>>> assert np.array_equal(msum.faces, [[0, 1, 2], [3, 4, 5]])
Saving and reading
>>> from tempfile import NamedTemporaryFile
...
...
@@ -112,9 +109,9 @@ class Mesh3D(tfields.TensorMaps):
"""
def
__new__
(
cls
,
tensors
,
**
kwargs
):
fields
=
kwargs
.
pop
(
'fields'
,
[])
if
not
issubclass
(
type
(
tensors
),
Mesh3D
):
kwargs
[
'dim'
]
=
3
fields
=
kwargs
.
pop
(
'fields'
,
[])
faces
=
kwargs
.
pop
(
'faces'
,
None
)
faceScalars
=
kwargs
.
pop
(
'faceScalars'
,
[])
maps
=
kwargs
.
pop
(
'maps'
,
None
)
...
...
@@ -288,7 +285,10 @@ class Mesh3D(tfields.TensorMaps):
"""
if
self
.
faces
.
size
==
0
:
return
tfields
.
Triangles3D
([])
return
tfields
.
Triangles3D
(
self
[
self
.
faces
.
flatten
()],
triangleScalars
=
self
.
faceScalars
)
tris
=
tfields
.
Tensors
.
merged
(
*
[
self
[
mp
.
flatten
()]
for
mp
in
self
.
maps
])
map_fields
=
[
mp
.
fields
for
mp
in
self
.
maps
]
fields
=
[
tfields
.
Tensors
.
merged
(
*
fields
)
for
fields
in
zip
(
*
map_fields
)]
return
tfields
.
Triangles3D
(
tris
,
*
fields
)
@
decoTools
.
cached_property
()
def
planes
(
self
):
...
...
@@ -313,22 +313,22 @@ class Mesh3D(tfields.TensorMaps):
def
createFromTxtFile
(
cls
,
filePath
):
return
tfields
.
Triangles3D
.
createFromTxtFile
(
filePath
).
getMesh3D
()
def
__getattr__
(
self
,
name
):
"""
getter methods are forwarded to self.triangles
Examples:
>>> m = tfields.Mesh3D([]);
>>> m.getAreas
<bound method Triangles3D.getAreas of Triangles3D([], shape=(0, 3), dtype=float64)>
"""
if
name
.
startswith
(
'get'
):
if
not
hasattr
(
tfields
.
Triangles3D
,
name
)
or
name
==
'getMask'
:
raise
AttributeError
(
"Could not forward attribute {0}"
.
format
(
name
))
else
:
return
getattr
(
self
.
triangles
,
name
)
else
:
raise
AttributeError
(
"No attribute with name {0}"
.
format
(
name
))
#
def __getattr__(self, name):
#
"""
#
getter methods are forwarded to self.triangles
#
Examples:
#
>>> m = tfields.Mesh3D([]);
#
>>> m.getAreas
#
<bound method Triangles3D.getAreas of Triangles3D([], shape=(0, 3), dtype=float64)>
#
"""
#
if name.startswith('get'):
#
if not hasattr(tfields.Triangles3D, name) or name == 'getMask':
#
raise AttributeError("Could not forward attribute {0}".format(name))
#
else:
#
return getattr(self.triangles, name)
#
else:
#
raise AttributeError("No attribute with name {0}".format(name))
def
getNFaces
(
self
):
return
self
.
faces
.
shape
[
0
]
...
...
tfields/triangles3D.py
View file @
64f4270c
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment