# Source code for halotools.mock_observables.tensor_calculations.tensor_derived_quantities

"""
"""
from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np

__all__ = (
'principal_axes_from_inertia_tensors', 'sphericity_from_inertia_tensors',
'triaxility_from_inertia_tensors')

[docs]
def principal_axes_from_inertia_tensors(inertia_tensors):
r""" Calculate the principal eigenvector of each of the input inertia tensors.

Parameters
----------
inertia_tensors : ndarray
Numpy array of shape (npts, 3, 3) storing a collection of 3x3 symmetric
positive-definite matrices

Returns
-------
principal_axes : ndarray
Numpy array of shape (npts, 3) storing a collection of 3d principal eigenvectors

eigenvalues : ndarray
Numpy array of shape (npts, ) storing the eigenvalue of each principal eigenvector

Notes
-----
The function ~halotools.mock_observables.inertia_tensor_per_object
calculates the inertia tensors :math:\mathcal{I}_{\rm i} for a collection of
points inside a 3d mass distribution.

"""
evals, evecs = np.linalg.eigh(inertia_tensors)
return evecs[:, :, 2], evals[:, 2]

[docs]
def sphericity_from_inertia_tensors(inertia_tensors):
r""" Calculate the sphericity :math:\mathcal{S}_{\rm i}
of each of the :math:i=1,\dots,N_{\rm points}
mass distributions defined by the input inertia tensors :math:\mathcal{I}_{\rm i}.

Sphericity :math:0 < \mathcal{S} <= 1 is defined in terms of
the eigenvalues of the inertia tensor :math:\mathcal{I},
denoted by :math:\lambda_{a}, \lambda_{b}, \lambda_{c},
from largest to smallest:

.. math::
\mathcal{S}\equiv\lambda_{c}/\lambda_{a}

Parameters
----------
inertia_tensors : ndarray
Numpy array of shape (npts, 3, 3) storing a collection of 3x3 symmetric
positive-definite matrices

Returns
-------
sphericity : ndarray
Numpy array of shape (npts, ) storing the sphericity of each inertia tensor

Notes
-----
The function ~halotools.mock_observables.inertia_tensor_per_object
calculates the inertia tensors :math:\mathcal{I}_{\rm i} for a collection of
points inside a 3d mass distribution.
"""
evals, evecs = np.linalg.eigh(inertia_tensors)
third_evals = evals[:, 0]
first_evals = evals[:, 2]
sphericity = third_evals/first_evals
return sphericity

[docs]
def triaxility_from_inertia_tensors(inertia_tensors):
r""" Calculate the triaxility :math:\mathcal{T}_{\rm i}
of each of the :math:i=1,\dots,N_{\rm points}
mass distributions defined by the input inertia tensors :math:\mathcal{I}_{\rm i}.

Triaxility :math:\mathcal{T} is defined in terms of
the eigenvalues of the inertia tensor :math:\mathcal{I},
denoted by :math:\lambda_{a}, \lambda_{b}, \lambda_{c},
from largest to smallest:

.. math::
\mathcal{T}\equiv\frac{\lambda_{a}^{2}-\lambda_{b}^{2}}{\lambda_{a}^{2}-\lambda_{c}^{2}}

Parameters
----------
inertia_tensors : ndarray
Numpy array of shape (npts, 3, 3) storing a collection of 3x3 symmetric
positive-definite matrices

Returns
-------
triaxility : ndarray
Numpy array of shape (npts, ) storing the triaxility of each inertia tensor

Notes
-----
The function ~halotools.mock_observables.inertia_tensor_per_object
calculates the inertia tensors :math:\mathcal{I}_{\rm i} for a collection of
points inside a 3d mass distribution.
"""
evals, evecs = np.linalg.eigh(inertia_tensors)
third_evals = evals[:, 0]
second_evals = evals[:, 1]
first_evals = evals[:, 2]
triaxility = (first_evals**2 - second_evals**2)/(first_evals**2 - third_evals**2)
return triaxility