diff --git a/python/damask/_crystal.py b/python/damask/_crystal.py index ad5b9ed31..a63cb0c81 100644 --- a/python/damask/_crystal.py +++ b/python/damask/_crystal.py @@ -131,9 +131,8 @@ class Crystal(): Crystal to check for equality. """ - if not isinstance(other, Crystal): - return NotImplemented - return self.lattice == other.lattice and \ + return NotImplemented if not isinstance(other, Crystal) else \ + self.lattice == other.lattice and \ self.parameters == other.parameters and \ self.family == other.family @@ -316,8 +315,8 @@ class Crystal(): self.lattice[-1],None),dtype=float) def to_lattice(self, *, - direction: np.ndarray = None, - plane: np.ndarray = None) -> np.ndarray: + direction: FloatSequence = None, + plane: FloatSequence = None) -> np.ndarray: """ Calculate lattice vector corresponding to crystal frame direction or plane normal. diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 06caf9b4c..5a9b7b141 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -189,7 +189,7 @@ class Orientation(Rotation,Crystal): Returns ------- - mask : numpy.ndarray bool + mask : numpy.ndarray of bool Mask indicating where corresponding orientations are close. """ @@ -372,10 +372,10 @@ class Orientation(Rotation,Crystal): Parameters ---------- - uvw : list, numpy.ndarray of shape (...,3) - lattice direction aligned with lab frame x-direction. - hkl : list, numpy.ndarray of shape (...,3) - lattice plane normal aligned with lab frame z-direction. + uvw : numpy.ndarray, shape (...,3) + Lattice direction aligned with lab frame x-direction. + hkl : numpy.ndarray, shape (...,3) + Lattice plane normal aligned with lab frame z-direction. """ o = cls(**kwargs) @@ -417,7 +417,7 @@ class Orientation(Rotation,Crystal): Returns ------- - in : numpy.ndarray of bool, quaternion.shape + in : numpy.ndarray of bool, shape (self.shape) Whether Rodrigues-Frank vector falls into fundamental zone. Notes @@ -461,7 +461,7 @@ class Orientation(Rotation,Crystal): Returns ------- - in : numpy.ndarray of bool, quaternion.shape + in : numpy.ndarray of bool, shape (self.shape) Whether Rodrigues-Frank vector falls into disorientation FZ. References @@ -515,7 +515,7 @@ class Orientation(Rotation,Crystal): ------- disorientation : Orientation Disorientation between self and other. - operators : numpy.ndarray int of shape (...,2), conditional + operators : numpy.ndarray of int, shape (...,2), conditional Index of symmetrically equivalent orientation that rotated vector to the SST. Notes @@ -583,14 +583,14 @@ class Orientation(Rotation,Crystal): def average(self, - weights = None, - return_cloud = False): + weights: FloatSequence = None, + return_cloud: bool = False): """ Return orientation average over last dimension. Parameters ---------- - weights : numpy.ndarray, optional + weights : numpy.ndarray, shape (self.shape), optional Relative weights of orientations. return_cloud : bool, optional Return the set of symmetrically equivalent orientations that was used in averaging. @@ -610,8 +610,8 @@ class Orientation(Rotation,Crystal): """ eq = self.equivalent - m = eq.misorientation(self[...,0].reshape((1,)+self.shape[:-1]+(1,)) - .broadcast_to(eq.shape)).as_axis_angle()[...,3] + m = eq.misorientation(self[...,0].reshape((1,)+self.shape[:-1]+(1,)) # type: ignore + .broadcast_to(eq.shape)).as_axis_angle()[...,3] # type: ignore r = Rotation(np.squeeze(np.take_along_axis(eq.quaternion, np.argmin(m,axis=0)[np.newaxis,...,np.newaxis], axis=0), @@ -625,7 +625,7 @@ class Orientation(Rotation,Crystal): def to_SST(self, - vector: np.ndarray, + vector: FloatSequence, proper: bool = False, return_operators: bool = False) -> np.ndarray: """ @@ -633,10 +633,10 @@ class Orientation(Rotation,Crystal): Parameters ---------- - vector : numpy.ndarray of shape (...,3) + vector : numpy.ndarray, shape (...,3) Lab frame vector to align with crystal frame direction. Shape of vector blends with shape of own rotation array. - For example, a rotation array of shape (3,2) and a (2,4) vector array result in (3,2,4) outputs. + For example, a rotation array of shape (3,2) and a vector array of shape (2,4) result in (3,2,4) outputs. proper : bool, optional Consider only vectors with z >= 0, hence combine two neighboring SSTs. Defaults to False. @@ -646,15 +646,18 @@ class Orientation(Rotation,Crystal): Returns ------- - vector_SST : numpy.ndarray of shape (...,3) + vector_SST : numpy.ndarray, shape (...,3) Rotated vector falling into SST. - operators : numpy.ndarray int of shape (...), conditional + operators : numpy.ndarray of int, shape (...), conditional Index of symmetrically equivalent orientation that rotated vector to SST. """ + vector_ = np.array(vector,float) + if vector_.shape[-1] != 3: + raise ValueError('input is not a field of three-dimensional vectors') eq = self.equivalent - blend = util.shapeblender(eq.shape,np.array(vector).shape[:-1]) - poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(np.array(vector),blend+(3,)) #type: ignore + blend = util.shapeblender(eq.shape,vector_.shape[:-1]) + poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(vector_,blend+(3,)) #type: ignore ok = self.in_SST(poles,proper=proper) ok &= np.cumsum(ok,axis=0) == 1 loc = np.where(ok) @@ -667,14 +670,14 @@ class Orientation(Rotation,Crystal): def in_SST(self, - vector: np.ndarray, + vector: FloatSequence, proper: bool = False) -> Union[np.bool_, np.ndarray]: """ Check whether given crystal frame vector falls into standard stereographic triangle of own symmetry. Parameters ---------- - vector : numpy.ndarray of shape (...,3) + vector : numpy.ndarray, shape (...,3) Vector to check. proper : bool, optional Consider only vectors with z >= 0, hence combine two neighboring SSTs. @@ -686,31 +689,32 @@ class Orientation(Rotation,Crystal): Whether vector falls into SST. """ - if not isinstance(vector,np.ndarray) or vector.shape[-1] != 3: + vector_ = np.array(vector,float) + if vector_.shape[-1] != 3: raise ValueError('input is not a field of three-dimensional vectors') if self.standard_triangle is None: # direct exit for no symmetry - return np.ones_like(vector[...,0],bool) + return np.ones_like(vector_[...,0],bool) if proper: components_proper = np.around(np.einsum('...ji,...i', - np.broadcast_to(self.standard_triangle['proper'], vector.shape+(3,)), - vector), 12) + np.broadcast_to(self.standard_triangle['proper'], vector_.shape+(3,)), + vector_), 12) components_improper = np.around(np.einsum('...ji,...i', - np.broadcast_to(self.standard_triangle['improper'], vector.shape+(3,)), - vector), 12) + np.broadcast_to(self.standard_triangle['improper'], vector_.shape+(3,)), + vector_), 12) return np.all(components_proper >= 0.0,axis=-1) \ | np.all(components_improper >= 0.0,axis=-1) else: components = np.around(np.einsum('...ji,...i', - np.broadcast_to(self.standard_triangle['improper'], vector.shape+(3,)), - np.block([vector[...,:2],np.abs(vector[...,2:3])])), 12) + np.broadcast_to(self.standard_triangle['improper'], vector_.shape+(3,)), + np.block([vector_[...,:2],np.abs(vector_[...,2:3])])), 12) return np.all(components >= 0.0,axis=-1) def IPF_color(self, - vector: np.ndarray, + vector: FloatSequence, in_SST: bool = True, proper: bool = False) -> np.ndarray: """ @@ -718,10 +722,10 @@ class Orientation(Rotation,Crystal): Parameters ---------- - vector : numpy.ndarray of shape (...,3) + vector : numpy.ndarray, shape (...,3) Vector to colorize. Shape of vector blends with shape of own rotation array. - For example, a rotation array of shape (3,2) and a (2,4) vector array result in (3,2,4) outputs. + For example, a rotation array of shape (3,2) and a vector array of shape (2,4) result in (3,2,4) outputs. in_SST : bool, optional Consider symmetrically equivalent orientations such that poles are located in SST. Defaults to True. @@ -731,7 +735,7 @@ class Orientation(Rotation,Crystal): Returns ------- - rgb : numpy.ndarray of shape (...,3) + rgb : numpy.ndarray, shape (...,3) RGB array of IPF colors. Examples @@ -755,7 +759,7 @@ class Orientation(Rotation,Crystal): if proper: components_proper = np.around(np.einsum('...ji,...i', - np.broadcast_to(self.standard_triangle['proper'], vector_.shape+(3,)), + np.broadcast_to(self.standard_triangle['proper'], vector_.shape+(3,)), vector_), 12) components_improper = np.around(np.einsum('...ji,...i', np.broadcast_to(self.standard_triangle['improper'], vector_.shape+(3,)), @@ -862,16 +866,16 @@ class Orientation(Rotation,Crystal): Parameters ---------- - uvw|hkl : numpy.ndarray of shape (...,3) + uvw|hkl : numpy.ndarray, shape (...,3) Miller indices of crystallographic direction or plane normal. Shape of vector blends with shape of own rotation array. - For example, a rotation array of shape (3,2) and a (2,4) vector array result in (3,2,4) outputs. + For example, a rotation array, shape (3,2) and a vector array of shape (2,4) result in (3,2,4) outputs. with_symmetry : bool, optional Calculate all N symmetrically equivalent vectors. Returns ------- - vector : numpy.ndarray of shape (...,3) or (...,N,3) + vector : numpy.ndarray, shape (...,3) or (...,N,3) Lab frame vector (or vectors if with_symmetry) along [uvw] direction or (hkl) plane normal. """ @@ -894,13 +898,13 @@ class Orientation(Rotation,Crystal): Parameters ---------- - N_slip|N_twin : iterable of int + N_slip|N_twin : '*' or iterable of int Number of deformation systems per family of the deformation system. Use '*' to select all. Returns ------- - P : numpy.ndarray of shape (N,...,3,3) + P : numpy.ndarray, shape (N,...,3,3) Schmid matrix for each of the N deformation systems. Examples diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 226d66f69..273cf8e92 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -108,12 +108,12 @@ class Rotation: def __getitem__(self, item: Union[Tuple[int], int, bool, np.bool_, np.ndarray]): """Return slice according to item.""" - return self.copy() \ - if self.shape == () else \ + return self.copy() if self.shape == () else \ self.copy(rotation=self.quaternion[item+(slice(None),)] if isinstance(item,tuple) else self.quaternion[item]) - def __eq__(self, other: object) -> bool: + def __eq__(self, + other: object) -> bool: """ Equal to other. @@ -123,9 +123,8 @@ class Rotation: Rotation to check for equality. """ - if not isinstance(other, Rotation): - return NotImplemented - return np.logical_or(np.all(self.quaternion == other.quaternion,axis=-1), + return NotImplemented if not isinstance(other, Rotation) else \ + np.logical_or(np.all(self.quaternion == other.quaternion,axis=-1), np.all(self.quaternion == -1.0*other.quaternion,axis=-1)) @@ -163,7 +162,7 @@ class Rotation: Returns ------- - mask : numpy.ndarray bool + mask : numpy.ndarray of bool Mask indicating where corresponding rotations are close. """ @@ -228,13 +227,13 @@ class Rotation: def __pow__(self: MyType, - exp: int) -> MyType: + exp: Union[float, int]) -> MyType: """ Perform the rotation 'exp' times. Parameters ---------- - exp : float + exp : scalar Exponent. """ @@ -243,13 +242,13 @@ class Rotation: return self.copy(rotation=Rotation(np.block([np.cos(exp*phi),np.sin(exp*phi)*p]))._standardize()) def __ipow__(self: MyType, - exp: int) -> MyType: + exp: Union[float, int]) -> MyType: """ Perform the rotation 'exp' times (in-place). Parameters ---------- - exp : float + exp : scalar Exponent. """ @@ -263,7 +262,7 @@ class Rotation: Parameters ---------- - other : Rotation of shape (self.shape) + other : Rotation, shape (self.shape) Rotation for composition. Returns @@ -290,7 +289,7 @@ class Rotation: Parameters ---------- - other : Rotation of shape (self.shape) + other : Rotation, shape (self.shape) Rotation for composition. """ @@ -304,7 +303,7 @@ class Rotation: Parameters ---------- - other : damask.Rotation of shape (self.shape) + other : damask.Rotation, shape (self.shape) Rotation to invert for composition. Returns @@ -325,7 +324,7 @@ class Rotation: Parameters ---------- - other : Rotation of shape (self.shape) + other : Rotation, shape (self.shape) Rotation to invert for composition. """ @@ -339,12 +338,12 @@ class Rotation: Parameters ---------- - other : numpy.ndarray of shape (...,3), (...,3,3), or (...,3,3,3,3) + other : numpy.ndarray, shape (...,3), (...,3,3), or (...,3,3,3,3) Vector or tensor on which to apply the rotation. Returns ------- - rotated : numpy.ndarray of shape (...,3), (...,3,3), or (...,3,3,3,3) + rotated : numpy.ndarray, shape (...,3), (...,3,3), or (...,3,3,3,3) Rotated vector or tensor, i.e. transformed to frame defined by rotation. """ @@ -401,6 +400,15 @@ class Rotation: """ Flatten array. + Parameters + ---------- + order : {'C', 'F', 'A'}, optional + 'C' flattens in row-major (C-style) order. + 'F' flattens in column-major (Fortran-style) order. + 'A' flattens in column-major order if object is Fortran contiguous in memory, + row-major order otherwise. + Defaults to 'C'. + Returns ------- flattened : damask.Rotation @@ -416,6 +424,18 @@ class Rotation: """ Reshape array. + Parameters + ---------- + shape : int or tuple of ints + The new shape should be compatible with the original shape. + If an integer is supplied, then the result will be a 1-D array of that length. + order : {'C', 'F', 'A'}, optional + 'C' flattens in row-major (C-style) order. + 'F' flattens in column-major (Fortran-style) order. + 'A' flattens in column-major order if object is Fortran contiguous in memory, + row-major order otherwise. + Defaults to 'C'. + Returns ------- reshaped : damask.Rotation @@ -434,7 +454,7 @@ class Rotation: Parameters ---------- - shape : int, tuple + shape : int or tuple of ints Shape of broadcasted array. mode : str, optional Where to preferentially locate missing dimensions. @@ -458,7 +478,7 @@ class Rotation: Parameters ---------- - weights : FloatSequence, optional + weights : numpy.ndarray, optional Relative weight of each rotation. Returns @@ -518,7 +538,7 @@ class Rotation: Returns ------- - q : numpy.ndarray of shape (...,4) + q : numpy.ndarray, shape (...,4) Unit quaternion (q_0, q_1, q_2, q_3) in positive real hemisphere, i.e. ǀqǀ = 1, q_0 ≥ 0. """ @@ -536,7 +556,7 @@ class Rotation: Returns ------- - phi : numpy.ndarray of shape (...,3) + phi : numpy.ndarray, shape (...,3) Bunge Euler angles (φ_1 ∈ [0,2π], ϕ ∈ [0,π], φ_2 ∈ [0,2π]) or (φ_1 ∈ [0,360], ϕ ∈ [0,180], φ_2 ∈ [0,360]) if degrees == True. @@ -555,8 +575,7 @@ class Rotation: """ eu = Rotation._qu2eu(self.quaternion) - if degrees: eu = np.degrees(eu) - return eu + return np.degrees(eu) if degrees else eu def as_axis_angle(self, degrees: bool = False, @@ -573,7 +592,7 @@ class Rotation: Returns ------- - axis_angle : numpy.ndarray of shape (...,4) or tuple ((...,3), (...)) if pair == True + axis_angle : numpy.ndarray, shape (...,4) or tuple ((...,3), (...)) if pair == True Axis and angle [n_1, n_2, n_3, ω] with ǀnǀ = 1 and ω ∈ [0,π] or ω ∈ [0,180] if degrees == True. @@ -597,7 +616,7 @@ class Rotation: Returns ------- - R : numpy.ndarray of shape (...,3,3) + R : numpy.ndarray, shape (...,3,3) Rotation matrix R with det(R) = 1, R.T ∙ R = I. Examples @@ -627,7 +646,7 @@ class Rotation: Returns ------- - rho : numpy.ndarray of shape (...,4) or (...,3) if compact == True + rho : numpy.ndarray, shape (...,4) or (...,3) if compact == True Rodrigues–Frank vector [n_1, n_2, n_3, tan(ω/2)] with ǀnǀ = 1 and ω ∈ [0,π] or [n_1, n_2, n_3] with ǀnǀ = tan(ω/2) and ω ∈ [0,π] if compact == True. @@ -654,7 +673,7 @@ class Rotation: Returns ------- - h : numpy.ndarray of shape (...,3) + h : numpy.ndarray, shape (...,3) Homochoric vector (h_1, h_2, h_3) with ǀhǀ < (3/4*π)^(1/3). Examples @@ -675,7 +694,7 @@ class Rotation: Returns ------- - x : numpy.ndarray of shape (...,3) + x : numpy.ndarray, shape (...,3) Cubochoric vector (x_1, x_2, x_3) with max(x_i) < 1/2*π^(2/3). Examples @@ -702,7 +721,7 @@ class Rotation: Parameters ---------- - q : numpy.ndarray of shape (...,4) + q : numpy.ndarray, shape (...,4) Unit quaternion (q_0, q_1, q_2, q_3) in positive real hemisphere, i.e. ǀqǀ = 1, q_0 ≥ 0. accept_homomorph : bool, optional Allow homomorphic variants, i.e. q_0 < 0 (negative real hemisphere). @@ -736,7 +755,7 @@ class Rotation: Parameters ---------- - phi : numpy.ndarray of shape (...,3) + phi : numpy.ndarray, shape (...,3) Euler angles (φ_1 ∈ [0,2π], ϕ ∈ [0,π], φ_2 ∈ [0,2π]) or (φ_1 ∈ [0,360], ϕ ∈ [0,180], φ_2 ∈ [0,360]) if degrees == True. degrees : bool, optional @@ -767,7 +786,7 @@ class Rotation: Parameters ---------- - axis_angle : numpy.ndarray of shape (...,4) + axis_angle : numpy.ndarray, shape (...,4) Axis and angle (n_1, n_2, n_3, ω) with ǀnǀ = 1 and ω ∈ [0,π] or ω ∈ [0,180] if degrees == True. degrees : bool, optional @@ -804,7 +823,7 @@ class Rotation: Parameters ---------- - basis : numpy.ndarray of shape (...,3,3) + basis : numpy.ndarray, shape (...,3,3) Three three-dimensional lattice basis vectors. orthonormal : bool, optional Basis is strictly orthonormal, i.e. is free of stretch components. Defaults to True. @@ -838,7 +857,7 @@ class Rotation: Parameters ---------- - R : numpy.ndarray of shape (...,3,3) + R : numpy.ndarray, shape (...,3,3) Rotation matrix with det(R) = 1, R.T ∙ R = I. """ @@ -852,9 +871,9 @@ class Rotation: Parameters ---------- - a : numpy.ndarray of shape (...,2,3) + a : numpy.ndarray, shape (...,2,3) Two three-dimensional lattice vectors of first orthogonal basis. - b : numpy.ndarray of shape (...,2,3) + b : numpy.ndarray, shape (...,2,3) Corresponding three-dimensional lattice vectors of second basis. """ @@ -882,7 +901,7 @@ class Rotation: Parameters ---------- - rho : numpy.ndarray of shape (...,4) + rho : numpy.ndarray, shape (...,4) Rodrigues–Frank vector (n_1, n_2, n_3, tan(ω/2)) with ǀnǀ = 1 and ω ∈ [0,π]. normalize : bool, optional Allow ǀnǀ ≠ 1. Defaults to False. @@ -913,7 +932,7 @@ class Rotation: Parameters ---------- - h : numpy.ndarray of shape (...,3) + h : numpy.ndarray, shape (...,3) Homochoric vector (h_1, h_2, h_3) with ǀhǀ < (3/4*π)^(1/3). P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. @@ -940,7 +959,7 @@ class Rotation: Parameters ---------- - x : numpy.ndarray of shape (...,3) + x : numpy.ndarray, shape (...,3) Cubochoric vector (x_1, x_2, x_3) with max(x_i) < 1/2*π^(2/3). P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. @@ -1002,9 +1021,9 @@ class Rotation: Parameters ---------- - weights : numpy.ndarray of shape (n) + weights : numpy.ndarray, shape (n) Texture intensity values (probability density or volume fraction) at Euler space grid points. - phi : numpy.ndarray of shape (n,3) + phi : numpy.ndarray, shape (n,3) Grid coordinates in Euler space at which weights are defined. N : integer, optional Number of discrete orientations to be sampled from the given ODF. @@ -1020,14 +1039,14 @@ class Rotation: Returns ------- - samples : damask.Rotation of shape (N) - Array of sampled rotations closely representing the input ODF. + samples : damask.Rotation, shape (N) + Array of sampled rotations that approximate the input ODF. Notes ----- Due to the distortion of Euler space in the vicinity of ϕ = 0, probability densities, p, defined on grid points with ϕ = 0 will never result in reconstructed orientations as their dV/V = p dγ = p × 0. - Hence, it is recommended to transform any such dataset to cell centers that avoid grid points at ϕ = 0. + Hence, it is recommended to transform any such dataset to a cell-centered version, which avoids grid points at ϕ = 0. References ---------- @@ -1095,9 +1114,9 @@ class Rotation: Parameters ---------- - alpha : numpy.ndarray of shape (2) + alpha : numpy.ndarray, shape (2) Polar coordinates (phi from x, theta from z) of fiber direction in crystal frame. - beta : numpy.ndarray of shape (2) + beta : numpy.ndarray, shape (2) Polar coordinates (phi from x, theta from z) of fiber direction in sample frame. sigma : float, optional Standard deviation of (Gaussian) misorientation distribution. diff --git a/python/damask/_table.py b/python/damask/_table.py index 1572c4f76..189f46d6b 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -185,7 +185,7 @@ class Table: Returns ------- - mask : numpy.ndarray bool + mask : numpy.ndarray of bool Mask indicating where corresponding table values are close. """