Source code for skypy.utils.random
"""Random utility module.
This module provides methods to draw from random distributions.
Utility Functions
=================
.. autosummary::
:nosignatures:
:toctree: ../api/
schechter
triaxial_axis_ratio
"""
import numpy as np
[docs]def schechter(alpha, x_min, x_max, resolution=100, size=None, scale=1.):
"""Sample from the Schechter function.
Parameters
----------
alpha : float or int
The alpha parameter in the Schechter function in [1]_.
x_min, x_max : array_like
Lower and upper bounds for the random variable x.
resolution : int
Resolution of the inverse transform sampling spline. Default is 100.
size: int, optional
Output shape of samples. If size is None and scale is a scalar, a
single sample is returned. If size is None and scale is an array, an
array of samples is returned with the same shape as scale.
scale: array-like, optional
Scale factor for the returned samples. Default is 1.
Returns
-------
x_sample : array_like
Samples drawn from the Schechter function.
Warnings
--------
The inverse cumulative distribution function is approximated from the
Schechter function evaluated on a logarithmically-spaced grid. The user
must choose the `resolution` of this grid to satisfy their desired
numerical accuracy.
References
----------
.. [1] https://en.wikipedia.org/wiki/Luminosity_function_(astronomy)
"""
if size is None:
size = np.broadcast(x_min, x_max, scale).shape or None
lnx_min = np.log(x_min)
lnx_max = np.log(x_max)
lnx = np.linspace(np.min(lnx_min), np.max(lnx_max), resolution)
pdf = np.exp(np.add(alpha, 1)*lnx - np.exp(lnx))
cdf = pdf # in place
np.cumsum((pdf[1:]+pdf[:-1])/2*np.diff(lnx), out=cdf[1:])
cdf[0] = 0
cdf /= cdf[-1]
t_lower = np.interp(lnx_min, lnx, cdf)
t_upper = np.interp(lnx_max, lnx, cdf)
u = np.random.uniform(t_lower, t_upper, size=size)
lnx_sample = np.interp(u, cdf, lnx)
return np.exp(lnx_sample) * scale
[docs]def triaxial_axis_ratio(zeta, xi, size=None):
r'''axis ratio of a randomly projected triaxial ellipsoid
Given the two axis ratios `1 >= zeta >= xi` of a randomly oriented triaxial
ellipsoid, computes the axis ratio `q` of the projection.
Parameters
----------
zeta : array_like
Axis ratio of intermediate and major axis.
xi : array_like
Axis ratio of minor and major axis.
size : tuple of int or None
Size of the random draw. If `None` is given, size is inferred from
other inputs.
Returns
-------
q : array_like
Axis ratio of the randomly projected ellipsoid.
Notes
-----
See equations (11) and (12) in [1]_ for details.
References
----------
.. [1] Binney J., 1985, MNRAS, 212, 767. doi:10.1093/mnras/212.4.767
'''
# get size from inputs if not explicitly provided
if size is None:
size = np.broadcast(zeta, xi).shape
# draw random viewing angle (theta, phi)
cos2_theta = np.random.uniform(low=-1., high=1., size=size)
cos2_theta *= cos2_theta
sin2_theta = 1 - cos2_theta
cos2_phi = np.cos(np.random.uniform(low=0., high=2*np.pi, size=size))
cos2_phi *= cos2_phi
sin2_phi = 1 - cos2_phi
# transform arrays to quantities that are used in eq. (11)
z2m1 = np.square(zeta)
z2m1 -= 1
x2 = np.square(xi)
# eq. (11) multiplied by xi^2 zeta^2
A = (1 + z2m1*sin2_phi)*cos2_theta + x2*sin2_theta
B2 = 4*z2m1**2*cos2_theta*sin2_phi*cos2_phi
C = 1 + z2m1*cos2_phi
# eq. (12)
q = np.sqrt((A+C-np.sqrt((A-C)**2+B2))/(A+C+np.sqrt((A-C)**2+B2)))
return q