hexrd.phase_transition.texture package

Submodules

Module contents

class hexrd.phase_transition.texture.DeLaValleePoussinKernel(halfwidth: float, crystal_symmetry: str | ndarray | None = None, sample_symmetry: str | ndarray | None = None)[source]

Bases: SO3Kernel

De la Vallée Poussin kernel on SO(3).

A radially symmetric kernel on SO(3) defined by:

K(ω) = C · cos(ω/2)^(2κ)

where ω is the misorientation angle, κ is the shape parameter, and C = B(3/2, 1/2) / B(3/2, κ + 1/2) is the normalization constant (B denotes the Beta function).

The halfwidth h is the angle at which the kernel drops to half its peak value. It is related to κ analytically by:

κ = ln(0.5) / (2 · ln(cos(h/2)))

Parameters

halfwidthfloat

Half-width parameter in radians — the angle at which K drops to half its maximum. Must be > 0, typically in [π/180, π/2].

crystal_symmetrystr or numpy.ndarray, optional

Crystal symmetry used to compute symmetry-reduced misorientation angles. Strings are interpreted as Laue group labels.

sample_symmetrystr or numpy.ndarray, optional

Sample symmetry used to compute symmetry-reduced misorientation angles. Strings are interpreted as Laue group labels, with triclinic, monoclinic, and orthorhombic sample labels mapped to their corresponding finite Laue groups.

Attributes

halfwidthfloat

Half-width parameter in radians

kappafloat

Shape parameter κ derived from half-width

norm_constantfloat

Normalization constant from the Beta function

Notes

Symmetry is opt-in and must be supplied explicitly. By default the kernel applies NO crystal or sample symmetry: symmetry-equivalent orientations are treated as distinct and the misorientation angle is the raw geometric one. To have the kernel respect symmetry - i.e. treat orientations related by a symmetry operation as identical and use the smallest equivalent misorientation - you must pass crystal_symmetry (and/or sample_symmetry). For example, a cubic material must be built with crystal_symmetry='oh'; omitting it silently ignores cubic symmetry and will overestimate misorientation angles.

Examples

>>> kernel = DeLaValleePoussinKernel(halfwidth=np.radians(15))
>>> R1 = np.eye(3)
>>> R2 = np.eye(3)  # Same orientation
>>> value = kernel.eval(R1, R2)  # Maximum value = C
>>>
>>> # Respect cubic crystal symmetry (otherwise it is ignored):
>>> kernel = DeLaValleePoussinKernel(
...     halfwidth=np.radians(15), crystal_symmetry='oh'
... )
property crystal_symmetry: str | None

str or None: Crystal symmetry label, if built from a label.

Returns None when the symmetry was supplied directly as a quaternion array, even if symmetry reduction is active. Use has_symmetry to test whether reduction is enabled.

eval(R1: ndarray, R2: ndarray) float | ndarray[source]

Evaluate de la Vallée Poussin kernel between rotations.

K(ω) = C · cos(ω/2)^(2κ)

Parameters

R1, R2array_like

Rotation matrices of shape (…, 3, 3)

Returns

float or numpy.ndarray

Kernel values, shape matches broadcasting of R1 and R2

Examples

>>> kernel = DeLaValleePoussinKernel(
...     halfwidth=np.radians(10)
... )
>>> value = kernel.eval(np.eye(3), np.eye(3))
property halfwidth: float

float: Half-width in radians (angle where K = K_max / 2).

property has_symmetry: bool

bool: Whether non-trivial symmetry reduction is enabled.

property kappa: float

float: Shape parameter κ.

misorientation_angle(R1: ndarray, R2: ndarray) float | ndarray[source]

Calculate misorientation angle between rotation matrices.

Without symmetry, uses the formula: cos(ω) = (trace(R1^T @ R2) - 1) / 2, and supports arbitrary broadcasting of R1 and R2. With crystal or sample symmetry, delegates to hexrd.core.rotations.misorientation for symmetry-reduced angles; in that case one of R1/R2 must be a single orientation (shape (3, 3)), which is reduced against the other as a batch.

Parameters

R1, R2array_like

Rotation matrices of shape (…, 3, 3)

Returns

float or numpy.ndarray

Misorientation angles in radians, shape matches input broadcasting

property norm_constant: float

float: Normalization constant from Beta function.

property sample_symmetry: str | None

str or None: Sample symmetry label, if built from a label.

Returns None when the symmetry was supplied directly as a quaternion array, even if symmetry reduction is active. Use has_symmetry to test whether reduction is enabled.

class hexrd.phase_transition.texture.SO3Kernel[source]

Bases: ABC

Abstract base class for kernels on the SO(3) rotation group.

All SO(3) kernels should inherit from this class and implement the eval() method for kernel evaluation.

abstract eval(R1: ndarray, R2: ndarray) float | ndarray[source]

Evaluate kernel between two rotations.

Parameters

R1, R2array_like

Rotation matrices of shape (…, 3, 3)

Returns

float or numpy.ndarray

Kernel values

class hexrd.phase_transition.texture.UniformODF(crystal_symmetry: str | ndarray | None = None, sample_symmetry: str | ndarray | None = None)[source]

Bases: object

Uniform (random) orientation distribution function.

Represents a completely isotropic texture where all crystal orientations are equally likely. The value is constant at 1 MRD (multiples of a random distribution), the standard normalization where the uniform distribution serves as the reference density.

Parameters

crystal_symmetrystr or numpy.ndarray, optional

Crystal symmetry as a Laue group label (‘ci’, ‘c2h’, ‘d2h’, ‘c4h’, ‘d4h’, ‘s6’, ‘d3d’, ‘c6h’, ‘d6h’, ‘th’, ‘oh’) or a quaternion symmetry array. Validated but inert (the value is 1 MRD regardless); default None.

sample_symmetrystr or numpy.ndarray, optional

Sample symmetry as a label (‘triclinic’, ‘monoclinic’, ‘orthorhombic’) or a quaternion array. Validated but inert; default None.

Attributes

valuefloat

Constant ODF value = 1.0 (MRD)

crystal_symmetrystr or None

Crystal symmetry label, or None if unset or given as an array

sample_symmetrystr or None

Sample symmetry label, or None if unset or given as an array

Examples

>>> odf = UniformODF('d6h', 'triclinic')  # hexagonal crystal
>>> orientations = np.eye(3).reshape(1, 3, 3)
>>> values = odf.eval(orientations)
>>> print(values[0])  # 1.0
property crystal_symmetry: str | None

Crystal symmetry label, or None if unset or given as an array.

eval(orientations: ndarray) float | ndarray[source]

Evaluate uniform ODF at given orientations.

For a uniform ODF, all orientations return 1.0 MRD (multiples of a random distribution).

Parameters

orientationsarray_like

Orientation matrices. Can be: - Single 3x3 rotation matrix - Array of shape (N, 3, 3) for N orientations - Any shape ending in (3, 3) for rotation matrices

Returns

float or numpy.ndarray

ODF values, all equal to 1.0 (MRD). A scalar float for a single (3, 3) orientation; otherwise an array whose shape matches the leading dimensions of the input.

Examples

>>> odf = UniformODF('oh', 'triclinic')
>>>
>>> # Single orientation
>>> R = np.eye(3)
>>> value = odf.eval(R)  # scalar
>>>
>>> # Multiple orientations
>>> Rs = np.array([np.eye(3), np.eye(3)])  # shape (2, 3, 3)
>>> values = odf.eval(Rs)  # shape (2,)
property sample_symmetry: str | None

Sample symmetry label, or None if unset or given as an array.

property value: float

Constant ODF value in MRD.

class hexrd.phase_transition.texture.UnimodalODF(modal_orientations, kernel, weights=None)[source]

Bases: object

Unimodal orientation distribution function.

Represents a texture with one or more preferred orientations around which crystal orientations are concentrated. Uses kernel functions to create smooth distributions around modal orientations.

Mathematical form: f(g) = Σᵢ wᵢ K(g, g₀ᵢ), Σᵢ wᵢ = 1 Because the de la Vallée Poussin kernel is normalized so its mean over SO(3) is 1 (MRD), this weighted sum is itself a valid ODF in MRD units (uniform texture = 1).

Parameters

modal_orientationsarray_like

Modal (preferred) orientation(s). Can be: - Single 3x3 rotation matrix - Array of shape (N, 3, 3) for N modal orientations

kernelDeLaValleePoussinKernel

Kernel function defining the shape of the distribution. The kernel is the single source of truth for symmetry: any crystal/sample symmetry must be set on the kernel, and the ODF exposes it via the crystal_symmetry/sample_symmetry properties.

weightsarray_like, optional

Weights for multiple modal orientations. Must sum to 1. If None, equal weights are used for multiple orientations.

Attributes

modal_orientationsnumpy.ndarray

Array of modal orientations, shape (N, 3, 3)

kernelDeLaValleePoussinKernel

Kernel function used for the distribution

weightsnumpy.ndarray

Component weights, shape (N,)

crystal_symmetrystr or None

Crystal symmetry label, delegated from the kernel

sample_symmetrystr or None

Sample symmetry label, delegated from the kernel

n_componentsint

Number of modal orientations

Examples

>>> from hexrd.phase_transition.texture import UnimodalODF
>>> from hexrd.phase_transition.texture import DeLaValleePoussinKernel
>>>
>>> # Single modal orientation (cubic crystal symmetry on the kernel)
>>> kernel = DeLaValleePoussinKernel(
...     halfwidth=np.radians(15), crystal_symmetry='oh'
... )
>>> modal = np.eye(3)  # Identity orientation
>>> odf = UnimodalODF(modal, kernel)
>>>
>>> # Evaluate at modal orientation (should give maximum value)
>>> value = odf.eval(modal)
property crystal_symmetry

str or None: Crystal symmetry label, delegated from the kernel.

estimated_max_value()[source]

Estimate the maximum ODF value, in MRD.

The ODF maxima occur at (or very near) the modal orientations, so this evaluates the full ODF at each mode and returns the largest value.

Returns

float

Maximum ODF value in MRD (multiples of a random distribution)

eval(orientations)[source]

Evaluate unimodal ODF at given orientations.

Computes f(g) = Σᵢ wᵢ K(g, g₀ᵢ) for all input orientations, in MRD.

Parameters

orientationsarray_like

Orientation matrices of shape (…, 3, 3)

Returns

numpy.ndarray

ODF values with shape matching leading dimensions of input

Examples

>>> modal = np.eye(3)
>>> kernel = DeLaValleePoussinKernel(halfwidth=np.radians(10))
>>> odf = UnimodalODF(modal, kernel)
>>>
>>> # Single evaluation
>>> value = odf.eval(modal)  # Should give maximum
>>>
>>> # Batch evaluation
>>> Rs = np.array([np.eye(3), rotation_matrix_z(np.pi/4)])
>>> values = odf.eval(Rs)  # shape (2,)
property kernel

DeLaValleePoussinKernel: Kernel function.

property modal_orientations

numpy.ndarray: Modal orientations, shape (N, 3, 3).

property n_components

int: Number of modal orientations.

property sample_symmetry

str or None: Sample symmetry label, delegated from the kernel.

property weights

numpy.ndarray: Component weights, shape (N,).

hexrd.phase_transition.texture.eval_odf_batch(odf, orientations, chunk_size=10000)[source]

Evaluate ODF on large batches of orientations with memory management.

For very large orientation datasets, this function processes orientations in chunks to avoid memory issues while maintaining vectorization benefits.

Parameters

odfODF object

ODF object with eval() method

orientationsarray_like

Large array of orientation matrices, shape (N, 3, 3). A single (3, 3) matrix is also accepted.

chunk_sizeint, optional

Number of orientations to process per chunk, default 10000

Returns

numpy.ndarray or float

ODF values, shape (N,) for an (N, 3, 3) input, or a scalar float for a single (3, 3) orientation.

Examples

>>> odf = UniformODF('oh', 'triclinic')
>>> # Large batch of orientations
>>> Rs = np.random.normal(size=(50000, 3, 3))  # Not actual rotations!
>>> # In practice, use proper rotation matrices
>>> values = eval_odf_batch(odf, Rs, chunk_size=5000)
hexrd.phase_transition.texture.eval_random_orientations(odf, n_orientations=1000, seed=None)[source]

Evaluate ODF at random orientations for statistical analysis.

Generates random rotation matrices and evaluates the ODF at these orientations. Useful for normalization checks and Monte Carlo integration.

Parameters

odfODF object

ODF to evaluate

n_orientationsint, optional

Number of random orientations to generate, default 1000

seedint, optional

Random seed for reproducibility

Returns

tuple of (numpy.ndarray, numpy.ndarray)

orientations : Random rotation matrices, shape (n_orientations, 3, 3) values : ODF values at these orientations, shape (n_orientations,)

Examples

>>> odf = UniformODF('oh', 'triclinic')
>>> orientations, values = eval_random_orientations(odf, n_orientations=100)
>>> print(f"Mean ODF value: {np.mean(values)}")  # Should be ~1.0 (MRD)