Source code for hmf.mass_function.integrate_hmf

"""A supporting module with a routine to integrate the differential hmf in a robust manner."""

import numpy as np
import scipy.integrate as intg
from scipy.interpolate import InterpolatedUnivariateSpline as Spline


class NaNError(Exception):
    """Integrator hit a NaN."""


[docs] def hmf_integral_gtm(m, dndm, mass_density=False): """ Cumulatively integrate dn/dm. Parameters ---------- M : array_like Array of masses. dndm : array_like Array of dn/dm (corresponding to M) mass_density : bool, `False` Whether to calculate mass density (or number density). Returns ------- ngtm : array_like Cumulative integral of dndm. Examples -------- Using a simple power-law mass function: >>> import numpy as np >>> m = np.logspace(10,18,500) >>> dndm = m**-2 >>> ngtm = hmf_integral_gtm(m,dndm) >>> np.allclose(ngtm,1/m) #1/m is the analytic integral to infinity. True The function always integrates to m=1e18, and extrapolates with a spline if data not provided: >>> m = np.logspace(10,12,500) >>> dndm = m**-2 >>> ngtm = hmf_integral_gtm(m,dndm) >>> np.allclose(ngtm,1/m) #1/m is the analytic integral to infinity. True """ n = len(m) # Eliminate NaN's mask = np.isfinite(dndm) m = m[mask] dndm = dndm[mask] dndlnm = m * dndm if len(m) < 4: raise NaNError( f"There are too few real numbers in dndm: len(dndm) = {n}, #NaN's = {n - len(m)}" ) # Calculate the mass function (and its integral) from the highest M up to 10**18 if m[-1] < m[0] * 10**18 / m[3]: m_upper = np.arange(np.log(m[-1]), np.log(10**18), np.log(m[1]) - np.log(m[0])) mf_func = Spline(np.log(m), np.log(dndlnm), k=1) mf = mf_func(m_upper) if not mass_density: int_upper = intg.simpson(np.exp(mf), dx=m_upper[2] - m_upper[1]) else: int_upper = intg.simpson(np.exp(m_upper + mf), dx=m_upper[2] - m_upper[1]) else: int_upper = 0 # Calculate the cumulative integral (backwards) of [m*]dndlnm if not mass_density: ngtm = np.concatenate( ( intg.cumulative_trapezoid(dndlnm[::-1], dx=np.log(m[1] / m[0]))[::-1], np.zeros(1), ) ) else: ngtm = np.concatenate( ( intg.cumulative_trapezoid(m[::-1] * dndlnm[::-1], dx=np.log(m[1]) - np.log(m[0]))[ ::-1 ], np.zeros(1), ) ) return ngtm + int_upper