Merge branch 'development' into 'polish-rotation-error-determination'
# Conflicts: # python/damask/_rotation.py
This commit is contained in:
commit
25979fcd77
|
@ -248,7 +248,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fraction : float or sequence of float
|
fraction : (sequence of) float
|
||||||
Fractional coordinate(s) to evaluate Colormap at.
|
Fractional coordinate(s) to evaluate Colormap at.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Grid:
|
||||||
Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0].
|
Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0].
|
||||||
initial_conditions : dictionary, optional
|
initial_conditions : dictionary, optional
|
||||||
Labels and values of the inital conditions at each material point.
|
Labels and values of the inital conditions at each material point.
|
||||||
comments : str or sequence of str, optional
|
comments : (sequence of) str, optional
|
||||||
Additional, human-readable information, e.g. history of operations.
|
Additional, human-readable information, e.g. history of operations.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -427,7 +427,7 @@ class Grid:
|
||||||
coordinates : str
|
coordinates : str
|
||||||
Label of the vector column containing the spatial coordinates.
|
Label of the vector column containing the spatial coordinates.
|
||||||
Need to be ordered (1./x fast, 3./z slow).
|
Need to be ordered (1./x fast, 3./z slow).
|
||||||
labels : str or sequence of str
|
labels : (sequence of) str
|
||||||
Label(s) of the columns containing the material definition.
|
Label(s) of the columns containing the material definition.
|
||||||
Each unique combination of values results in one material ID.
|
Each unique combination of values results in one material ID.
|
||||||
|
|
||||||
|
@ -972,15 +972,16 @@ class Grid:
|
||||||
# materials: 1
|
# materials: 1
|
||||||
|
|
||||||
"""
|
"""
|
||||||
options = ('nearest',False,None)
|
|
||||||
orig = tuple(map(np.linspace,self.origin + self.size/self.cells*.5,
|
orig = tuple(map(np.linspace,self.origin + self.size/self.cells*.5,
|
||||||
self.origin + self.size - self.size/self.cells*.5,self.cells))
|
self.origin + self.size - self.size/self.cells*.5,self.cells))
|
||||||
|
interpolator = partial(interpolate.RegularGridInterpolator,
|
||||||
|
points=orig,method='nearest',bounds_error=False,fill_value=None)
|
||||||
new = grid_filters.coordinates0_point(cells,self.size,self.origin)
|
new = grid_filters.coordinates0_point(cells,self.size,self.origin)
|
||||||
|
|
||||||
return Grid(material = interpolate.RegularGridInterpolator(orig,self.material,*options)(new).astype(int),
|
return Grid(material = interpolator(values=self.material)(new).astype(int),
|
||||||
size = self.size,
|
size = self.size,
|
||||||
origin = self.origin,
|
origin = self.origin,
|
||||||
initial_conditions = {k: interpolate.RegularGridInterpolator(orig,v,*options)(new)
|
initial_conditions = {k: interpolator(values=v)(new)
|
||||||
for k,v in self.initial_conditions.items()},
|
for k,v in self.initial_conditions.items()},
|
||||||
comments = self.comments+[util.execution_stamp('Grid','scale')],
|
comments = self.comments+[util.execution_stamp('Grid','scale')],
|
||||||
)
|
)
|
||||||
|
@ -1043,9 +1044,9 @@ class Grid:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
from_material : int or sequence of int
|
from_material : (sequence of) int
|
||||||
Material indices to be substituted.
|
Material indices to be substituted.
|
||||||
to_material : int or sequence of int
|
to_material : (sequence of) int
|
||||||
New material indices.
|
New material indices.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -1104,7 +1105,7 @@ class Grid:
|
||||||
distance : float, optional
|
distance : float, optional
|
||||||
Voxel distance checked for presence of other materials.
|
Voxel distance checked for presence of other materials.
|
||||||
Defaults to sqrt(3).
|
Defaults to sqrt(3).
|
||||||
selection : int or collection of int, optional
|
selection : (collection of) int, optional
|
||||||
Material IDs to consider. Defaults to all.
|
Material IDs to consider. Defaults to all.
|
||||||
invert_selection : bool, optional
|
invert_selection : bool, optional
|
||||||
Consider all material IDs except those in selection. Defaults to False.
|
Consider all material IDs except those in selection. Defaults to False.
|
||||||
|
@ -1179,7 +1180,7 @@ class Grid:
|
||||||
Center of the primitive.
|
Center of the primitive.
|
||||||
If given as integers, cell centers are addressed.
|
If given as integers, cell centers are addressed.
|
||||||
If given as floats, physical coordinates are addressed.
|
If given as floats, physical coordinates are addressed.
|
||||||
exponent : float or sequence of float, len (3)
|
exponent : (sequence of) float, len (3)
|
||||||
Exponents for the three axes.
|
Exponents for the three axes.
|
||||||
0 gives octahedron (ǀxǀ^(2^0) + ǀyǀ^(2^0) + ǀzǀ^(2^0) < 1)
|
0 gives octahedron (ǀxǀ^(2^0) + ǀyǀ^(2^0) + ǀzǀ^(2^0) < 1)
|
||||||
1 gives sphere (ǀxǀ^(2^1) + ǀyǀ^(2^1) + ǀzǀ^(2^1) < 1)
|
1 gives sphere (ǀxǀ^(2^1) + ǀyǀ^(2^1) + ǀzǀ^(2^1) < 1)
|
||||||
|
@ -1271,7 +1272,7 @@ class Grid:
|
||||||
offset : int, optional
|
offset : int, optional
|
||||||
Offset (positive or negative) to tag material IDs.
|
Offset (positive or negative) to tag material IDs.
|
||||||
Defaults to material.max()+1.
|
Defaults to material.max()+1.
|
||||||
selection : int or collection of int, optional
|
selection : (collection of) int, optional
|
||||||
Material IDs that trigger an offset.
|
Material IDs that trigger an offset.
|
||||||
Defaults to any other than own material ID.
|
Defaults to any other than own material ID.
|
||||||
invert_selection : bool, optional
|
invert_selection : bool, optional
|
||||||
|
|
|
@ -468,7 +468,7 @@ class Rotation:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
shape : int or sequence of ints
|
shape : (sequence of) int
|
||||||
New shape, number of elements needs to match the original shape.
|
New shape, number of elements needs to match the original shape.
|
||||||
If an integer is supplied, then the result will be a 1-D array of that length.
|
If an integer is supplied, then the result will be a 1-D array of that length.
|
||||||
order : {'C', 'F', 'A'}, optional
|
order : {'C', 'F', 'A'}, optional
|
||||||
|
@ -496,7 +496,7 @@ class Rotation:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
shape : int or sequence of ints
|
shape : (sequence of) int
|
||||||
Shape of broadcasted array, needs to be compatible with the original shape.
|
Shape of broadcasted array, needs to be compatible with the original shape.
|
||||||
mode : str, optional
|
mode : str, optional
|
||||||
Where to preferentially locate missing dimensions.
|
Where to preferentially locate missing dimensions.
|
||||||
|
@ -773,12 +773,12 @@ class Rotation:
|
||||||
raise ValueError('P ∉ {-1,1}')
|
raise ValueError('P ∉ {-1,1}')
|
||||||
|
|
||||||
qu[...,1:4] *= -P
|
qu[...,1:4] *= -P
|
||||||
|
|
||||||
if accept_homomorph:
|
if accept_homomorph:
|
||||||
qu[qu[...,0] < 0.0] *= -1
|
qu[qu[...,0] < 0.0] *= -1
|
||||||
else:
|
elif np.any(qu[...,0] < 0.0):
|
||||||
if np.any(qu[...,0] < 0.0):
|
raise ValueError('quaternion with negative first (real) component')
|
||||||
raise ValueError('quaternion with negative first (real) component')
|
if not np.allclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=1e-8):
|
||||||
if not np.allclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=0.0):
|
|
||||||
raise ValueError('quaternion is not of unit length')
|
raise ValueError('quaternion is not of unit length')
|
||||||
|
|
||||||
return Rotation(qu)
|
return Rotation(qu)
|
||||||
|
@ -1022,7 +1022,7 @@ class Rotation:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
shape : int or sequence of ints, optional
|
shape : (sequence of) int, optional
|
||||||
Shape of the returned array. Defaults to None, which gives a scalar.
|
Shape of the returned array. Defaults to None, which gives a scalar.
|
||||||
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
|
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
|
||||||
A seed to initialize the BitGenerator.
|
A seed to initialize the BitGenerator.
|
||||||
|
@ -1058,7 +1058,7 @@ class Rotation:
|
||||||
Texture intensity values (probability density or volume fraction) at Euler space grid points.
|
Texture intensity values (probability density or volume fraction) at Euler space grid points.
|
||||||
phi : numpy.ndarray, shape (n,3)
|
phi : numpy.ndarray, shape (n,3)
|
||||||
Grid coordinates in Euler space at which weights are defined.
|
Grid coordinates in Euler space at which weights are defined.
|
||||||
shape : int or sequence of ints, optional
|
shape : (sequence of) int, optional
|
||||||
Shape of the returned array. Defaults to None, which gives a scalar.
|
Shape of the returned array. Defaults to None, which gives a scalar.
|
||||||
degrees : bool, optional
|
degrees : bool, optional
|
||||||
Euler space grid coordinates are in degrees. Defaults to True.
|
Euler space grid coordinates are in degrees. Defaults to True.
|
||||||
|
@ -1110,7 +1110,7 @@ class Rotation:
|
||||||
Central rotation.
|
Central rotation.
|
||||||
sigma : float
|
sigma : float
|
||||||
Standard deviation of (Gaussian) misorientation distribution.
|
Standard deviation of (Gaussian) misorientation distribution.
|
||||||
shape : int or sequence of ints, optional
|
shape : (sequence of) int, optional
|
||||||
Shape of the returned array. Defaults to None, which gives a scalar.
|
Shape of the returned array. Defaults to None, which gives a scalar.
|
||||||
degrees : bool, optional
|
degrees : bool, optional
|
||||||
sigma is given in degrees. Defaults to False.
|
sigma is given in degrees. Defaults to False.
|
||||||
|
@ -1168,7 +1168,7 @@ class Rotation:
|
||||||
sigma : float, optional
|
sigma : float, optional
|
||||||
Standard deviation of (Gaussian) misorientation distribution.
|
Standard deviation of (Gaussian) misorientation distribution.
|
||||||
Defaults to 0.
|
Defaults to 0.
|
||||||
shape : int or sequence of ints, optional
|
shape : (sequence of) int, optional
|
||||||
Shape of the returned array. Defaults to None, which gives a scalar.
|
Shape of the returned array. Defaults to None, which gives a scalar.
|
||||||
degrees : bool, optional
|
degrees : bool, optional
|
||||||
sigma and polar coordinates are given in degrees. Defaults to False.
|
sigma and polar coordinates are given in degrees. Defaults to False.
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Table:
|
||||||
For instance, 'F':(3,3) for a deformation gradient, or 'r':(1,) for a scalar.
|
For instance, 'F':(3,3) for a deformation gradient, or 'r':(1,) for a scalar.
|
||||||
data : numpy.ndarray or pandas.DataFrame, optional
|
data : numpy.ndarray or pandas.DataFrame, optional
|
||||||
Data. Existing column labels of a pandas.DataFrame will be replaced.
|
Data. Existing column labels of a pandas.DataFrame will be replaced.
|
||||||
comments : str or iterable of str, optional
|
comments : (iterable of) str, optional
|
||||||
Additional, human-readable information.
|
Additional, human-readable information.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -464,9 +464,9 @@ class Table:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
label_old : str or iterable of str
|
label_old : (iterable of) str
|
||||||
Old column label(s).
|
Old column label(s).
|
||||||
label_new : str or iterable of str
|
label_new : (iterable of) str
|
||||||
New column label(s).
|
New column label(s).
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
|
|
@ -110,7 +110,7 @@ class VTK:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
comments : str or sequence of str
|
comments : (sequence of) str
|
||||||
Comments.
|
Comments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -118,7 +118,7 @@ def from_grid(grid,
|
||||||
----------
|
----------
|
||||||
grid : damask.Grid
|
grid : damask.Grid
|
||||||
Grid from which the material IDs are used as seeds.
|
Grid from which the material IDs are used as seeds.
|
||||||
selection : int or collection of int, optional
|
selection : (collection of) int, optional
|
||||||
Material IDs to consider.
|
Material IDs to consider.
|
||||||
invert_selection : bool, optional
|
invert_selection : bool, optional
|
||||||
Consider all material IDs except those in selection. Defaults to False.
|
Consider all material IDs except those in selection. Defaults to False.
|
||||||
|
|
|
@ -46,7 +46,7 @@ def srepr(msg,
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
msg : object with __repr__ or sequence of objects with __repr__
|
msg : (sequence of) object with __repr__
|
||||||
Items to join.
|
Items to join.
|
||||||
glue : str, optional
|
glue : str, optional
|
||||||
Glue used for joining operation. Defaults to '\n'.
|
Glue used for joining operation. Defaults to '\n'.
|
||||||
|
@ -71,7 +71,7 @@ def emph(msg) -> str:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
msg : object with __repr__ or sequence of objects with __repr__
|
msg : (sequence of) object with __repr__
|
||||||
Message to format.
|
Message to format.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -88,7 +88,7 @@ def deemph(msg) -> str:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
msg : object with __repr__ or sequence of objects with __repr__
|
msg : (sequence of) object with __repr__
|
||||||
Message to format.
|
Message to format.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -105,7 +105,7 @@ def warn(msg) -> str:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
msg : object with __repr__ or sequence of objects with __repr__
|
msg : (sequence of) object with __repr__
|
||||||
Message to format.
|
Message to format.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -122,7 +122,7 @@ def strikeout(msg) -> str:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
msg : object with __repr__ or iterable of objects with __repr__
|
msg : (iterable of) object with __repr__
|
||||||
Message to format.
|
Message to format.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -738,7 +738,7 @@ def tail_repack(extended: _Union[str, _Sequence[str]],
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
extended : str or list of str
|
extended : (list of) str
|
||||||
Extended string list with potentially autosplitted tailing string relative to `existing`.
|
Extended string list with potentially autosplitted tailing string relative to `existing`.
|
||||||
existing : list of str
|
existing : list of str
|
||||||
Base string list.
|
Base string list.
|
||||||
|
@ -767,7 +767,7 @@ def aslist(arg: _Union[_IntCollection, int, None]) -> _List:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
arg : int or collection of int or None
|
arg : (collection of) int or None
|
||||||
Entity to transform into list.
|
Entity to transform into list.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
|
|
@ -708,6 +708,7 @@ class TestRotation:
|
||||||
@pytest.mark.parametrize('degrees',[True,False])
|
@pytest.mark.parametrize('degrees',[True,False])
|
||||||
def test_axis_angle(self,set_of_rotations,degrees,normalize,P):
|
def test_axis_angle(self,set_of_rotations,degrees,normalize,P):
|
||||||
c = np.array([P*-1,P*-1,P*-1,1.])
|
c = np.array([P*-1,P*-1,P*-1,1.])
|
||||||
|
c[:3] *= 0.9 if normalize else 1.0
|
||||||
for rot in set_of_rotations:
|
for rot in set_of_rotations:
|
||||||
m = rot.as_Euler_angles()
|
m = rot.as_Euler_angles()
|
||||||
o = Rotation.from_axis_angle(rot.as_axis_angle(degrees)*c,degrees,normalize,P).as_Euler_angles()
|
o = Rotation.from_axis_angle(rot.as_axis_angle(degrees)*c,degrees,normalize,P).as_Euler_angles()
|
||||||
|
@ -730,16 +731,30 @@ class TestRotation:
|
||||||
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) \
|
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) \
|
||||||
and o[3]<=np.pi+1.e-9, f'{m},{o},{rot.as_quaternion()}'
|
and o[3]<=np.pi+1.e-9, f'{m},{o},{rot.as_quaternion()}'
|
||||||
|
|
||||||
|
def test_parallel(self,set_of_rotations):
|
||||||
|
a = np.array([[1.0,0.0,0.0],
|
||||||
|
[0.0,1.0,0.0]])
|
||||||
|
for rot in set_of_rotations:
|
||||||
|
assert rot.allclose(Rotation.from_parallel(a,rot.broadcast_to((2,))@a))
|
||||||
|
|
||||||
@pytest.mark.parametrize('P',[1,-1])
|
@pytest.mark.parametrize('P',[1,-1])
|
||||||
@pytest.mark.parametrize('normalize',[True,False])
|
@pytest.mark.parametrize('normalize',[True,False])
|
||||||
def test_Rodrigues(self,set_of_rotations,normalize,P):
|
def test_Rodrigues(self,set_of_rotations,normalize,P):
|
||||||
c = np.array([P*-1,P*-1,P*-1,1.])
|
c = np.array([P*-1,P*-1,P*-1,1.])
|
||||||
|
c[:3] *= 0.9 if normalize else 1.0
|
||||||
for rot in set_of_rotations:
|
for rot in set_of_rotations:
|
||||||
m = rot.as_matrix()
|
m = rot.as_matrix()
|
||||||
o = Rotation.from_Rodrigues_vector(rot.as_Rodrigues_vector()*c,normalize,P).as_matrix()
|
o = Rotation.from_Rodrigues_vector(rot.as_Rodrigues_vector()*c,normalize,P).as_matrix()
|
||||||
ok = np.allclose(m,o,atol=atol)
|
ok = np.allclose(m,o,atol=atol)
|
||||||
assert ok and np.isclose(np.linalg.det(o),1.0), f'{m},{o}'
|
assert ok and np.isclose(np.linalg.det(o),1.0), f'{m},{o}'
|
||||||
|
|
||||||
|
def test_Rodrigues_compact(self,set_of_rotations):
|
||||||
|
for rot in set_of_rotations:
|
||||||
|
c = rot.as_Rodrigues_vector(compact=True)
|
||||||
|
r = rot.as_Rodrigues_vector(compact=False)
|
||||||
|
assert np.allclose(r[:3]*r[3], c, equal_nan=True)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('P',[1,-1])
|
@pytest.mark.parametrize('P',[1,-1])
|
||||||
def test_homochoric(self,set_of_rotations,P):
|
def test_homochoric(self,set_of_rotations,P):
|
||||||
cutoff = np.tan(np.pi*.5*(1.-1e-4))
|
cutoff = np.tan(np.pi*.5*(1.-1e-4))
|
||||||
|
@ -760,8 +775,9 @@ class TestRotation:
|
||||||
|
|
||||||
@pytest.mark.parametrize('P',[1,-1])
|
@pytest.mark.parametrize('P',[1,-1])
|
||||||
@pytest.mark.parametrize('accept_homomorph',[True,False])
|
@pytest.mark.parametrize('accept_homomorph',[True,False])
|
||||||
|
# @pytest.mark.parametrize('normalize',[True,False])
|
||||||
def test_quaternion(self,set_of_rotations,P,accept_homomorph):
|
def test_quaternion(self,set_of_rotations,P,accept_homomorph):
|
||||||
c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1)
|
c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1) #* (0.9 if normalize else 1.0)
|
||||||
for rot in set_of_rotations:
|
for rot in set_of_rotations:
|
||||||
m = rot.as_cubochoric()
|
m = rot.as_cubochoric()
|
||||||
o = Rotation.from_quaternion(rot.as_quaternion()*c,accept_homomorph,P).as_cubochoric()
|
o = Rotation.from_quaternion(rot.as_quaternion()*c,accept_homomorph,P).as_cubochoric()
|
||||||
|
@ -889,6 +905,15 @@ class TestRotation:
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
fr(eval(f'R.{to}()'),P=-30)
|
fr(eval(f'R.{to}()'),P=-30)
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_multiplication(self):
|
||||||
|
rot = Rotation.from_random()
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
rot@Rotation.from_random()
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
rot@[1,2,3,4]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('shape',[None,(3,),(4,2)])
|
@pytest.mark.parametrize('shape',[None,(3,),(4,2)])
|
||||||
def test_broadcast(self,shape):
|
def test_broadcast(self,shape):
|
||||||
rot = Rotation.from_random(shape)
|
rot = Rotation.from_random(shape)
|
||||||
|
|
Loading…
Reference in New Issue